24 QString QgsAggregateAlgorithm::name()
const
26 return QStringLiteral(
"aggregate" );
29 QString QgsAggregateAlgorithm::displayName()
const
31 return QObject::tr(
"Aggregate" );
34 QString QgsAggregateAlgorithm::shortHelpString()
const
36 return QObject::tr(
"This algorithm take a vector or table layer and aggregate 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." );
43 QStringList QgsAggregateAlgorithm::tags()
const
45 return QObject::tr(
"attributes,sum,mean,collect,dissolve,statistics" ).split(
',' );
48 QString QgsAggregateAlgorithm::group()
const
50 return QObject::tr(
"Vector geometry" );
53 QString QgsAggregateAlgorithm::groupId()
const
55 return QStringLiteral(
"vectorgeometry" );
58 QgsAggregateAlgorithm *QgsAggregateAlgorithm::createInstance()
const
60 return new QgsAggregateAlgorithm();
63 void QgsAggregateAlgorithm::initAlgorithm(
const QVariantMap & )
66 addParameter(
new QgsProcessingParameterExpression( QStringLiteral(
"GROUP_BY" ), QObject::tr(
"Group by expression (NULL to group all features)" ), QStringLiteral(
"NULL" ), QStringLiteral(
"INPUT" ) ) );
73 mSource.reset( parameterAsSource( parameters, QStringLiteral(
"INPUT" ), context ) );
77 mGroupBy = parameterAsExpression( parameters, QStringLiteral(
"GROUP_BY" ), context );
82 mGroupByExpression = createExpression( mGroupBy, context );
83 mGeometryExpression = createExpression( QStringLiteral(
"collect($geometry, %1)" ).arg( mGroupBy ), context );
85 const QVariantList aggregates = parameters.value( QStringLiteral(
"AGGREGATES" ) ).toList();
86 int currentAttributeIndex = 0;
87 for (
const QVariant &aggregate : aggregates )
89 const QVariantMap aggregateDef = aggregate.toMap();
91 const QString name = aggregateDef.value( QStringLiteral(
"name" ) ).toString();
95 const QVariant::Type type =
static_cast< QVariant::Type
>( aggregateDef.value( QStringLiteral(
"type" ) ).toInt() );
96 const QString
typeName = aggregateDef.value( QStringLiteral(
"type_name" ) ).toString();
97 const QVariant::Type subType =
static_cast< QVariant::Type
>( aggregateDef.value( QStringLiteral(
"sub_type" ) ).toInt() );
99 const int length = aggregateDef.value( QStringLiteral(
"length" ), 0 ).toInt();
100 const int precision = aggregateDef.value( QStringLiteral(
"precision" ), 0 ).toInt();
105 const QString aggregateType = aggregateDef.value( QStringLiteral(
"aggregate" ) ).toString();
106 const QString source = aggregateDef.value( QStringLiteral(
"input" ) ).toString();
107 const QString delimiter = aggregateDef.value( QStringLiteral(
"delimiter" ) ).toString();
110 if ( aggregateType == QLatin1String(
"first_value" ) )
114 else if ( aggregateType == QLatin1String(
"last_value" ) )
117 mAttributesRequireLastFeature << currentAttributeIndex;
119 else if ( aggregateType == QLatin1String(
"concatenate" ) || aggregateType == QLatin1String(
"concatenate_unique" ) )
121 expression = QStringLiteral(
"%1(%2, %3, %4, %5)" ).arg( aggregateType,
124 QStringLiteral(
"TRUE" ),
129 expression = QStringLiteral(
"%1(%2, %3)" ).arg( aggregateType, source, mGroupBy );
131 mExpressions.append( createExpression( expression, context ) );
132 currentAttributeIndex++;
140 QgsExpressionContext expressionContext = createExpressionContext( parameters, context, mSource.get() );
141 mGroupByExpression.prepare( &expressionContext );
144 const long long count = mSource->featureCount();
145 double progressStep = count > 0 ? 50.0 / count : 1;
146 long long current = 0;
148 QHash< QVariantList, Group > groups;
149 QVector< QVariantList > keys;
152 std::vector< std::unique_ptr< QgsFeatureSink > > groupSinks;
158 const QVariant groupByValue = mGroupByExpression.evaluate( &expressionContext );
159 if ( mGroupByExpression.hasEvalError() )
161 throw QgsProcessingException( QObject::tr(
"Evaluation error in group by expression \"%1\": %2" ).arg( mGroupByExpression.expression(),
162 mGroupByExpression.evalErrorString() ) );
166 const QVariantList key = groupByValue.type() == QVariant::List ? groupByValue.toList() : ( QVariantList() << groupByValue );
168 const auto groupIt = groups.find( key );
169 if ( groupIt == groups.end() )
171 QString
id = QStringLiteral(
"memory:" );
176 mSource->sourceCrs() ) );
184 group.sink = sink.get();
186 groupSinks.emplace_back( std::move( sink ) );
188 group.firstFeature = feature;
189 group.lastFeature = feature;
197 groupIt->lastFeature = feature;
210 std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral(
"OUTPUT" ), context, destId, mFields,
QgsWkbTypes::multiType( mSource->wkbType() ), mSource->sourceCrs() ) );
216 progressStep = 50.0 / keys.size();
219 for (
const QVariantList &key : keys )
221 const Group &group = groups[ key ];
228 if ( mGeometryExpression.hasEvalError() )
230 throw QgsProcessingException( QObject::tr(
"Evaluation error in geometry expression \"%1\": %2" ).arg( mGeometryExpression.expression(),
231 mGeometryExpression.evalErrorString() ) );
239 QStringList keyString;
240 for (
const QVariant &v : key )
241 keyString << v.toString();
243 throw QgsProcessingException( QObject::tr(
"Impossible to combine geometries for %1 = %2" ).arg( mGroupBy, keyString.join(
',' ) ) );
248 attributes.reserve( mExpressions.size() );
249 int currentAttributeIndex = 0;
250 for (
auto it = mExpressions.begin(); it != mExpressions.end(); ++it )
252 exprContext.
setFeature( mAttributesRequireLastFeature.contains( currentAttributeIndex ) ? group.lastFeature : group.firstFeature );
255 const QVariant value = it->evaluate( &exprContext );
256 if ( it->hasEvalError() )
258 throw QgsProcessingException( QObject::tr(
"Evaluation error in expression \"%1\": %2" ).arg( it->expression(), it->evalErrorString() ) );
260 attributes.append( value );
264 attributes.append( QVariant() );
266 currentAttributeIndex++;
277 feedback->
setProgress( 50 + current * progressStep );
283 results.insert( QStringLiteral(
"OUTPUT" ), destId );
287 bool QgsAggregateAlgorithm::supportInPlaceEdit(
const QgsMapLayer *layer )
const
296 expr.setGeomCalculator( &mDa );
298 expr.setAreaUnits( context.
areaUnit() );
299 if ( expr.hasParserError() )
302 QObject::tr(
"Parser error in expression \"%1\": %2" ).arg( expressionString, expr.parserErrorString() ) );