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 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." );
 
   43QStringList QgsAggregateAlgorithm::tags()
 const 
   45  return QObject::tr( 
"attributes,sum,mean,collect,dissolve,statistics" ).split( 
',' );
 
   48QString QgsAggregateAlgorithm::group()
 const 
   50  return QObject::tr( 
"Vector geometry" );
 
   53QString QgsAggregateAlgorithm::groupId()
 const 
   55  return QStringLiteral( 
"vectorgeometry" );
 
   58QgsAggregateAlgorithm *QgsAggregateAlgorithm::createInstance()
 const 
   60  return new QgsAggregateAlgorithm();
 
   63void 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 );
 
  287bool 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() ) );
 
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.
 
Class for 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)
 
bool isValid() const
Will return if this iterator is valid.
 
This class 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 SIP_HOLDGIL
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 QgsMapLayer * mapLayerFromString(const QString &string, QgsProcessingContext &context, bool allowLoadingNewLayers=true, QgsProcessingUtils::LayerHint typeHint=QgsProcessingUtils::LayerHint::UnknownType)
Interprets a string as a map layer within the supplied context.
 
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.
 
@ TypeVector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
 
static Qgis::WkbType multiType(Qgis::WkbType type) SIP_HOLDGIL
Returns the multi type for a WKB type.