QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
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  QStringList fieldTypes = QStringList( {QObject::tr( "Float" ), QObject::tr( "Integer" ), QObject::tr( "String" ), QObject::tr( "Date" ) } );
69 
70  std::unique_ptr< QgsProcessingParameterString > fieldName = qgis::make_unique< QgsProcessingParameterString > ( QStringLiteral( "FIELD_NAME" ), QObject::tr( "Field name" ), QVariant(), false );
71  std::unique_ptr< QgsProcessingParameterEnum > fieldType = qgis::make_unique< QgsProcessingParameterEnum > ( QStringLiteral( "FIELD_TYPE" ), QObject::tr( "Result field type" ), fieldTypes, false, 0 );
72  std::unique_ptr< QgsProcessingParameterNumber > fieldLength = qgis::make_unique< QgsProcessingParameterNumber > ( QStringLiteral( "FIELD_LENGTH" ), QObject::tr( "Result field length" ), QgsProcessingParameterNumber::Integer, QVariant( 0 ), false, 0 );
73  std::unique_ptr< QgsProcessingParameterNumber > fieldPrecision = qgis::make_unique< QgsProcessingParameterNumber > ( QStringLiteral( "FIELD_PRECISION" ), QObject::tr( "Result field precision" ), QgsProcessingParameterNumber::Integer, QVariant( 0 ), false, 0 );
74  std::unique_ptr< QgsProcessingParameterExpression > expression = qgis::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 * )
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  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  int fieldIdx = mFields.lookupField( field.name() );
135 
136  if ( fieldIdx < 0 )
137  mFields.append( field );
138 
139  QString dest;
140 
141  mFieldIdx = mFields.lookupField( field.name() );
142 
143  // prepare expression
144  QString expressionString = parameterAsString( parameters, QStringLiteral( "FORMULA" ), context );
145  mExpressionContext = createExpressionContext( parameters, context, source.get() );
146  mExpression = QgsExpression( expressionString );
147  mDa.setSourceCrs( source->sourceCrs(), context.transformContext() );
148  mDa.setEllipsoid( context.ellipsoid() );
149 
150  mExpression.setGeomCalculator( &mDa );
151  mExpression.setDistanceUnits( context.distanceUnit() );
152  mExpression.setAreaUnits( context.areaUnit() );
153 
154  if ( mExpression.hasParserError() )
155  throw QgsProcessingException( QObject::tr( "Parser error with formula expression \"%2\": %3" )
156  .arg( expressionString, mExpression.parserErrorString() ) );
157 
158  mExpression.prepare( &mExpressionContext );
159 
160  return true;
161 }
162 
163 QgsFeatureList QgsFieldCalculatorAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &, QgsProcessingFeedback * )
164 {
165  QgsAttributes attributes( mFields.size() );
166  const QStringList fieldNames = mFields.names();
167  for ( const QString &fieldName : fieldNames )
168  {
169  const int attributeIndex = feature.fieldNameIndex( fieldName );
170 
171  if ( attributeIndex >= 0 )
172  attributes[attributeIndex] = feature.attribute( fieldName );
173  }
174 
175  if ( mExpression.isValid() )
176  {
177  mExpressionContext.setFeature( feature );
178  mExpressionContext.lastScope()->setVariable( QStringLiteral( "row_number" ), mRowNumber );
179 
180  const QVariant value = mExpression.evaluate( &mExpressionContext );
181 
182  if ( mExpression.hasEvalError() )
183  {
184  throw QgsProcessingException( QObject::tr( "Evaluation error in expression \"%1\": %2" )
185  .arg( mExpression.expression(), mExpression.evalErrorString() ) );
186  }
187 
188  attributes[mFieldIdx] = value;
189  }
190  else
191  {
192  attributes[mFieldIdx] = QVariant();
193  }
194 
195  QgsFeature f = feature;
196  f.setAttributes( attributes );
197  mRowNumber++;
198  return QgsFeatureList() << f;
199 }
200 
201 bool QgsFieldCalculatorAlgorithm::supportInPlaceEdit( const QgsMapLayer *layer ) const
202 {
203  Q_UNUSED( layer )
204  return false;
205 }
206 
208 
qgsexpressioncontextutils.h
QgsProcessingContext::distanceUnit
QgsUnitTypes::DistanceUnit distanceUnit() const
Returns the distance unit to use for distance calculations.
Definition: qgsprocessingcontext.cpp:141
QgsProcessingFeedback
Base class for providing feedback from a processing algorithm.
Definition: qgsprocessingfeedback.h:38
QgsFields
Container of fields for a vector layer.
Definition: qgsfields.h:45
qgsalgorithmfieldcalculator.h
QgsProcessingFeatureSource::FlagSkipGeometryValidityChecks
@ FlagSkipGeometryValidityChecks
Invalid geometry checks should always be skipped. This flag can be useful for algorithms which always...
Definition: qgsprocessingutils.h:477
field
const QgsField & field
Definition: qgsfield.h:456
QgsField::name
QString name
Definition: qgsfield.h:59
QgsFeature::fieldNameIndex
int fieldNameIndex(const QString &fieldName) const
Utility method to get attribute index from name.
Definition: qgsfeature.cpp:279
QgsProcessing::TypeVector
@ TypeVector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
Definition: qgsprocessing.h:53
QgsProcessingContext
Contains information about the context in which a processing algorithm is executed.
Definition: qgsprocessingcontext.h:44
QgsProcessingContext::ellipsoid
QString ellipsoid() const
Returns the ellipsoid to use for distance and area calculations.
Definition: qgsprocessingcontext.cpp:131
QgsFeatureList
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:583
QgsFeature::attribute
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:264
QgsProcessingContext::transformContext
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
Definition: qgsprocessingcontext.h:149
QgsProcessingParameterNumber::Integer
@ Integer
Integer values.
Definition: qgsprocessingparameters.h:1966
QgsProcessingFeatureSource::Flag
Flag
Flags controlling how QgsProcessingFeatureSource fetches features.
Definition: qgsprocessingutils.h:476
QgsProcessingContext::areaUnit
QgsUnitTypes::AreaUnit areaUnit() const
Returns the area unit to use for area calculations.
Definition: qgsprocessingcontext.cpp:151
QgsMapLayer
Base class for all map layer types.
Definition: qgsmaplayer.h:83
QgsAttributes
A vector of attributes.
Definition: qgsattributes.h:58
QgsFeature
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:56
QgsFeature::setAttributes
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
Definition: qgsfeature.cpp:129
QgsExpression
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:105
QgsProcessingException
Custom exception class for processing related exceptions.
Definition: qgsexception.h:83
QgsField
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:50