Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsalgorithmflattenrelationships.h 3 : : --------------------- 4 : : begin : August 2020 5 : : copyright : (C) 2020 by Nyall Dawson 6 : : email : nyall dot dawson 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 "qgsalgorithmflattenrelationships.h" 19 : : #include "qgsrelationmanager.h" 20 : : #include "qgsvectorlayer.h" 21 : : #include "qgsvectorlayerfeatureiterator.h" 22 : : 23 : : ///@cond PRIVATE 24 : : 25 : 0 : QString QgsFlattenRelationshipsAlgorithm::name() const 26 : : { 27 : 0 : return QStringLiteral( "flattenrelationships" ); 28 : : } 29 : : 30 : 0 : QString QgsFlattenRelationshipsAlgorithm::displayName() const 31 : : { 32 : 0 : return QObject::tr( "Flatten relationship" ); 33 : : } 34 : : 35 : 0 : QStringList QgsFlattenRelationshipsAlgorithm::tags() const 36 : : { 37 : 0 : return QObject::tr( "join,export,single,table" ).split( ',' ); 38 : 0 : } 39 : : 40 : 0 : QString QgsFlattenRelationshipsAlgorithm::group() const 41 : : { 42 : 0 : return QObject::tr( "Vector general" ); 43 : : } 44 : : 45 : 0 : QString QgsFlattenRelationshipsAlgorithm::groupId() const 46 : : { 47 : 0 : return QStringLiteral( "vectorgeneral" ); 48 : : } 49 : : 50 : 0 : QString QgsFlattenRelationshipsAlgorithm::shortDescription() const 51 : : { 52 : 0 : return QObject::tr( "Flatten a relationship for a vector layer." ); 53 : : } 54 : : 55 : 0 : QString QgsFlattenRelationshipsAlgorithm::shortHelpString() const 56 : : { 57 : 0 : return QObject::tr( "This algorithm flattens a relationship for a vector layer, exporting a single layer " 58 : : "containing one master feature per related feature. This master feature contains all " 59 : : "the attributes for the related features." ); 60 : : } 61 : : 62 : 0 : QgsProcessingAlgorithm::Flags QgsFlattenRelationshipsAlgorithm::flags() const 63 : : { 64 : 0 : return QgsProcessingAlgorithm::flags() | FlagRequiresProject; 65 : : } 66 : : 67 : 0 : void QgsFlattenRelationshipsAlgorithm::initAlgorithm( const QVariantMap & ) 68 : : { 69 : 0 : addParameter( new QgsProcessingParameterVectorLayer( QStringLiteral( "INPUT" ), 70 : 0 : QObject::tr( "Input layer" ), QList< int>() << QgsProcessing::TypeVector ) ); 71 : : 72 : 0 : addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Flattened layer" ), QgsProcessing::TypeVectorAnyGeometry, QVariant(), true, true ) ); 73 : 0 : } 74 : : 75 : 0 : QgsFlattenRelationshipsAlgorithm *QgsFlattenRelationshipsAlgorithm::createInstance() const 76 : : { 77 : 0 : return new QgsFlattenRelationshipsAlgorithm(); 78 : 0 : } 79 : : 80 : 0 : bool QgsFlattenRelationshipsAlgorithm::prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback * ) 81 : : { 82 : 0 : QgsProject *project = context.project(); 83 : 0 : if ( !project ) 84 : 0 : throw QgsProcessingException( QObject::tr( "No project available for relationships" ) ); 85 : : 86 : 0 : QgsVectorLayer *layer = parameterAsVectorLayer( parameters, QStringLiteral( "INPUT" ), context ); 87 : 0 : if ( !layer ) 88 : 0 : throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) ); 89 : : 90 : 0 : const QList<QgsRelation> relations = project->relationManager()->referencedRelations( layer ); 91 : 0 : if ( relations.size() > 1 ) 92 : 0 : throw QgsProcessingException( QObject::tr( "Found %1 relations. This algorithm currently supports only a single relation." ).arg( relations.size() ) ); 93 : 0 : else if ( relations.empty() ) 94 : 0 : throw QgsProcessingException( QObject::tr( "No relations found." ) ); 95 : : 96 : 0 : mRelation = relations.at( 0 ); 97 : : 98 : 0 : QgsVectorLayer *referencingLayer = mRelation.referencingLayer(); 99 : 0 : if ( !referencingLayer ) 100 : 0 : throw QgsProcessingException( QObject::tr( "Could not resolved referenced layer." ) ); 101 : : 102 : 0 : mReferencingSource = std::make_unique< QgsVectorLayerFeatureSource >( referencingLayer ); 103 : 0 : mReferencingFields = referencingLayer->fields(); 104 : : 105 : : return true; 106 : 0 : } 107 : : 108 : 0 : QVariantMap QgsFlattenRelationshipsAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) 109 : : { 110 : 0 : std::unique_ptr< QgsProcessingFeatureSource > input( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) ); 111 : 0 : if ( !input ) 112 : 0 : throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) ); 113 : : 114 : 0 : QgsFields outFields = QgsProcessingUtils::combineFields( input->fields(), mReferencingFields ); 115 : : 116 : 0 : QString dest; 117 : 0 : std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, outFields, 118 : 0 : input->wkbType(), input->sourceCrs(), QgsFeatureSink::RegeneratePrimaryKey ) ); 119 : 0 : if ( parameters.value( QStringLiteral( "OUTPUT" ) ).isValid() && !sink ) 120 : 0 : throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) ); 121 : : 122 : : // Create output vector layer with additional attributes 123 : 0 : double step = input->featureCount() > 0 ? 100.0 / input->featureCount() : 1; 124 : 0 : QgsFeatureIterator features = input->getFeatures( QgsFeatureRequest(), QgsProcessingFeatureSource::FlagSkipGeometryValidityChecks ); 125 : 0 : long long i = 0; 126 : 0 : QgsFeature feat; 127 : 0 : while ( features.nextFeature( feat ) ) 128 : : { 129 : 0 : i++; 130 : 0 : if ( feedback->isCanceled() ) 131 : : { 132 : 0 : break; 133 : : } 134 : : 135 : 0 : feedback->setProgress( i * step ); 136 : : 137 : 0 : QgsFeatureRequest referencingRequest = mRelation.getRelatedFeaturesRequest( feat ); 138 : 0 : referencingRequest.setFlags( referencingRequest.flags() | QgsFeatureRequest::NoGeometry ); 139 : 0 : QgsFeatureIterator childIt = mReferencingSource->getFeatures( referencingRequest ); 140 : 0 : QgsFeature relatedFeature; 141 : 0 : while ( childIt.nextFeature( relatedFeature ) ) 142 : : { 143 : 0 : QgsAttributes attrs = feat.attributes(); 144 : 0 : attrs.append( relatedFeature.attributes() ); 145 : 0 : QgsFeature outFeat = feat; 146 : 0 : outFeat.setAttributes( attrs ); 147 : 0 : sink->addFeature( outFeat, QgsFeatureSink::FastInsert ); 148 : 0 : } 149 : 0 : } 150 : : 151 : 0 : QVariantMap outputs; 152 : 0 : if ( sink ) 153 : 0 : outputs.insert( QStringLiteral( "OUTPUT" ), dest ); 154 : 0 : return outputs; 155 : 0 : } 156 : : 157 : : 158 : : ///@endcond