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" ).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();
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() );
97 const int length = aggregateDef.value( QStringLiteral(
"length" ), 0 ).toInt();
98 const int precision = aggregateDef.value( QStringLiteral(
"precision" ), 0 ).toInt();
103 const QString aggregateType = aggregateDef.value( QStringLiteral(
"aggregate" ) ).toString();
104 const QString source = aggregateDef.value( QStringLiteral(
"input" ) ).toString();
105 const QString delimiter = aggregateDef.value( QStringLiteral(
"delimiter" ) ).toString();
108 if ( aggregateType == QLatin1String(
"first_value" ) )
112 else if ( aggregateType == QLatin1String(
"concatenate" ) || aggregateType == QLatin1String(
"concatenate_unique" ) )
114 expression = QStringLiteral(
"%1(%2, %3, %4, \'%5\')" ).arg( aggregateType,
117 QStringLiteral(
"TRUE" ),
122 expression = QStringLiteral(
"%1(%2, %3)" ).arg( aggregateType, source, mGroupBy );
124 mExpressions.append( createExpression( expression, context ) );
132 QgsExpressionContext expressionContext = createExpressionContext( parameters, context, mSource.get() );
133 mGroupByExpression.prepare( &expressionContext );
136 const long long count = mSource->featureCount();
137 double progressStep = count > 0 ? 50.0 / count : 1;
138 long long current = 0;
140 QHash< QVariantList, Group > groups;
141 QVector< QVariantList > keys;
144 std::vector< std::unique_ptr< QgsFeatureSink > > groupSinks;
150 const QVariant groupByValue = mGroupByExpression.evaluate( &expressionContext );
151 if ( mGroupByExpression.hasEvalError() )
153 throw QgsProcessingException( QObject::tr(
"Evaluation error in group by expression \"%1\": %2" ).arg( mGroupByExpression.expression(),
154 mGroupByExpression.evalErrorString() ) );
158 const QVariantList key = groupByValue.type() == QVariant::List ? groupByValue.toList() : ( QVariantList() << groupByValue );
160 auto groupIt = groups.constFind( key );
161 if ( groupIt == groups.constEnd() )
163 QString
id = QStringLiteral(
"memory:" );
168 mSource->sourceCrs() ) );
175 group.sink = sink.get();
177 groupSinks.emplace_back( std::move( sink ) );
179 group.feature = feature;
198 std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral(
"OUTPUT" ), context, destId, mFields,
QgsWkbTypes::multiType( mSource->wkbType() ), mSource->sourceCrs() ) );
204 progressStep = 50.0 / keys.size();
207 for (
const QVariantList &key : keys )
209 Group &group = groups[ key ];
216 if ( mGeometryExpression.hasEvalError() )
218 throw QgsProcessingException( QObject::tr(
"Evaluation error in geometry expression \"%1\": %2" ).arg( mGeometryExpression.expression(),
219 mGeometryExpression.evalErrorString() ) );
227 QStringList keyString;
228 for (
const QVariant &v : key )
229 keyString << v.toString();
231 throw QgsProcessingException( QObject::tr(
"Impossible to combine geometries for %1 = %2" ).arg( mGroupBy, keyString.join(
',' ) ) );
236 attributes.reserve( mExpressions.size() );
237 for (
auto it = mExpressions.begin(); it != mExpressions.end(); ++it )
241 const QVariant value = it->evaluate( &exprContext );
242 if ( it->hasEvalError() )
244 throw QgsProcessingException( QObject::tr(
"Evaluation error in expression \"%1\": %2" ).arg( it->expression(), it->evalErrorString() ) );
246 attributes.append( value );
250 attributes.append( QVariant() );
261 feedback->
setProgress( 50 + current * progressStep );
267 results.insert( QStringLiteral(
"OUTPUT" ), destId );
271 bool QgsAggregateAlgorithm::supportInPlaceEdit(
const QgsMapLayer *layer )
const
280 expr.setGeomCalculator( &mDa );
283 if ( expr.hasParserError() )
286 QObject::tr(
"Parser error in expression \"%1\": %2" ).arg( expressionString, expr.parserErrorString() ) );