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