Branch data Line data Source code
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 : : 18 : : #include "qgsalgorithmsplitvectorlayer.h" 19 : : #include "qgsvectorfilewriter.h" 20 : : 21 : : ///@cond PRIVATE 22 : : 23 : 0 : QString QgsSplitVectorLayerAlgorithm::name() const 24 : : { 25 : 0 : return QStringLiteral( "splitvectorlayer" ); 26 : : } 27 : : 28 : 0 : QString QgsSplitVectorLayerAlgorithm::displayName() const 29 : : { 30 : 0 : return QObject::tr( "Split vector layer" ); 31 : : } 32 : : 33 : 0 : QStringList QgsSplitVectorLayerAlgorithm::tags() const 34 : : { 35 : 0 : return QObject::tr( "vector,split,field,unique" ).split( ',' ); 36 : 0 : } 37 : : 38 : 0 : QString QgsSplitVectorLayerAlgorithm::group() const 39 : : { 40 : 0 : return QObject::tr( "Vector general" ); 41 : : } 42 : : 43 : 0 : QString QgsSplitVectorLayerAlgorithm::groupId() const 44 : : { 45 : 0 : return QStringLiteral( "vectorgeneral" ); 46 : : } 47 : : 48 : 0 : QString QgsSplitVectorLayerAlgorithm::shortHelpString() const 49 : : { 50 : 0 : return QObject::tr( "Splits input vector layer into multiple layers by specified unique ID field." ) 51 : 0 : + QStringLiteral( "\n\n" ) 52 : 0 : + QObject::tr( "Each of the layers created in the output folder contains all features from " 53 : : "the input layer with the same value for the specified attribute. The number " 54 : : "of files generated is equal to the number of different values found for the " 55 : : "specified attribute." ); 56 : 0 : } 57 : : 58 : 0 : QgsSplitVectorLayerAlgorithm *QgsSplitVectorLayerAlgorithm::createInstance() const 59 : : { 60 : 0 : return new QgsSplitVectorLayerAlgorithm(); 61 : : } 62 : : 63 : 0 : void QgsSplitVectorLayerAlgorithm::initAlgorithm( const QVariantMap & ) 64 : : { 65 : 0 : addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) ); 66 : 0 : addParameter( new QgsProcessingParameterField( QStringLiteral( "FIELD" ), QObject::tr( "Unique ID field" ), 67 : 0 : QVariant(), QStringLiteral( "INPUT" ) ) ); 68 : : 69 : 0 : QStringList options = QgsVectorFileWriter::supportedFormatExtensions(); 70 : 0 : auto fileTypeParam = std::make_unique < QgsProcessingParameterEnum >( QStringLiteral( "FILE_TYPE" ), QObject::tr( "Output file type" ), options, false, QVariantList() << 0, true ); 71 : 0 : fileTypeParam->setFlags( QgsProcessingParameterDefinition::FlagAdvanced ); 72 : 0 : addParameter( fileTypeParam.release() ); 73 : : 74 : 0 : addParameter( new QgsProcessingParameterFolderDestination( QStringLiteral( "OUTPUT" ), QObject::tr( "Output directory" ) ) ); 75 : 0 : addOutput( new QgsProcessingOutputMultipleLayers( QStringLiteral( "OUTPUT_LAYERS" ), QObject::tr( "Output layers" ) ) ); 76 : 0 : } 77 : : 78 : 0 : QVariantMap QgsSplitVectorLayerAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) 79 : : { 80 : 0 : std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) ); 81 : 0 : if ( !source ) 82 : 0 : throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) ); 83 : : 84 : 0 : QString fieldName = parameterAsString( parameters, QStringLiteral( "FIELD" ), context ); 85 : 0 : QString outputDir = parameterAsString( parameters, QStringLiteral( "OUTPUT" ), context ); 86 : 0 : QString outputFormat; 87 : 0 : if ( parameters.value( QStringLiteral( "FILE_TYPE" ) ).isValid() ) 88 : : { 89 : 0 : int idx = parameterAsEnum( parameters, QStringLiteral( "FILE_TYPE" ), context ); 90 : 0 : outputFormat = QgsVectorFileWriter::supportedFormatExtensions().at( idx ); 91 : 0 : } 92 : : else 93 : : { 94 : 0 : outputFormat = context.preferredVectorFormat(); 95 : 0 : if ( !QgsVectorFileWriter::supportedFormatExtensions().contains( outputFormat, Qt::CaseInsensitive ) ) 96 : 0 : outputFormat = QStringLiteral( "gpkg" ); 97 : : } 98 : : 99 : 0 : if ( !QDir().mkpath( outputDir ) ) 100 : 0 : throw QgsProcessingException( QStringLiteral( "Failed to create output directory." ) ); 101 : : 102 : 0 : QgsFields fields = source->fields(); 103 : 0 : QgsCoordinateReferenceSystem crs = source->sourceCrs(); 104 : 0 : QgsWkbTypes::Type geometryType = source->wkbType(); 105 : 0 : int fieldIndex = fields.lookupField( fieldName ); 106 : 0 : QSet< QVariant > uniqueValues = source->uniqueValues( fieldIndex ); 107 : 0 : QString baseName = outputDir + QDir::separator() + fieldName; 108 : : 109 : 0 : int current = 0; 110 : 0 : double step = uniqueValues.size() > 0 ? 100.0 / uniqueValues.size() : 1; 111 : : 112 : 0 : int count = 0; 113 : 0 : QgsFeature feat; 114 : 0 : QStringList outputLayers; 115 : 0 : std::unique_ptr< QgsFeatureSink > sink; 116 : : 117 : 0 : for ( auto it = uniqueValues.constBegin(); it != uniqueValues.constEnd(); ++it ) 118 : : { 119 : 0 : if ( feedback->isCanceled() ) 120 : 0 : break; 121 : : 122 : 0 : QString fileName = QStringLiteral( "%1_%2.%3" ).arg( baseName ).arg( ( *it ).toString() ).arg( outputFormat ); 123 : 0 : feedback->pushInfo( QObject::tr( "Creating layer: %1" ).arg( fileName ) ); 124 : : 125 : 0 : sink.reset( QgsProcessingUtils::createFeatureSink( fileName, context, fields, geometryType, crs ) ); 126 : 0 : QString expr = QgsExpression::createFieldEqualityExpression( fieldName, *it ); 127 : 0 : QgsFeatureIterator features = source->getFeatures( QgsFeatureRequest().setFilterExpression( expr ) ); 128 : 0 : while ( features.nextFeature( feat ) ) 129 : : { 130 : 0 : if ( feedback->isCanceled() ) 131 : 0 : break; 132 : : 133 : 0 : sink->addFeature( feat, QgsFeatureSink::FastInsert ); 134 : 0 : count += 1; 135 : : } 136 : : 137 : 0 : feedback->pushInfo( QObject::tr( "Added %1 features to layer" ).arg( count ) ); 138 : 0 : outputLayers << fileName; 139 : : 140 : 0 : current += 1; 141 : 0 : feedback->setProgress( current * step ); 142 : 0 : } 143 : : 144 : 0 : QVariantMap outputs; 145 : 0 : outputs.insert( QStringLiteral( "OUTPUT" ), outputDir ); 146 : 0 : outputs.insert( QStringLiteral( "OUTPUT_LAYERS" ), outputLayers ); 147 : 0 : return outputs; 148 : 0 : } 149 : : 150 : : ///@endcond