QGIS API Documentation 3.99.0-Master (2fe06baccd8)
Loading...
Searching...
No Matches
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
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
20
22#include "qgsvariantutils.h"
23
25
26QString QgsFieldCalculatorAlgorithm::name() const
27{
28 return QStringLiteral( "fieldcalculator" );
29}
30
31QString QgsFieldCalculatorAlgorithm::displayName() const
32{
33 return QObject::tr( "Field calculator" );
34}
35
36QStringList QgsFieldCalculatorAlgorithm::tags() const
37{
38 return QObject::tr( "field,calculator,vector" ).split( ',' );
39}
40
41QString QgsFieldCalculatorAlgorithm::group() const
42{
43 return QObject::tr( "Vector table" );
44}
45
46QString QgsFieldCalculatorAlgorithm::groupId() const
47{
48 return QStringLiteral( "vectortable" );
49}
50
51QString QgsFieldCalculatorAlgorithm::outputName() const
52{
53 return QObject::tr( "Calculated" );
54}
55
56QList<int> QgsFieldCalculatorAlgorithm::inputLayerTypes() const
57{
58 return QList<int>() << static_cast<int>( Qgis::ProcessingSourceType::Vector );
59}
60
61Qgis::ProcessingAlgorithmDocumentationFlags QgsFieldCalculatorAlgorithm::documentationFlags() const
62{
64}
65
66Qgis::ProcessingFeatureSourceFlags QgsFieldCalculatorAlgorithm::sourceFlags() const
67{
69}
70
71void QgsFieldCalculatorAlgorithm::initParameters( const QVariantMap &configuration )
72{
73 Q_UNUSED( configuration )
74
75 QStringList fieldTypes;
76 QVariantList icons;
77 fieldTypes.reserve( 11 );
78 icons.reserve( 11 );
79 for ( const auto &type :
80 std::vector<std::pair<QMetaType::Type, QMetaType::Type>> {
81 { QMetaType::Type::Double, QMetaType::Type::UnknownType },
82 { QMetaType::Type::Int, QMetaType::Type::UnknownType },
83 { QMetaType::Type::QString, QMetaType::Type::UnknownType },
84 { QMetaType::Type::QDate, QMetaType::Type::UnknownType },
85 { QMetaType::Type::QTime, QMetaType::Type::UnknownType },
86 { QMetaType::Type::QDateTime, QMetaType::Type::UnknownType },
87 { QMetaType::Type::Bool, QMetaType::Type::UnknownType },
88 { QMetaType::Type::QByteArray, QMetaType::Type::UnknownType },
89 { QMetaType::Type::QStringList, QMetaType::Type::UnknownType },
90 { QMetaType::Type::QVariantList, QMetaType::Type::Int },
91 { QMetaType::Type::QVariantList, QMetaType::Type::Double }
92 } )
93 {
94 fieldTypes << QgsVariantUtils::typeToDisplayString( type.first, type.second );
95 icons << QgsFields::iconForFieldType( type.first, type.second );
96 }
97
98 auto fieldName = std::make_unique<QgsProcessingParameterString>( QStringLiteral( "FIELD_NAME" ), QObject::tr( "Field name" ), QVariant(), false );
99 auto fieldType = std::make_unique<QgsProcessingParameterEnum>( QStringLiteral( "FIELD_TYPE" ), QObject::tr( "Result field type" ), fieldTypes, false, 0 );
100 fieldType->setMetadata(
101 { QVariantMap( { { QStringLiteral( "widget_wrapper" ), QVariantMap( { { QStringLiteral( "icons" ), icons } } ) } } )
102 }
103 );
104
105 auto fieldLength = std::make_unique<QgsProcessingParameterNumber>( QStringLiteral( "FIELD_LENGTH" ), QObject::tr( "Result field length" ), Qgis::ProcessingNumberParameterType::Integer, QVariant( 0 ), false, 0 );
106 auto fieldPrecision = std::make_unique<QgsProcessingParameterNumber>( QStringLiteral( "FIELD_PRECISION" ), QObject::tr( "Result field precision" ), Qgis::ProcessingNumberParameterType::Integer, QVariant( 0 ), false, 0 );
107 auto expression = std::make_unique<QgsProcessingParameterExpression>( QStringLiteral( "FORMULA" ), QObject::tr( "Formula" ), QVariant(), QStringLiteral( "INPUT" ), false );
108
109 expression->setMetadata( QVariantMap( { { "inlineEditor", true } } ) );
110
111 addParameter( fieldName.release() );
112 addParameter( fieldType.release() );
113 addParameter( fieldLength.release() );
114 addParameter( fieldPrecision.release() );
115 addParameter( expression.release() );
116}
117
118QgsFields QgsFieldCalculatorAlgorithm::outputFields( const QgsFields & ) const
119{
120 return mFields;
121}
122
123QString QgsFieldCalculatorAlgorithm::shortHelpString() const
124{
125 return QObject::tr( "This algorithm computes a new vector layer with the same features of the input layer, "
126 "but either overwriting an existing attribute or adding an additional attribute. The values of this field "
127 "are computed from each feature using an expression, based on the properties and attributes of the feature. "
128 "Note that if \"Field name\" is an existing field in the layer then all the rest of the field settings are ignored." );
129}
130
131QString QgsFieldCalculatorAlgorithm::shortDescription() const
132{
133 return QObject::tr( "Computes a new vector layer with the same features of the input layer, "
134 "but either overwriting an existing attribute or adding an additional attribute." );
135}
136
137QgsFieldCalculatorAlgorithm *QgsFieldCalculatorAlgorithm::createInstance() const
138{
139 return new QgsFieldCalculatorAlgorithm();
140}
141
142
143bool QgsFieldCalculatorAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
144{
145 std::unique_ptr<QgsProcessingFeatureSource> source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
146
147 if ( !source )
148 throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
149
150 // prepare fields
151 const int fieldTypeIdx = parameterAsInt( parameters, QStringLiteral( "FIELD_TYPE" ), context );
152 const int fieldLength = parameterAsInt( parameters, QStringLiteral( "FIELD_LENGTH" ), context );
153 const int fieldPrecision = parameterAsInt( parameters, QStringLiteral( "FIELD_PRECISION" ), context );
154 const QString fieldName = parameterAsString( parameters, QStringLiteral( "FIELD_NAME" ), context );
155
156 QMetaType::Type fieldType = QMetaType::Type::QString;
157 QMetaType::Type fieldSubType = QMetaType::Type::UnknownType;
158 switch ( fieldTypeIdx )
159 {
160 case 0: // Float
161 fieldType = QMetaType::Type::Double;
162 break;
163 case 1: // Integer
164 fieldType = QMetaType::Type::Int;
165 break;
166 case 2: // String
167 fieldType = QMetaType::Type::QString;
168 break;
169 case 3: // Date
170 fieldType = QMetaType::Type::QDate;
171 break;
172 case 4: // Time
173 fieldType = QMetaType::Type::QTime;
174 break;
175 case 5: // DateTime
176 fieldType = QMetaType::Type::QDateTime;
177 break;
178 case 6: // Boolean
179 fieldType = QMetaType::Type::Bool;
180 break;
181 case 7: // Binary
182 fieldType = QMetaType::Type::QByteArray;
183 break;
184 case 8: // StringList
185 fieldType = QMetaType::Type::QStringList;
186 fieldSubType = QMetaType::Type::QString;
187 break;
188 case 9: // IntegerList
189 fieldType = QMetaType::Type::QVariantList;
190 fieldSubType = QMetaType::Type::Int;
191 break;
192 case 10: // DoubleList
193 fieldType = QMetaType::Type::QVariantList;
194 fieldSubType = QMetaType::Type::Double;
195 break;
196 }
197
198 if ( fieldName.isEmpty() )
199 throw QgsProcessingException( QObject::tr( "Field name must not be an empty string" ) );
200
201 const QgsField field(
202 fieldName,
203 fieldType,
204 QString(),
205 fieldLength,
206 fieldPrecision,
207 QString(),
208 fieldSubType
209 );
210
211 mFields = source->fields();
212
213 const int fieldIdx = mFields.indexFromName( field.name() );
214
215 if ( fieldIdx < 0 )
216 {
217 mFields.append( field );
218 }
219 else
220 {
221 feedback->pushWarning( QObject::tr( "Field name %1 already exists and will be replaced" ).arg( field.name() ) );
222 }
223
224 mFieldIdx = mFields.lookupField( field.name() );
225
226 // prepare expression
227 const QString expressionString = parameterAsString( parameters, QStringLiteral( "FORMULA" ), context );
228 mExpressionContext = createExpressionContext( parameters, context, source.get() );
229 mExpression = QgsExpression( expressionString );
230 mDa.setSourceCrs( source->sourceCrs(), context.transformContext() );
231 mDa.setEllipsoid( context.ellipsoid() );
232
233 mExpression.setGeomCalculator( &mDa );
234 mExpression.setDistanceUnits( context.distanceUnit() );
235 mExpression.setAreaUnits( context.areaUnit() );
236
237 if ( mExpression.hasParserError() )
238 throw QgsProcessingException( QObject::tr( "Parser error with formula expression \"%2\": %3" )
239 .arg( expressionString, mExpression.parserErrorString() ) );
240
241 mExpression.prepare( &mExpressionContext );
242
243 return true;
244}
245
246QgsFeatureList QgsFieldCalculatorAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &, QgsProcessingFeedback * )
247{
248 QgsAttributes attributes( mFields.size() );
249 const QStringList fieldNames = mFields.names();
250 for ( const QString &fieldName : fieldNames )
251 {
252 const int attributeIndex = feature.fieldNameIndex( fieldName );
253
254 if ( attributeIndex >= 0 )
255 attributes[attributeIndex] = feature.attribute( fieldName );
256 }
257
258 if ( mExpression.isValid() )
259 {
260 mExpressionContext.setFeature( feature );
261 mExpressionContext.lastScope()->setVariable( QStringLiteral( "row_number" ), mRowNumber );
262
263 const QVariant value = mExpression.evaluate( &mExpressionContext );
264
265 if ( mExpression.hasEvalError() )
266 {
267 throw QgsProcessingException( QObject::tr( "Evaluation error in expression \"%1\": %2" )
268 .arg( mExpression.expression(), mExpression.evalErrorString() ) );
269 }
270
271 attributes[mFieldIdx] = value;
272 }
273 else
274 {
275 attributes[mFieldIdx] = QVariant();
276 }
277
278 QgsFeature f = feature;
279 f.setAttributes( attributes );
280 mRowNumber++;
281 return QgsFeatureList() << f;
282}
283
284bool QgsFieldCalculatorAlgorithm::supportInPlaceEdit( const QgsMapLayer *layer ) const
285{
286 Q_UNUSED( layer )
287 return false;
288}
289
@ Vector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
Definition qgis.h:3539
@ RespectsEllipsoid
Algorithm respects the context's ellipsoid settings, and uses ellipsoidal based measurements.
Definition qgis.h:3621
QFlags< ProcessingAlgorithmDocumentationFlag > ProcessingAlgorithmDocumentationFlags
Flags describing algorithm behavior for documentation purposes.
Definition qgis.h:3630
@ SkipGeometryValidityChecks
Invalid geometry checks should always be skipped. This flag can be useful for algorithms which always...
Definition qgis.h:3711
QFlags< ProcessingFeatureSourceFlag > ProcessingFeatureSourceFlags
Flags which control how QgsProcessingFeatureSource fetches features.
Definition qgis.h:3722
A vector of attributes.
Handles 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:58
int fieldNameIndex(const QString &fieldName) const
Utility method to get attribute index from name.
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
Q_INVOKABLE QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:54
Container of fields for a vector layer.
Definition qgsfields.h:46
static QIcon iconForFieldType(QMetaType::Type type, QMetaType::Type subType=QMetaType::Type::UnknownType, const QString &typeString=QString())
Returns an icon corresponding to a field type.
Base class for all map layer types.
Definition qgsmaplayer.h:80
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.
virtual void pushWarning(const QString &warning)
Pushes a warning informational message from the algorithm.
static QString typeToDisplayString(QMetaType::Type type, QMetaType::Type subType=QMetaType::Type::UnknownType)
Returns a user-friendly translated string representing a QVariant type.
QList< QgsFeature > QgsFeatureList