QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
qgsalgorithmflattenrelationships.cpp
Go to the documentation of this file.
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
19#include "qgsrelationmanager.h"
20#include "qgsvectorlayer.h"
22
24
25QString QgsFlattenRelationshipsAlgorithm::name() const
26{
27 return QStringLiteral( "flattenrelationships" );
28}
29
30QString QgsFlattenRelationshipsAlgorithm::displayName() const
31{
32 return QObject::tr( "Flatten relationship" );
33}
34
35QStringList QgsFlattenRelationshipsAlgorithm::tags() const
36{
37 return QObject::tr( "join,export,single,table" ).split( ',' );
38}
39
40QString QgsFlattenRelationshipsAlgorithm::group() const
41{
42 return QObject::tr( "Vector general" );
43}
44
45QString QgsFlattenRelationshipsAlgorithm::groupId() const
46{
47 return QStringLiteral( "vectorgeneral" );
48}
49
50QString QgsFlattenRelationshipsAlgorithm::shortDescription() const
51{
52 return QObject::tr( "Flatten a relationship for a vector layer." );
53}
54
55QString QgsFlattenRelationshipsAlgorithm::shortHelpString() const
56{
57 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
62QgsProcessingAlgorithm::Flags QgsFlattenRelationshipsAlgorithm::flags() const
63{
64 return QgsProcessingAlgorithm::flags() | FlagRequiresProject;
65}
66
67void QgsFlattenRelationshipsAlgorithm::initAlgorithm( const QVariantMap & )
68{
69 addParameter( new QgsProcessingParameterVectorLayer( QStringLiteral( "INPUT" ),
70 QObject::tr( "Input layer" ), QList< int>() << QgsProcessing::TypeVector ) );
71
72 addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Flattened layer" ), QgsProcessing::TypeVectorAnyGeometry ) );
73}
74
75QgsFlattenRelationshipsAlgorithm *QgsFlattenRelationshipsAlgorithm::createInstance() const
76{
77 return new QgsFlattenRelationshipsAlgorithm();
78}
79
80bool QgsFlattenRelationshipsAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
81{
82 QgsProject *project = context.project();
83 if ( !project )
84 throw QgsProcessingException( QObject::tr( "No project available for relationships" ) );
85
86 QgsVectorLayer *layer = parameterAsVectorLayer( parameters, QStringLiteral( "INPUT" ), context );
87 if ( !layer )
88 throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
89
90 const QList<QgsRelation> relations = project->relationManager()->referencedRelations( layer );
91 if ( relations.size() > 1 )
92 throw QgsProcessingException( QObject::tr( "Found %n relation(s). This algorithm currently supports only a single relation.", nullptr, relations.size() ) );
93 else if ( relations.empty() )
94 throw QgsProcessingException( QObject::tr( "No relations found." ) );
95
96 mRelation = relations.at( 0 );
97
98 QgsVectorLayer *referencingLayer = mRelation.referencingLayer();
99 if ( !referencingLayer )
100 throw QgsProcessingException( QObject::tr( "Could not resolved referenced layer." ) );
101
102 mReferencingSource = std::make_unique< QgsVectorLayerFeatureSource >( referencingLayer );
103 mReferencingFields = referencingLayer->fields();
104
105 return true;
106}
107
108QVariantMap QgsFlattenRelationshipsAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
109{
110 std::unique_ptr< QgsProcessingFeatureSource > input( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
111 if ( !input )
112 throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
113
114 const QgsFields outFields = QgsProcessingUtils::combineFields( input->fields(), mReferencingFields );
115
116 QString dest;
117 std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, outFields,
118 input->wkbType(), input->sourceCrs(), QgsFeatureSink::RegeneratePrimaryKey ) );
119 if ( parameters.value( QStringLiteral( "OUTPUT" ) ).isValid() && !sink )
120 throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
121
122 // Create output vector layer with additional attributes
123 const double step = input->featureCount() > 0 ? 100.0 / input->featureCount() : 1;
125 long long i = 0;
126 QgsFeature feat;
127 while ( features.nextFeature( feat ) )
128 {
129 i++;
130 if ( feedback->isCanceled() )
131 {
132 break;
133 }
134
135 feedback->setProgress( i * step );
136
137 QgsFeatureRequest referencingRequest = mRelation.getRelatedFeaturesRequest( feat );
138 referencingRequest.setFlags( referencingRequest.flags() | QgsFeatureRequest::NoGeometry );
139 QgsFeatureIterator childIt = mReferencingSource->getFeatures( referencingRequest );
140 QgsFeature relatedFeature;
141 while ( childIt.nextFeature( relatedFeature ) )
142 {
143 QgsAttributes attrs = feat.attributes();
144 attrs.append( relatedFeature.attributes() );
145 QgsFeature outFeat = feat;
146 outFeat.setAttributes( attrs );
147 if ( !sink->addFeature( outFeat, QgsFeatureSink::FastInsert ) )
148 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, QStringLiteral( "OUTPUT" ) ) );
149 }
150 }
151
152 QVariantMap outputs;
153 if ( sink )
154 outputs.insert( QStringLiteral( "OUTPUT" ), dest );
155 return outputs;
156}
157
158
A vector of attributes.
Definition: qgsattributes.h:59
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).
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
Flags flags() const
Returns the flags which affect how features are fetched.
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
@ FastInsert
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
@ RegeneratePrimaryKey
This flag indicates, that a primary key field cannot be guaranteed to be unique and the sink should i...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
QgsAttributes attributes
Definition: qgsfeature.h:65
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
Definition: qgsfeature.cpp:160
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
virtual Flags flags() const
Returns the flags indicating how and when the algorithm operates and should be exposed to users.
Contains information about the context in which a processing algorithm is executed.
QgsProject * project() const
Returns the project in which the algorithm is being executed.
Custom exception class for processing related exceptions.
Definition: qgsexception.h:83
@ FlagSkipGeometryValidityChecks
Invalid geometry checks should always be skipped. This flag can be useful for algorithms which always...
Base class for providing feedback from a processing algorithm.
A feature sink output for processing algorithms.
A vector layer (with or without geometry) parameter for processing algorithms.
static QgsFields combineFields(const QgsFields &fieldsA, const QgsFields &fieldsB, const QString &fieldsBPrefix=QString())
Combines two field lists, avoiding duplicate field names (in a case-insensitive manner).
@ TypeVector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
Definition: qgsprocessing.h:54
@ TypeVectorAnyGeometry
Any vector layer with geometry.
Definition: qgsprocessing.h:48
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition: qgsproject.h:104
QgsRelationManager * relationManager
Definition: qgsproject.h:114
QList< QgsRelation > referencedRelations(const QgsVectorLayer *layer=nullptr) const
Gets all relations where this layer is the referenced part (i.e.
Represents a vector layer which manages a vector based data sets.
QgsFields fields() const FINAL
Returns the list of fields of this layer.