LCOV - code coverage report
Current view: top level - analysis/processing - qgsalgorithmfieldcalculator.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 0 102 0.0 %
Date: 2021-04-10 08:29:14 Functions: 0 0 -
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :                          qgsalgorithmfieldcalculator.h
       3                 :            :                          ----------------------
       4                 :            :     begin                : September 2020
       5                 :            :     copyright            : (C) 2020 by Ivan Ivanov
       6                 :            :     email                : ivan@opengis.ch
       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                 :            : 
      19                 :            : #include "qgsalgorithmfieldcalculator.h"
      20                 :            : #include "qgsexpressioncontextutils.h"
      21                 :            : 
      22                 :            : ///@cond PRIVATE
      23                 :            : 
      24                 :          0 : QString QgsFieldCalculatorAlgorithm::name() const
      25                 :            : {
      26                 :          0 :   return QStringLiteral( "fieldcalculator" );
      27                 :            : }
      28                 :            : 
      29                 :          0 : QString QgsFieldCalculatorAlgorithm::displayName() const
      30                 :            : {
      31                 :          0 :   return QObject::tr( "Field calculator" );
      32                 :            : }
      33                 :            : 
      34                 :          0 : QStringList QgsFieldCalculatorAlgorithm::tags() const
      35                 :            : {
      36                 :          0 :   return QObject::tr( "field,calculator,vector" ).split( ',' );
      37                 :          0 : }
      38                 :            : 
      39                 :          0 : QString QgsFieldCalculatorAlgorithm::group() const
      40                 :            : {
      41                 :          0 :   return QObject::tr( "Vector table" );
      42                 :            : }
      43                 :            : 
      44                 :          0 : QString QgsFieldCalculatorAlgorithm::groupId() const
      45                 :            : {
      46                 :          0 :   return QStringLiteral( "vectortable" );
      47                 :            : }
      48                 :            : 
      49                 :          0 : QString QgsFieldCalculatorAlgorithm::outputName() const
      50                 :            : {
      51                 :          0 :   return QObject::tr( "Calculated" );
      52                 :            : }
      53                 :            : 
      54                 :          0 : QList<int> QgsFieldCalculatorAlgorithm::inputLayerTypes() const
      55                 :            : {
      56                 :          0 :   return QList<int>() << QgsProcessing::TypeVector;
      57                 :          0 : }
      58                 :            : 
      59                 :          0 : QgsProcessingFeatureSource::Flag QgsFieldCalculatorAlgorithm::sourceFlags() const
      60                 :            : {
      61                 :          0 :   return QgsProcessingFeatureSource::FlagSkipGeometryValidityChecks;
      62                 :            : }
      63                 :            : 
      64                 :          0 : void QgsFieldCalculatorAlgorithm::initParameters( const QVariantMap &configuration )
      65                 :            : {
      66                 :          0 :   Q_UNUSED( configuration );
      67                 :            : 
      68                 :          0 :   QStringList fieldTypes = QStringList( {QObject::tr( "Float" ), QObject::tr( "Integer" ), QObject::tr( "String" ), QObject::tr( "Date" ) } );
      69                 :            : 
      70                 :          0 :   std::unique_ptr< QgsProcessingParameterString > fieldName = std::make_unique< QgsProcessingParameterString > ( QStringLiteral( "FIELD_NAME" ), QObject::tr( "Field name" ), QVariant(), false );
      71                 :          0 :   std::unique_ptr< QgsProcessingParameterEnum > fieldType = std::make_unique< QgsProcessingParameterEnum > ( QStringLiteral( "FIELD_TYPE" ), QObject::tr( "Result field type" ), fieldTypes, false, 0 );
      72                 :          0 :   std::unique_ptr< QgsProcessingParameterNumber > fieldLength = std::make_unique< QgsProcessingParameterNumber > ( QStringLiteral( "FIELD_LENGTH" ), QObject::tr( "Result field length" ), QgsProcessingParameterNumber::Integer, QVariant( 0 ), false, 0 );
      73                 :          0 :   std::unique_ptr< QgsProcessingParameterNumber > fieldPrecision = std::make_unique< QgsProcessingParameterNumber > ( QStringLiteral( "FIELD_PRECISION" ), QObject::tr( "Result field precision" ), QgsProcessingParameterNumber::Integer, QVariant( 0 ), false, 0 );
      74                 :          0 :   std::unique_ptr< QgsProcessingParameterExpression > expression = std::make_unique< QgsProcessingParameterExpression> ( QStringLiteral( "FORMULA" ), QObject::tr( "Formula" ), QVariant(), QStringLiteral( "INPUT" ), false );
      75                 :            : 
      76                 :          0 :   expression->setMetadata( QVariantMap( {{"inlineEditor", true}} ) );
      77                 :            : 
      78                 :          0 :   addParameter( fieldName.release() );
      79                 :          0 :   addParameter( fieldType.release() );
      80                 :          0 :   addParameter( fieldLength.release() );
      81                 :          0 :   addParameter( fieldPrecision.release() );
      82                 :          0 :   addParameter( expression.release() );
      83                 :          0 : }
      84                 :            : 
      85                 :          0 : QgsFields QgsFieldCalculatorAlgorithm::outputFields( const QgsFields & ) const
      86                 :            : {
      87                 :          0 :   return mFields;
      88                 :            : }
      89                 :            : 
      90                 :          0 : QString QgsFieldCalculatorAlgorithm::shortHelpString() const
      91                 :            : {
      92                 :          0 :   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                 :          0 : QgsFieldCalculatorAlgorithm *QgsFieldCalculatorAlgorithm::createInstance() const
      99                 :            : {
     100                 :          0 :   return new QgsFieldCalculatorAlgorithm();
     101                 :          0 : }
     102                 :            : 
     103                 :            : 
     104                 :          0 : bool QgsFieldCalculatorAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
     105                 :            : {
     106                 :          0 :   std::unique_ptr< QgsProcessingFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
     107                 :            : 
     108                 :          0 :   if ( !source )
     109                 :          0 :     throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
     110                 :            : 
     111                 :          0 :   QList<QVariant::Type> fieldTypes( {QVariant::Double, QVariant::Int, QVariant::String, QVariant::Date} );
     112                 :            : 
     113                 :            :   // prepare fields
     114                 :          0 :   const int fieldTypeIdx = parameterAsInt( parameters, QStringLiteral( "FIELD_TYPE" ), context );
     115                 :          0 :   const int fieldLength = parameterAsInt( parameters, QStringLiteral( "FIELD_LENGTH" ), context );
     116                 :          0 :   const int fieldPrecision = parameterAsInt( parameters, QStringLiteral( "FIELD_PRECISION" ), context );
     117                 :          0 :   const QString fieldName = parameterAsString( parameters, QStringLiteral( "FIELD_NAME" ), context );
     118                 :            : 
     119                 :          0 :   QVariant::Type fieldType = fieldTypes[fieldTypeIdx];
     120                 :            : 
     121                 :          0 :   if ( fieldName.isEmpty() )
     122                 :          0 :     throw QgsProcessingException( QObject::tr( "Field name must not be an empty string" ) );
     123                 :            : 
     124                 :          0 :   const QgsField field(
     125                 :            :     fieldName,
     126                 :          0 :     fieldType,
     127                 :          0 :     QString(),
     128                 :          0 :     fieldLength,
     129                 :          0 :     fieldPrecision
     130                 :            :   );
     131                 :            : 
     132                 :          0 :   mFields = source->fields();
     133                 :            : 
     134                 :          0 :   int fieldIdx = mFields.indexFromName( field.name() );
     135                 :            : 
     136                 :          0 :   if ( fieldIdx < 0 )
     137                 :            :   {
     138                 :          0 :     mFields.append( field );
     139                 :          0 :   }
     140                 :            :   else
     141                 :            :   {
     142                 :          0 :     feedback->pushWarning( QObject::tr( "Field name %1 already exists and will be replaced" ).arg( field.name() ) );
     143                 :            :   }
     144                 :            : 
     145                 :          0 :   QString dest;
     146                 :            : 
     147                 :          0 :   mFieldIdx = mFields.lookupField( field.name() );
     148                 :            : 
     149                 :            :   // prepare expression
     150                 :          0 :   QString expressionString = parameterAsString( parameters, QStringLiteral( "FORMULA" ), context );
     151                 :          0 :   mExpressionContext = createExpressionContext( parameters, context, source.get() );
     152                 :          0 :   mExpression = QgsExpression( expressionString );
     153                 :          0 :   mDa.setSourceCrs( source->sourceCrs(), context.transformContext() );
     154                 :          0 :   mDa.setEllipsoid( context.ellipsoid() );
     155                 :            : 
     156                 :          0 :   mExpression.setGeomCalculator( &mDa );
     157                 :          0 :   mExpression.setDistanceUnits( context.distanceUnit() );
     158                 :          0 :   mExpression.setAreaUnits( context.areaUnit() );
     159                 :            : 
     160                 :          0 :   if ( mExpression.hasParserError() )
     161                 :          0 :     throw QgsProcessingException( QObject::tr( "Parser error with formula expression \"%2\": %3" )
     162                 :          0 :                                   .arg( expressionString, mExpression.parserErrorString() ) );
     163                 :            : 
     164                 :          0 :   mExpression.prepare( &mExpressionContext );
     165                 :            : 
     166                 :            :   return true;
     167                 :          0 : }
     168                 :            : 
     169                 :          0 : QgsFeatureList QgsFieldCalculatorAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &, QgsProcessingFeedback * )
     170                 :            : {
     171                 :          0 :   QgsAttributes attributes( mFields.size() );
     172                 :          0 :   const QStringList fieldNames = mFields.names();
     173                 :          0 :   for ( const QString &fieldName : fieldNames )
     174                 :            :   {
     175                 :          0 :     const int attributeIndex = feature.fieldNameIndex( fieldName );
     176                 :            : 
     177                 :          0 :     if ( attributeIndex >= 0 )
     178                 :          0 :       attributes[attributeIndex] = feature.attribute( fieldName );
     179                 :            :   }
     180                 :            : 
     181                 :          0 :   if ( mExpression.isValid() )
     182                 :            :   {
     183                 :          0 :     mExpressionContext.setFeature( feature );
     184                 :          0 :     mExpressionContext.lastScope()->setVariable( QStringLiteral( "row_number" ), mRowNumber );
     185                 :            : 
     186                 :          0 :     const QVariant value = mExpression.evaluate( &mExpressionContext );
     187                 :            : 
     188                 :          0 :     if ( mExpression.hasEvalError() )
     189                 :            :     {
     190                 :          0 :       throw QgsProcessingException( QObject::tr( "Evaluation error in expression \"%1\": %2" )
     191                 :          0 :                                     .arg( mExpression.expression(), mExpression.evalErrorString() ) );
     192                 :            :     }
     193                 :            : 
     194                 :          0 :     attributes[mFieldIdx] = value;
     195                 :          0 :   }
     196                 :            :   else
     197                 :            :   {
     198                 :          0 :     attributes[mFieldIdx] = QVariant();
     199                 :            :   }
     200                 :            : 
     201                 :          0 :   QgsFeature f = feature;
     202                 :          0 :   f.setAttributes( attributes );
     203                 :          0 :   mRowNumber++;
     204                 :          0 :   return QgsFeatureList() << f;
     205                 :          0 : }
     206                 :            : 
     207                 :          0 : bool QgsFieldCalculatorAlgorithm::supportInPlaceEdit( const QgsMapLayer *layer ) const
     208                 :            : {
     209                 :            :   Q_UNUSED( layer )
     210                 :          0 :   return false;
     211                 :            : }
     212                 :            : 
     213                 :            : ///@endcond

Generated by: LCOV version 1.14