QGIS API Documentation  3.0.2-Girona (307d082)
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  addParameter( new QgsProcessingParameterExpression( QStringLiteral( "EXPRESSION" ), QObject::tr( "Expression" ), QVariant(), QStringLiteral( "INPUT" ) ) );
51 
52  addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Matching features" ) ) );
53  QgsProcessingParameterFeatureSink *failOutput = new QgsProcessingParameterFeatureSink( QStringLiteral( "FAIL_OUTPUT" ), QObject::tr( "Non-matching" ),
54  QgsProcessing::TypeVectorAnyGeometry, QVariant(), true );
55  failOutput->setCreateByDefault( false );
56  addParameter( failOutput );
57 }
58 
59 QString QgsExtractByExpressionAlgorithm::shortHelpString() const
60 {
61  return QObject::tr( "This algorithm creates a new vector layer that only contains matching features from an input layer. "
62  "The criteria for adding features to the resulting layer is based on a QGIS expression.\n\n"
63  "For more information about expressions see the <a href =\"{qgisdocs}/user_manual/working_with_vector/expression.html\">user manual</a>" );
64 }
65 
66 QgsExtractByExpressionAlgorithm *QgsExtractByExpressionAlgorithm::createInstance() const
67 {
68  return new QgsExtractByExpressionAlgorithm();
69 }
70 
71 QVariantMap QgsExtractByExpressionAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
72 {
73  std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
74  if ( !source )
75  throw QgsProcessingException( QObject::tr( "Could not load source layer for INPUT" ) );
76 
77  QString expressionString = parameterAsExpression( parameters, QStringLiteral( "EXPRESSION" ), context );
78 
79  QString matchingSinkId;
80  std::unique_ptr< QgsFeatureSink > matchingSink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, matchingSinkId, source->fields(),
81  source->wkbType(), source->sourceCrs() ) );
82  if ( !matchingSink )
83  throw QgsProcessingException( QObject::tr( "Could not create destination layer for OUTPUT" ) );;
84 
85  QString nonMatchingSinkId;
86  std::unique_ptr< QgsFeatureSink > nonMatchingSink( parameterAsSink( parameters, QStringLiteral( "FAIL_OUTPUT" ), context, nonMatchingSinkId, source->fields(),
87  source->wkbType(), source->sourceCrs() ) );
88 
89  QgsExpression expression( expressionString );
90  if ( expression.hasParserError() )
91  {
92  throw QgsProcessingException( expression.parserErrorString() );
93  }
94 
95  QgsExpressionContext expressionContext = createExpressionContext( parameters, context, dynamic_cast< QgsProcessingFeatureSource * >( source.get() ) );
96 
97  long count = source->featureCount();
98 
99  double step = count > 0 ? 100.0 / count : 1;
100  int current = 0;
101 
102  if ( !nonMatchingSink )
103  {
104  // not saving failing features - so only fetch good features
105  QgsFeatureRequest req;
106  req.setFilterExpression( expressionString );
107  req.setExpressionContext( expressionContext );
108 
109  QgsFeatureIterator it = source->getFeatures( req );
110  QgsFeature f;
111  while ( it.nextFeature( f ) )
112  {
113  if ( feedback->isCanceled() )
114  {
115  break;
116  }
117 
118  matchingSink->addFeature( f, QgsFeatureSink::FastInsert );
119 
120  feedback->setProgress( current * step );
121  current++;
122  }
123  }
124  else
125  {
126  // saving non-matching features, so we need EVERYTHING
127  expressionContext.setFields( source->fields() );
128  expression.prepare( &expressionContext );
129 
130  QgsFeatureIterator it = source->getFeatures();
131  QgsFeature f;
132  while ( it.nextFeature( f ) )
133  {
134  if ( feedback->isCanceled() )
135  {
136  break;
137  }
138 
139  expressionContext.setFeature( f );
140  if ( expression.evaluate( &expressionContext ).toBool() )
141  {
142  matchingSink->addFeature( f, QgsFeatureSink::FastInsert );
143  }
144  else
145  {
146  nonMatchingSink->addFeature( f, QgsFeatureSink::FastInsert );
147  }
148 
149  feedback->setProgress( current * step );
150  current++;
151  }
152  }
153 
154 
155  QVariantMap outputs;
156  outputs.insert( QStringLiteral( "OUTPUT" ), matchingSinkId );
157  if ( nonMatchingSink )
158  outputs.insert( QStringLiteral( "FAIL_OUTPUT" ), nonMatchingSinkId );
159  return outputs;
160 }
161 
163 
Wrapper for iterator of features from vector data provider or vector layer.
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
Base class for providing feedback from a processing algorithm.
An expression parameter for processing algorithms.
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:63
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:62
A feature sink output for processing algorithms.
QgsFeatureRequest & setExpressionContext(const QgsExpressionContext &context)
Sets the expression context used to evaluate filter expressions.
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
This class wraps a request for features to a vector layer (or directly its vector data provider)...
Custom exception class for processing related exceptions.
Definition: qgsexception.h:82
void setCreateByDefault(bool createByDefault)
Sets whether the destination should be created by default.
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
An input feature source (such as vector layers) parameter for processing algorithms.
bool nextFeature(QgsFeature &f)
Contains information about the context in which a processing algorithm is executed.
Any vector layer with geometry.
Definition: qgsprocessing.h:48