QGIS API Documentation 3.32.0-Lima (311a8cb8a6)
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#include "qgsvectorfilewriter.h"
20#include "qgsvariantutils.h"
21
23
24QString QgsSplitVectorLayerAlgorithm::name() const
25{
26 return QStringLiteral( "splitvectorlayer" );
27}
28
29QString QgsSplitVectorLayerAlgorithm::displayName() const
30{
31 return QObject::tr( "Split vector layer" );
32}
33
34QStringList QgsSplitVectorLayerAlgorithm::tags() const
35{
36 return QObject::tr( "vector,split,field,unique" ).split( ',' );
37}
38
39QString QgsSplitVectorLayerAlgorithm::group() const
40{
41 return QObject::tr( "Vector general" );
42}
43
44QString QgsSplitVectorLayerAlgorithm::groupId() const
45{
46 return QStringLiteral( "vectorgeneral" );
47}
48
49QString QgsSplitVectorLayerAlgorithm::shortHelpString() const
50{
51 return QObject::tr( "Splits input vector layer into multiple layers by specified unique ID field." )
52 + QStringLiteral( "\n\n" )
53 + QObject::tr( "Each of the layers created in the output folder contains all features from "
54 "the input layer with the same value for the specified attribute. The number "
55 "of files generated is equal to the number of different values found for the "
56 "specified attribute." );
57}
58
59QgsSplitVectorLayerAlgorithm *QgsSplitVectorLayerAlgorithm::createInstance() const
60{
61 return new QgsSplitVectorLayerAlgorithm();
62}
63
64void QgsSplitVectorLayerAlgorithm::initAlgorithm( const QVariantMap & )
65{
66 addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ), QList<int>() << QgsProcessing::TypeVector ) );
67 addParameter( new QgsProcessingParameterField( QStringLiteral( "FIELD" ), QObject::tr( "Unique ID field" ),
68 QVariant(), QStringLiteral( "INPUT" ) ) );
69 std::unique_ptr< QgsProcessingParameterBoolean > prefixFieldParam = std::make_unique< QgsProcessingParameterBoolean >( QStringLiteral( "PREFIX_FIELD" ),
70 QObject::tr( "Add field prefix to file names" ), true );
71 addParameter( prefixFieldParam.release() );
72
73 const QStringList options = QgsVectorFileWriter::supportedFormatExtensions();
74 auto fileTypeParam = std::make_unique < QgsProcessingParameterEnum >( QStringLiteral( "FILE_TYPE" ), QObject::tr( "Output file type" ), options, false, 0, true );
75 fileTypeParam->setFlags( fileTypeParam->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
76 addParameter( fileTypeParam.release() );
77
78 addParameter( new QgsProcessingParameterFolderDestination( QStringLiteral( "OUTPUT" ), QObject::tr( "Output directory" ) ) );
79 addOutput( new QgsProcessingOutputMultipleLayers( QStringLiteral( "OUTPUT_LAYERS" ), QObject::tr( "Output layers" ) ) );
80}
81
82QVariantMap QgsSplitVectorLayerAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
83{
84 std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
85 if ( !source )
86 throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
87
88 const QString fieldName = parameterAsString( parameters, QStringLiteral( "FIELD" ), context );
89 const QString outputDir = parameterAsString( parameters, QStringLiteral( "OUTPUT" ), context );
90 QString outputFormat;
91 if ( parameters.value( QStringLiteral( "FILE_TYPE" ) ).isValid() )
92 {
93 const int idx = parameterAsEnum( parameters, QStringLiteral( "FILE_TYPE" ), context );
94 outputFormat = QgsVectorFileWriter::supportedFormatExtensions().at( idx );
95 }
96 else
97 {
98 outputFormat = context.preferredVectorFormat();
99 if ( !QgsVectorFileWriter::supportedFormatExtensions().contains( outputFormat, Qt::CaseInsensitive ) )
100 outputFormat = QStringLiteral( "gpkg" );
101 }
102
103 if ( !QDir().mkpath( outputDir ) )
104 throw QgsProcessingException( QStringLiteral( "Failed to create output directory." ) );
105
106 const QgsFields fields = source->fields();
107 const QgsCoordinateReferenceSystem crs = source->sourceCrs();
108 const Qgis::WkbType geometryType = source->wkbType();
109 const int fieldIndex = fields.lookupField( fieldName );
110 const QSet< QVariant > uniqueValues = source->uniqueValues( fieldIndex );
111 QString baseName = outputDir + QDir::separator();
112
113 if ( parameterAsBool( parameters, QStringLiteral( "PREFIX_FIELD" ), context ) )
114 {
115 baseName.append( fieldName + "_" );
116 }
117
118 int current = 0;
119 const double step = uniqueValues.size() > 0 ? 100.0 / uniqueValues.size() : 1;
120
121 int count = 0;
122 QgsFeature feat;
123 QStringList outputLayers;
124 std::unique_ptr< QgsFeatureSink > sink;
125
126 for ( auto it = uniqueValues.constBegin(); it != uniqueValues.constEnd(); ++it )
127 {
128 if ( feedback->isCanceled() )
129 break;
130
131 QString fileName;
132 if ( QgsVariantUtils::isNull( *it ) )
133 {
134 fileName = QStringLiteral( "%1NULL.%2" ).arg( baseName ).arg( outputFormat );
135 }
136 else if ( ( *it ).toString().isEmpty() )
137 {
138 fileName = QStringLiteral( "%1EMPTY.%2" ).arg( baseName ).arg( outputFormat );
139 }
140 else
141 {
142 fileName = QStringLiteral( "%1%2.%3" ).arg( baseName ).arg( ( *it ).toString() ).arg( outputFormat );
143 }
144 feedback->pushInfo( QObject::tr( "Creating layer: %1" ).arg( fileName ) );
145
146 sink.reset( QgsProcessingUtils::createFeatureSink( fileName, context, fields, geometryType, crs ) );
147 const QString expr = QgsExpression::createFieldEqualityExpression( fieldName, *it );
148 QgsFeatureIterator features = source->getFeatures( QgsFeatureRequest().setFilterExpression( expr ) );
149 count = 0;
150 while ( features.nextFeature( feat ) )
151 {
152 if ( feedback->isCanceled() )
153 break;
154
155 if ( !sink->addFeature( feat, QgsFeatureSink::FastInsert ) )
156 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, QStringLiteral( "OUTPUT" ) ) );
157 count += 1;
158 }
159
160 feedback->pushInfo( QObject::tr( "Added %n feature(s) to layer", nullptr, count ) );
161 outputLayers << fileName;
162
163 current += 1;
164 feedback->setProgress( current * step );
165 }
166
167 QVariantMap outputs;
168 outputs.insert( QStringLiteral( "OUTPUT" ), outputDir );
169 outputs.insert( QStringLiteral( "OUTPUT_LAYERS" ), outputLayers );
170 return outputs;
171}
172
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition: qgis.h:154
This class represents a coordinate reference system (CRS).
static QString createFieldEqualityExpression(const QString &fieldName, const QVariant &value, QVariant::Type fieldType=QVariant::Type::Invalid)
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)
This class 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:56
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:63
Container of fields for a vector layer.
Definition: qgsfields.h:45
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:359
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.
Definition: qgsexception.h:84
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...
@ FlagAdvanced
Parameter is an advanced parameter which should be hidden from users by default.
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.
@ TypeVector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
Definition: qgsprocessing.h:55
static bool isNull(const QVariant &variant)
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".
const QgsCoordinateReferenceSystem & crs