QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsalgorithmextractbyexpression.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsalgorithmextractbyexpression.cpp
3  ---------------------
4  begin : April 2017
5  copyright : (C) 2017 by Nyall Dawson
6  email : nyall dot dawson at gmail dot com
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 
19 
21 
22 QString QgsExtractByExpressionAlgorithm::name() const
23 {
24  return QStringLiteral( "extractbyexpression" );
25 }
26 
27 QString QgsExtractByExpressionAlgorithm::displayName() const
28 {
29  return QObject::tr( "Extract by expression" );
30 }
31 
32 QStringList QgsExtractByExpressionAlgorithm::tags() const
33 {
34  return QObject::tr( "extract,filter,expression,field" ).split( ',' );
35 }
36 
37 QString QgsExtractByExpressionAlgorithm::group() const
38 {
39  return QObject::tr( "Vector selection" );
40 }
41 
42 QString QgsExtractByExpressionAlgorithm::groupId() const
43 {
44  return QStringLiteral( "vectorselection" );
45 }
46 
47 void QgsExtractByExpressionAlgorithm::initAlgorithm( const QVariantMap & )
48 {
49  addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ),
50  QList< int >() << QgsProcessing::TypeVector ) );
51  addParameter( new QgsProcessingParameterExpression( QStringLiteral( "EXPRESSION" ), QObject::tr( "Expression" ), QVariant(), QStringLiteral( "INPUT" ) ) );
52 
53  addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Matching features" ) ) );
54  QgsProcessingParameterFeatureSink *failOutput = new QgsProcessingParameterFeatureSink( QStringLiteral( "FAIL_OUTPUT" ), QObject::tr( "Non-matching" ),
55  QgsProcessing::TypeVectorAnyGeometry, QVariant(), true );
56  failOutput->setCreateByDefault( false );
57  addParameter( failOutput );
58 }
59 
60 QString QgsExtractByExpressionAlgorithm::shortHelpString() const
61 {
62  return QObject::tr( "This algorithm creates a new vector layer that only contains matching features from an input layer. "
63  "The criteria for adding features to the resulting layer is based on a QGIS expression.\n\n"
64  "For help with QGIS expression functions, see the inbuilt help for specific functions "
65  "which is available in the expression builder." );
66 }
67 
68 QgsExtractByExpressionAlgorithm *QgsExtractByExpressionAlgorithm::createInstance() const
69 {
70  return new QgsExtractByExpressionAlgorithm();
71 }
72 
73 QVariantMap QgsExtractByExpressionAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
74 {
75  std::unique_ptr< QgsProcessingFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
76  if ( !source )
77  throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
78 
79  const QString expressionString = parameterAsExpression( parameters, QStringLiteral( "EXPRESSION" ), context );
80 
81  QString matchingSinkId;
82  std::unique_ptr< QgsFeatureSink > matchingSink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, matchingSinkId, source->fields(),
83  source->wkbType(), source->sourceCrs() ) );
84  if ( !matchingSink )
85  throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
86 
87  QString nonMatchingSinkId;
88  std::unique_ptr< QgsFeatureSink > nonMatchingSink( parameterAsSink( parameters, QStringLiteral( "FAIL_OUTPUT" ), context, nonMatchingSinkId, source->fields(),
89  source->wkbType(), source->sourceCrs() ) );
90 
91  QgsExpression expression( expressionString );
92  if ( expression.hasParserError() )
93  {
94  throw QgsProcessingException( expression.parserErrorString() );
95  }
96 
97  QgsExpressionContext expressionContext = createExpressionContext( parameters, context, source.get() );
98 
99  const long count = source->featureCount();
100 
101  const double step = count > 0 ? 100.0 / count : 1;
102  int current = 0;
103 
104  if ( !nonMatchingSink )
105  {
106  // not saving failing features - so only fetch good features
107  QgsFeatureRequest req;
108  req.setFilterExpression( expressionString );
109  req.setExpressionContext( expressionContext );
110 
112  QgsFeature f;
113  while ( it.nextFeature( f ) )
114  {
115  if ( feedback->isCanceled() )
116  {
117  break;
118  }
119 
120  if ( !matchingSink->addFeature( f, QgsFeatureSink::FastInsert ) )
121  throw QgsProcessingException( writeFeatureError( matchingSink.get(), parameters, QStringLiteral( "OUTPUT" ) ) );
122 
123  feedback->setProgress( current * step );
124  current++;
125  }
126  }
127  else
128  {
129  // saving non-matching features, so we need EVERYTHING
130  expressionContext.setFields( source->fields() );
131  expression.prepare( &expressionContext );
132 
133  QgsFeatureIterator it = source->getFeatures();
134  QgsFeature f;
135  while ( it.nextFeature( f ) )
136  {
137  if ( feedback->isCanceled() )
138  {
139  break;
140  }
141 
142  expressionContext.setFeature( f );
143  if ( expression.evaluate( &expressionContext ).toBool() )
144  {
145  if ( !matchingSink->addFeature( f, QgsFeatureSink::FastInsert ) )
146  throw QgsProcessingException( writeFeatureError( matchingSink.get(), parameters, QStringLiteral( "OUTPUT" ) ) );
147  }
148  else
149  {
150  if ( !nonMatchingSink->addFeature( f, QgsFeatureSink::FastInsert ) )
151  throw QgsProcessingException( writeFeatureError( nonMatchingSink.get(), parameters, QStringLiteral( "FAIL_OUTPUT" ) ) );
152  }
153 
154  feedback->setProgress( current * step );
155  current++;
156  }
157  }
158 
159 
160  QVariantMap outputs;
161  outputs.insert( QStringLiteral( "OUTPUT" ), matchingSinkId );
162  if ( nonMatchingSink )
163  outputs.insert( QStringLiteral( "FAIL_OUTPUT" ), nonMatchingSinkId );
164  return outputs;
165 }
166 
168 
QgsExpressionContext
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Definition: qgsexpressioncontext.h:406
QgsFeedback::setProgress
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:76
QgsProcessingFeedback
Base class for providing feedback from a processing algorithm.
Definition: qgsprocessingfeedback.h:37
QgsProcessingDestinationParameter::setCreateByDefault
void setCreateByDefault(bool createByDefault)
Sets whether the destination should be created by default.
Definition: qgsprocessingparameters.cpp:6803
QgsFeedback::isCanceled
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:67
QgsProcessingFeatureSource::FlagSkipGeometryValidityChecks
@ FlagSkipGeometryValidityChecks
Invalid geometry checks should always be skipped. This flag can be useful for algorithms which always...
Definition: qgsprocessingutils.h:584
QgsProcessingParameterFeatureSource
An input feature source (such as vector layers) parameter for processing algorithms.
Definition: qgsprocessingparameters.h:3057
QgsExpressionContext::setFields
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the context.
Definition: qgsexpressioncontext.cpp:587
qgsalgorithmextractbyexpression.h
QgsFeatureRequest::setExpressionContext
QgsFeatureRequest & setExpressionContext(const QgsExpressionContext &context)
Sets the expression context used to evaluate filter expressions.
Definition: qgsfeaturerequest.cpp:187
QgsFeatureRequest::setFilterExpression
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
Definition: qgsfeaturerequest.cpp:167
QgsProcessingParameterFeatureSink
A feature sink output for processing algorithms.
Definition: qgsprocessingparameters.h:3219
QgsFeatureRequest
This class wraps a request for features to a vector layer (or directly its vector data provider).
Definition: qgsfeaturerequest.h:83
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:54
QgsProcessingContext
Contains information about the context in which a processing algorithm is executed.
Definition: qgsprocessingcontext.h:46
QgsProcessing::TypeVectorAnyGeometry
@ TypeVectorAnyGeometry
Any vector layer with geometry.
Definition: qgsprocessing.h:48
QgsFeatureIterator::nextFeature
bool nextFeature(QgsFeature &f)
Definition: qgsfeatureiterator.h:399
QgsProcessingParameterExpression
An expression parameter for processing algorithms.
Definition: qgsprocessingparameters.h:2739
QgsFeature
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:55
QgsExpression
Class for parsing and evaluation of expressions (formerly called "search strings")....
Definition: qgsexpression.h:102
QgsFeatureIterator
Wrapper for iterator of features from vector data provider or vector layer.
Definition: qgsfeatureiterator.h:289
QgsProcessingException
Custom exception class for processing related exceptions.
Definition: qgsexception.h:82
QgsFeatureSink::FastInsert
@ FastInsert
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
Definition: qgsfeaturesink.h:70
QgsExpressionContext::setFeature
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
Definition: qgsexpressioncontext.cpp:525