QGIS API Documentation  3.21.0-Master (5b68dc587e)
qgsalgorithmfieldcalculator.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsalgorithmfieldcalculator.h
3  ----------------------
4  begin : September 2020
5  copyright : (C) 2020 by Ivan Ivanov
6  email : [email protected]
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 
18 
21 
23 
24 QString QgsFieldCalculatorAlgorithm::name() const
25 {
26  return QStringLiteral( "fieldcalculator" );
27 }
28 
29 QString QgsFieldCalculatorAlgorithm::displayName() const
30 {
31  return QObject::tr( "Field calculator" );
32 }
33 
34 QStringList QgsFieldCalculatorAlgorithm::tags() const
35 {
36  return QObject::tr( "field,calculator,vector" ).split( ',' );
37 }
38 
39 QString QgsFieldCalculatorAlgorithm::group() const
40 {
41  return QObject::tr( "Vector table" );
42 }
43 
44 QString QgsFieldCalculatorAlgorithm::groupId() const
45 {
46  return QStringLiteral( "vectortable" );
47 }
48 
49 QString QgsFieldCalculatorAlgorithm::outputName() const
50 {
51  return QObject::tr( "Calculated" );
52 }
53 
54 QList<int> QgsFieldCalculatorAlgorithm::inputLayerTypes() const
55 {
56  return QList<int>() << QgsProcessing::TypeVector;
57 }
58 
59 QgsProcessingFeatureSource::Flag QgsFieldCalculatorAlgorithm::sourceFlags() const
60 {
62 }
63 
64 void QgsFieldCalculatorAlgorithm::initParameters( const QVariantMap &configuration )
65 {
66  Q_UNUSED( configuration );
67 
68  const QStringList fieldTypes = QStringList( {QObject::tr( "Float" ), QObject::tr( "Integer" ), QObject::tr( "String" ), QObject::tr( "Date" ) } );
69 
70  std::unique_ptr< QgsProcessingParameterString > fieldName = std::make_unique< QgsProcessingParameterString > ( QStringLiteral( "FIELD_NAME" ), QObject::tr( "Field name" ), QVariant(), false );
71  std::unique_ptr< QgsProcessingParameterEnum > fieldType = std::make_unique< QgsProcessingParameterEnum > ( QStringLiteral( "FIELD_TYPE" ), QObject::tr( "Result field type" ), fieldTypes, false, 0 );
72  std::unique_ptr< QgsProcessingParameterNumber > fieldLength = std::make_unique< QgsProcessingParameterNumber > ( QStringLiteral( "FIELD_LENGTH" ), QObject::tr( "Result field length" ), QgsProcessingParameterNumber::Integer, QVariant( 0 ), false, 0 );
73  std::unique_ptr< QgsProcessingParameterNumber > fieldPrecision = std::make_unique< QgsProcessingParameterNumber > ( QStringLiteral( "FIELD_PRECISION" ), QObject::tr( "Result field precision" ), QgsProcessingParameterNumber::Integer, QVariant( 0 ), false, 0 );
74  std::unique_ptr< QgsProcessingParameterExpression > expression = std::make_unique< QgsProcessingParameterExpression> ( QStringLiteral( "FORMULA" ), QObject::tr( "Formula" ), QVariant(), QStringLiteral( "INPUT" ), false );
75 
76  expression->setMetadata( QVariantMap( {{"inlineEditor", true}} ) );
77 
78  addParameter( fieldName.release() );
79  addParameter( fieldType.release() );
80  addParameter( fieldLength.release() );
81  addParameter( fieldPrecision.release() );
82  addParameter( expression.release() );
83 }
84 
85 QgsFields QgsFieldCalculatorAlgorithm::outputFields( const QgsFields & ) const
86 {
87  return mFields;
88 }
89 
90 QString QgsFieldCalculatorAlgorithm::shortHelpString() const
91 {
92  return QObject::tr( "This algorithm computes a new vector layer with the same features of the input layer, "
93  "but either overwriting an existing attribute or adding an additional attribute. The values of this field "
94  "are computed from each feature using an expression, based on the properties and attributes of the feature. "
95  "Note that if \"Field name\" is an existing field in the layer then all the rest of the field settings are ignored." );
96 }
97 
98 QgsFieldCalculatorAlgorithm *QgsFieldCalculatorAlgorithm::createInstance() const
99 {
100  return new QgsFieldCalculatorAlgorithm();
101 }
102 
103 
104 bool QgsFieldCalculatorAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
105 {
106  std::unique_ptr< QgsProcessingFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
107 
108  if ( !source )
109  throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
110 
111  QList<QVariant::Type> fieldTypes( {QVariant::Double, QVariant::Int, QVariant::String, QVariant::Date} );
112 
113  // prepare fields
114  const int fieldTypeIdx = parameterAsInt( parameters, QStringLiteral( "FIELD_TYPE" ), context );
115  const int fieldLength = parameterAsInt( parameters, QStringLiteral( "FIELD_LENGTH" ), context );
116  const int fieldPrecision = parameterAsInt( parameters, QStringLiteral( "FIELD_PRECISION" ), context );
117  const QString fieldName = parameterAsString( parameters, QStringLiteral( "FIELD_NAME" ), context );
118 
119  const QVariant::Type fieldType = fieldTypes[fieldTypeIdx];
120 
121  if ( fieldName.isEmpty() )
122  throw QgsProcessingException( QObject::tr( "Field name must not be an empty string" ) );
123 
124  const QgsField field(
125  fieldName,
126  fieldType,
127  QString(),
128  fieldLength,
129  fieldPrecision
130  );
131 
132  mFields = source->fields();
133 
134  const int fieldIdx = mFields.indexFromName( field.name() );
135 
136  if ( fieldIdx < 0 )
137  {
138  mFields.append( field );
139  }
140  else
141  {
142  feedback->pushWarning( QObject::tr( "Field name %1 already exists and will be replaced" ).arg( field.name() ) );
143  }
144 
145  const QString dest;
146 
147  mFieldIdx = mFields.lookupField( field.name() );
148 
149  // prepare expression
150  const QString expressionString = parameterAsString( parameters, QStringLiteral( "FORMULA" ), context );
151  mExpressionContext = createExpressionContext( parameters, context, source.get() );
152  mExpression = QgsExpression( expressionString );
153  mDa.setSourceCrs( source->sourceCrs(), context.transformContext() );
154  mDa.setEllipsoid( context.ellipsoid() );
155 
156  mExpression.setGeomCalculator( &mDa );
157  mExpression.setDistanceUnits( context.distanceUnit() );
158  mExpression.setAreaUnits( context.areaUnit() );
159 
160  if ( mExpression.hasParserError() )
161  throw QgsProcessingException( QObject::tr( "Parser error with formula expression \"%2\": %3" )
162  .arg( expressionString, mExpression.parserErrorString() ) );
163 
164  mExpression.prepare( &mExpressionContext );
165 
166  return true;
167 }
168 
169 QgsFeatureList QgsFieldCalculatorAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &, QgsProcessingFeedback * )
170 {
171  QgsAttributes attributes( mFields.size() );
172  const QStringList fieldNames = mFields.names();
173  for ( const QString &fieldName : fieldNames )
174  {
175  const int attributeIndex = feature.fieldNameIndex( fieldName );
176 
177  if ( attributeIndex >= 0 )
178  attributes[attributeIndex] = feature.attribute( fieldName );
179  }
180 
181  if ( mExpression.isValid() )
182  {
183  mExpressionContext.setFeature( feature );
184  mExpressionContext.lastScope()->setVariable( QStringLiteral( "row_number" ), mRowNumber );
185 
186  const QVariant value = mExpression.evaluate( &mExpressionContext );
187 
188  if ( mExpression.hasEvalError() )
189  {
190  throw QgsProcessingException( QObject::tr( "Evaluation error in expression \"%1\": %2" )
191  .arg( mExpression.expression(), mExpression.evalErrorString() ) );
192  }
193 
194  attributes[mFieldIdx] = value;
195  }
196  else
197  {
198  attributes[mFieldIdx] = QVariant();
199  }
200 
201  QgsFeature f = feature;
202  f.setAttributes( attributes );
203  mRowNumber++;
204  return QgsFeatureList() << f;
205 }
206 
207 bool QgsFieldCalculatorAlgorithm::supportInPlaceEdit( const QgsMapLayer *layer ) const
208 {
209  Q_UNUSED( layer )
210  return false;
211 }
212 
A vector of attributes.
Definition: qgsattributes.h:58
Class for parsing and evaluation of expressions (formerly called "search strings").
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
int fieldNameIndex(const QString &fieldName) const
Utility method to get attribute index from name.
Definition: qgsfeature.cpp:317
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
Definition: qgsfeature.cpp:135
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Definition: qgsfeature.cpp:302
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:51
QString name
Definition: qgsfield.h:60
Container of fields for a vector layer.
Definition: qgsfields.h:45
Base class for all map layer types.
Definition: qgsmaplayer.h:73
Contains information about the context in which a processing algorithm is executed.
QgsUnitTypes::AreaUnit areaUnit() const
Returns the area unit to use for area calculations.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
QgsUnitTypes::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.
Definition: qgsexception.h:83
Flag
Flags controlling how QgsProcessingFeatureSource fetches features.
@ 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.
virtual void pushWarning(const QString &warning)
Pushes a warning informational message from the algorithm.
@ TypeVector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
Definition: qgsprocessing.h:54
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:834
const QgsField & field
Definition: qgsfield.h:463