24QString QgsAggregateAlgorithm::name()
const
26 return QStringLiteral(
"aggregate" );
29QString QgsAggregateAlgorithm::displayName()
const
31 return QObject::tr(
"Aggregate" );
34QString QgsAggregateAlgorithm::shortHelpString()
const
36 return QObject::tr(
"This algorithm takes a vector or table layer and aggregates features based on a group by expression. Features for which group by expression return the same value are grouped together.\n\n"
37 "It is possible to group all source features together using constant value in group by parameter, example: NULL.\n\n"
38 "It is also possible to group features using multiple fields using Array function, example: Array(\"Field1\", \"Field2\").\n\n"
39 "Geometries (if present) are combined into one multipart geometry for each group.\n\n"
40 "Output attributes are computed depending on each given aggregate definition." );
43QString QgsAggregateAlgorithm::shortDescription()
const
45 return QObject::tr(
"Aggregates features based on a group by expression, combining geometries (if present) into one multipart geometry for each group." );
48QStringList QgsAggregateAlgorithm::tags()
const
50 return QObject::tr(
"attributes,sum,mean,collect,dissolve,statistics" ).split(
',' );
53QString QgsAggregateAlgorithm::group()
const
55 return QObject::tr(
"Vector geometry" );
58QString QgsAggregateAlgorithm::groupId()
const
60 return QStringLiteral(
"vectorgeometry" );
63QgsAggregateAlgorithm *QgsAggregateAlgorithm::createInstance()
const
65 return new QgsAggregateAlgorithm();
68void QgsAggregateAlgorithm::initAlgorithm(
const QVariantMap & )
71 addParameter(
new QgsProcessingParameterExpression( QStringLiteral(
"GROUP_BY" ), QObject::tr(
"Group by expression (NULL to group all features)" ), QStringLiteral(
"NULL" ), QStringLiteral(
"INPUT" ) ) );
78 mSource.reset( parameterAsSource( parameters, QStringLiteral(
"INPUT" ), context ) );
82 mGroupBy = parameterAsExpression( parameters, QStringLiteral(
"GROUP_BY" ), context );
87 mGroupByExpression = createExpression( mGroupBy, context );
88 mGeometryExpression = createExpression( QStringLiteral(
"collect($geometry, %1)" ).arg( mGroupBy ), context );
90 const QVariantList aggregates = parameters.value( QStringLiteral(
"AGGREGATES" ) ).toList();
91 int currentAttributeIndex = 0;
92 for (
const QVariant &aggregate : aggregates )
94 const QVariantMap aggregateDef = aggregate.toMap();
96 const QString name = aggregateDef.value( QStringLiteral(
"name" ) ).toString();
100 const QMetaType::Type type =
static_cast<QMetaType::Type
>( aggregateDef.value( QStringLiteral(
"type" ) ).toInt() );
101 const QString
typeName = aggregateDef.value( QStringLiteral(
"type_name" ) ).toString();
102 const QMetaType::Type subType =
static_cast<QMetaType::Type
>( aggregateDef.value( QStringLiteral(
"sub_type" ) ).toInt() );
104 const int length = aggregateDef.value( QStringLiteral(
"length" ), 0 ).toInt();
105 const int precision = aggregateDef.value( QStringLiteral(
"precision" ), 0 ).toInt();
110 const QString aggregateType = aggregateDef.value( QStringLiteral(
"aggregate" ) ).toString();
111 const QString source = aggregateDef.value( QStringLiteral(
"input" ) ).toString();
112 const QString delimiter = aggregateDef.value( QStringLiteral(
"delimiter" ) ).toString();
115 if ( aggregateType == QLatin1String(
"first_value" ) )
119 else if ( aggregateType == QLatin1String(
"last_value" ) )
122 mAttributesRequireLastFeature << currentAttributeIndex;
124 else if ( aggregateType == QLatin1String(
"concatenate" ) || aggregateType == QLatin1String(
"concatenate_unique" ) )
126 expression = QStringLiteral(
"%1(%2, %3, %4, %5)" ).arg( aggregateType, source, mGroupBy, QStringLiteral(
"TRUE" ),
QgsExpression::quotedString( delimiter ) );
130 expression = QStringLiteral(
"%1(%2, %3)" ).arg( aggregateType, source, mGroupBy );
132 mExpressions.append( createExpression( expression, context ) );
133 currentAttributeIndex++;
141 QgsExpressionContext expressionContext = createExpressionContext( parameters, context, mSource.get() );
142 mGroupByExpression.prepare( &expressionContext );
145 const long long count = mSource->featureCount();
146 double progressStep = count > 0 ? 50.0 / count : 1;
147 long long current = 0;
149 QHash<QVariantList, Group> groups;
150 QVector<QVariantList> keys;
153 std::vector<std::unique_ptr<QgsFeatureSink>> groupSinks;
159 const QVariant groupByValue = mGroupByExpression.evaluate( &expressionContext );
160 if ( mGroupByExpression.hasEvalError() )
162 throw QgsProcessingException( QObject::tr(
"Evaluation error in group by expression \"%1\": %2" ).arg( mGroupByExpression.expression(), mGroupByExpression.evalErrorString() ) );
166 const QVariantList key = groupByValue.userType() == QMetaType::Type::QVariantList ? groupByValue.toList() : ( QVariantList() << groupByValue );
168 const auto groupIt = groups.find( key );
169 if ( groupIt == groups.end() )
171 QString
id = QStringLiteral(
"memory:" );
180 group.sink = sink.get();
182 groupSinks.emplace_back( std::move( sink ) );
184 group.firstFeature = feature;
185 group.lastFeature = feature;
193 groupIt->lastFeature = feature;
206 std::unique_ptr<QgsFeatureSink> sink( parameterAsSink( parameters, QStringLiteral(
"OUTPUT" ), context, destId, mFields,
QgsWkbTypes::multiType( mSource->wkbType() ), mSource->sourceCrs() ) );
212 progressStep = 50.0 / keys.size();
215 for (
const QVariantList &key : keys )
217 const Group &group = groups[key];
224 if ( mGeometryExpression.hasEvalError() )
226 throw QgsProcessingException( QObject::tr(
"Evaluation error in geometry expression \"%1\": %2" ).arg( mGeometryExpression.expression(), mGeometryExpression.evalErrorString() ) );
234 QStringList keyString;
235 for (
const QVariant &v : key )
236 keyString << v.toString();
238 throw QgsProcessingException( QObject::tr(
"Impossible to combine geometries for %1 = %2" ).arg( mGroupBy, keyString.join(
',' ) ) );
243 attributes.reserve( mExpressions.size() );
244 int currentAttributeIndex = 0;
245 for (
auto it = mExpressions.begin(); it != mExpressions.end(); ++it )
247 exprContext.
setFeature( mAttributesRequireLastFeature.contains( currentAttributeIndex ) ? group.lastFeature : group.firstFeature );
250 const QVariant value = it->evaluate( &exprContext );
251 if ( it->hasEvalError() )
253 throw QgsProcessingException( QObject::tr(
"Evaluation error in expression \"%1\": %2" ).arg( it->expression(), it->evalErrorString() ) );
255 attributes.append( value );
259 attributes.append( QVariant() );
261 currentAttributeIndex++;
272 feedback->
setProgress( 50 + current * progressStep );
280 results.insert( QStringLiteral(
"OUTPUT" ), destId );
284bool QgsAggregateAlgorithm::supportInPlaceEdit(
const QgsMapLayer *layer )
const
293 expr.setGeomCalculator( &mDa );
295 expr.setAreaUnits( context.
areaUnit() );
296 if ( expr.hasParserError() )
299 QObject::tr(
"Parser error in expression \"%1\": %2" ).arg( expressionString, expr.parserErrorString() )
@ Vector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
Handles parsing and evaluation of expressions (formerly called "search strings").
static QString quotedString(QString text)
Returns a quoted version of a string (in single quotes)
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.
bool isValid() const
Will return if this iterator is valid.
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...
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
bool isCanceled() const
Tells whether the operation has been canceled already.
void setProgress(double progress)
Sets the current progress for the feedback object.
Encapsulate a field in an attribute table or data source.
A geometry is the spatial representation of a feature.
QVector< QgsGeometry > asGeometryCollection() const
Returns contents of the geometry as a list of geometries.
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
static QgsGeometry unaryUnion(const QVector< QgsGeometry > &geometries, const QgsGeometryParameters ¶meters=QgsGeometryParameters())
Compute the unary union on a list of geometries.
Base class for all map layer types.
Contains information about the context in which a processing algorithm is executed.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
Qgis::AreaUnit areaUnit() const
Returns the area unit to use for area calculations.
Qgis::DistanceUnit distanceUnit() const
Returns the distance unit to use for distance calculations.
QString ellipsoid() const
Returns the ellipsoid to use for distance and area calculations.
Custom exception class for processing related exceptions.
Base class for providing feedback from a processing algorithm.
A parameter for "aggregate" configurations, which consist of a definition of desired output fields,...
An expression parameter for processing algorithms.
A feature sink output for processing algorithms.
An input feature source (such as vector layers) parameter for processing algorithms.
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 QgsMapLayer * mapLayerFromString(const QString &string, QgsProcessingContext &context, bool allowLoadingNewLayers=true, QgsProcessingUtils::LayerHint typeHint=QgsProcessingUtils::LayerHint::UnknownType, QgsProcessing::LayerOptionsFlags flags=QgsProcessing::LayerOptionsFlags())
Interprets a string as a map layer within the supplied context.
static Qgis::WkbType multiType(Qgis::WkbType type)
Returns the multi type for a WKB type.