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