QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
Loading...
Searching...
No Matches
qgsalgorithmsplitvectorlayer.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsalgorithmsplitvectorlayer.cpp
3 ---------------------
4 begin : May 2020
5 copyright : (C) 2020 by Alexander Bruy
6 email : alexander dot bruy at gmail dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
19
20#include "qgsfileutils.h"
21#include "qgsvariantutils.h"
22#include "qgsvectorfilewriter.h"
23
24#include <QString>
25
26using namespace Qt::StringLiterals;
27
29
30QString QgsSplitVectorLayerAlgorithm::name() const
31{
32 return u"splitvectorlayer"_s;
33}
34
35QString QgsSplitVectorLayerAlgorithm::displayName() const
36{
37 return QObject::tr( "Split vector layer" );
38}
39
40QStringList QgsSplitVectorLayerAlgorithm::tags() const
41{
42 return QObject::tr( "vector,split,field,unique" ).split( ',' );
43}
44
45QString QgsSplitVectorLayerAlgorithm::group() const
46{
47 return QObject::tr( "Vector general" );
48}
49
50QString QgsSplitVectorLayerAlgorithm::groupId() const
51{
52 return u"vectorgeneral"_s;
53}
54
55QString QgsSplitVectorLayerAlgorithm::shortHelpString() const
56{
57 return QObject::tr( "This algorithm splits input vector layer into multiple layers by specified unique ID field." )
58 + u"\n\n"_s
59 + QObject::tr(
60 "Each of the layers created in the output folder contains all features from "
61 "the input layer with the same value for the specified attribute. The number "
62 "of files generated is equal to the number of different values found for the "
63 "specified attribute."
64 );
65}
66
67QString QgsSplitVectorLayerAlgorithm::shortDescription() const
68{
69 return QObject::tr(
70 "Splits a vector layer into multiple layers, each containing "
71 "all the features with the same value for a specified attribute."
72 );
73}
74
75QgsSplitVectorLayerAlgorithm *QgsSplitVectorLayerAlgorithm::createInstance() const
76{
77 return new QgsSplitVectorLayerAlgorithm();
78}
79
80void QgsSplitVectorLayerAlgorithm::initAlgorithm( const QVariantMap & )
81{
82 addParameter( new QgsProcessingParameterFeatureSource( u"INPUT"_s, QObject::tr( "Input layer" ), QList<int>() << static_cast<int>( Qgis::ProcessingSourceType::Vector ) ) );
83 addParameter( new QgsProcessingParameterField( u"FIELD"_s, QObject::tr( "Unique ID field" ), QVariant(), u"INPUT"_s ) );
84 auto prefixFieldParam = std::make_unique<QgsProcessingParameterBoolean>( u"PREFIX_FIELD"_s, QObject::tr( "Add field prefix to file names" ), true );
85 addParameter( prefixFieldParam.release() );
86
87 const QStringList options = QgsVectorFileWriter::supportedFormatExtensions();
88 auto fileTypeParam = std::make_unique<QgsProcessingParameterEnum>( u"FILE_TYPE"_s, QObject::tr( "Output file type" ), options, false, 0, true );
89 fileTypeParam->setFlags( fileTypeParam->flags() | Qgis::ProcessingParameterFlag::Advanced );
90 addParameter( fileTypeParam.release() );
91
92 addParameter( new QgsProcessingParameterFolderDestination( u"OUTPUT"_s, QObject::tr( "Output directory" ) ) );
93 addOutput( new QgsProcessingOutputMultipleLayers( u"OUTPUT_LAYERS"_s, QObject::tr( "Output layers" ) ) );
94}
95
96QVariantMap QgsSplitVectorLayerAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
97{
98 std::unique_ptr<QgsProcessingFeatureSource> source( parameterAsSource( parameters, u"INPUT"_s, context ) );
99 if ( !source )
100 throw QgsProcessingException( invalidSourceError( parameters, u"INPUT"_s ) );
101
102 const QString fieldName = parameterAsString( parameters, u"FIELD"_s, context );
103 const QString outputDir = parameterAsString( parameters, u"OUTPUT"_s, context );
104 QString outputFormat;
105 if ( parameters.value( u"FILE_TYPE"_s ).isValid() )
106 {
107 const int idx = parameterAsEnum( parameters, u"FILE_TYPE"_s, context );
108 outputFormat = QgsVectorFileWriter::supportedFormatExtensions().at( idx );
109 }
110 else
111 {
112 outputFormat = context.preferredVectorFormat();
113 if ( !QgsVectorFileWriter::supportedFormatExtensions().contains( outputFormat, Qt::CaseInsensitive ) )
114 outputFormat = u"gpkg"_s;
115 }
116
117 if ( !QDir().mkpath( outputDir ) )
118 throw QgsProcessingException( QObject::tr( "Failed to create output directory." ) );
119
120 const QgsFields fields = source->fields();
121 const QgsCoordinateReferenceSystem crs = source->sourceCrs();
122 const Qgis::WkbType geometryType = source->wkbType();
123 const int fieldIndex = fields.lookupField( fieldName );
124 const QSet<QVariant> uniqueValues = source->uniqueValues( fieldIndex );
125 QString baseName = outputDir + QDir::separator();
126
127 if ( parameterAsBool( parameters, u"PREFIX_FIELD"_s, context ) )
128 {
129 baseName.append( fieldName + "_" );
130 }
131
132 int current = 0;
133 const double step = uniqueValues.size() > 0 ? 100.0 / uniqueValues.size() : 1;
134
135 int count = 0;
136 QgsFeature feat;
137 QStringList outputLayers;
138 std::unique_ptr<QgsFeatureSink> sink;
139
140 for ( auto it = uniqueValues.constBegin(); it != uniqueValues.constEnd(); ++it )
141 {
142 if ( feedback->isCanceled() )
143 break;
144
145 QString fileName;
146 if ( QgsVariantUtils::isNull( *it ) )
147 {
148 fileName = u"%1NULL.%2"_s.arg( baseName ).arg( outputFormat );
149 }
150 else if ( ( *it ).toString().isEmpty() )
151 {
152 fileName = u"%1EMPTY.%2"_s.arg( baseName ).arg( outputFormat );
153 }
154 else
155 {
156 fileName = u"%1%2.%3"_s.arg( baseName ).arg( QgsFileUtils::stringToSafeFilename( ( *it ).toString() ) ).arg( outputFormat );
157 }
158 feedback->pushInfo( QObject::tr( "Creating layer: %1" ).arg( fileName ) );
159
160 sink.reset( QgsProcessingUtils::createFeatureSink( fileName, context, fields, geometryType, crs ) );
161 const QString expr = QgsExpression::createFieldEqualityExpression( fieldName, *it );
162 QgsFeatureIterator features = source->getFeatures( QgsFeatureRequest().setFilterExpression( expr ), Qgis::ProcessingFeatureSourceFlag::SkipGeometryValidityChecks );
163 count = 0;
164 while ( features.nextFeature( feat ) )
165 {
166 if ( feedback->isCanceled() )
167 break;
168
169 if ( !sink->addFeature( feat, QgsFeatureSink::FastInsert ) )
170 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, u"OUTPUT"_s ) );
171 count += 1;
172 }
173 sink->finalize();
174
175 feedback->pushInfo( QObject::tr( "Added %n feature(s) to layer", nullptr, count ) );
176 outputLayers << fileName;
177
178 current += 1;
179 feedback->setProgress( current * step );
180 }
181
182 QVariantMap outputs;
183 outputs.insert( u"OUTPUT"_s, outputDir );
184 outputs.insert( u"OUTPUT_LAYERS"_s, outputLayers );
185 return outputs;
186}
187
@ Vector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
Definition qgis.h:3653
@ SkipGeometryValidityChecks
Invalid geometry checks should always be skipped. This flag can be useful for algorithms which always...
Definition qgis.h:3828
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:294
@ Advanced
Parameter is an advanced parameter which should be hidden from users by default.
Definition qgis.h:3880
Represents a coordinate reference system (CRS).
static QString createFieldEqualityExpression(const QString &fieldName, const QVariant &value, QMetaType::Type fieldType=QMetaType::Type::UnknownType)
Create an expression allowing to evaluate if a field is equal to a value.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
Wraps a request for features to a vector layer (or directly its vector data provider).
@ FastInsert
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:60
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:56
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition qgsfeedback.h:65
Container of fields for a vector layer.
Definition qgsfields.h:46
Q_INVOKABLE int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
static QString stringToSafeFilename(const QString &string)
Converts a string to a safe filename, replacing characters which are not safe for filenames with an '...
Contains information about the context in which a processing algorithm is executed.
QString preferredVectorFormat() const
Returns the preferred vector format to use for vector outputs.
Custom exception class for processing related exceptions.
Base class for providing feedback from a processing algorithm.
virtual void pushInfo(const QString &info)
Pushes a general informational message from the algorithm.
A multi-layer output for processing algorithms which create map layers, when the number and nature of...
An input feature source (such as vector layers) parameter for processing algorithms.
A vector layer or feature source field parameter for processing algorithms.
A folder destination parameter, for specifying the destination path for a folder created by the algor...
static QgsFeatureSink * createFeatureSink(QString &destination, QgsProcessingContext &context, const QgsFields &fields, Qgis::WkbType geometryType, const QgsCoordinateReferenceSystem &crs, const QVariantMap &createOptions=QVariantMap(), const QStringList &datasourceOptions=QStringList(), const QStringList &layerOptions=QStringList(), QgsFeatureSink::SinkFlags sinkFlags=QgsFeatureSink::SinkFlags(), QgsRemappingSinkDefinition *remappingDefinition=nullptr)
Creates a feature sink ready for adding features.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
static QStringList supportedFormatExtensions(VectorFormatOptions options=SortRecommended)
Returns a list of file extensions for supported formats, e.g "shp", "gpkg".