QGIS API Documentation  3.6.0-Noosa (5873452)
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 more information about expressions see the <a href =\"{qgisdocs}/user_manual/working_with_vector/expression.html\">user manual</a>" );
65 }
66 
67 QgsExtractByExpressionAlgorithm *QgsExtractByExpressionAlgorithm::createInstance() const
68 {
69  return new QgsExtractByExpressionAlgorithm();
70 }
71 
72 QVariantMap QgsExtractByExpressionAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
73 {
74  std::unique_ptr< QgsProcessingFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
75  if ( !source )
76  throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
77 
78  QString expressionString = parameterAsExpression( parameters, QStringLiteral( "EXPRESSION" ), context );
79 
80  QString matchingSinkId;
81  std::unique_ptr< QgsFeatureSink > matchingSink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, matchingSinkId, source->fields(),
82  source->wkbType(), source->sourceCrs() ) );
83  if ( !matchingSink )
84  throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
85 
86  QString nonMatchingSinkId;
87  std::unique_ptr< QgsFeatureSink > nonMatchingSink( parameterAsSink( parameters, QStringLiteral( "FAIL_OUTPUT" ), context, nonMatchingSinkId, source->fields(),
88  source->wkbType(), source->sourceCrs() ) );
89 
90  QgsExpression expression( expressionString );
91  if ( expression.hasParserError() )
92  {
93  throw QgsProcessingException( expression.parserErrorString() );
94  }
95 
96  QgsExpressionContext expressionContext = createExpressionContext( parameters, context, source.get() );
97 
98  long count = source->featureCount();
99 
100  double step = count > 0 ? 100.0 / count : 1;
101  int current = 0;
102 
103  if ( !nonMatchingSink )
104  {
105  // not saving failing features - so only fetch good features
106  QgsFeatureRequest req;
107  req.setFilterExpression( expressionString );
108  req.setExpressionContext( expressionContext );
109 
111  QgsFeature f;
112  while ( it.nextFeature( f ) )
113  {
114  if ( feedback->isCanceled() )
115  {
116  break;
117  }
118 
119  matchingSink->addFeature( f, QgsFeatureSink::FastInsert );
120 
121  feedback->setProgress( current * step );
122  current++;
123  }
124  }
125  else
126  {
127  // saving non-matching features, so we need EVERYTHING
128  expressionContext.setFields( source->fields() );
129  expression.prepare( &expressionContext );
130 
131  QgsFeatureIterator it = source->getFeatures();
132  QgsFeature f;
133  while ( it.nextFeature( f ) )
134  {
135  if ( feedback->isCanceled() )
136  {
137  break;
138  }
139 
140  expressionContext.setFeature( f );
141  if ( expression.evaluate( &expressionContext ).toBool() )
142  {
143  matchingSink->addFeature( f, QgsFeatureSink::FastInsert );
144  }
145  else
146  {
147  nonMatchingSink->addFeature( f, QgsFeatureSink::FastInsert );
148  }
149 
150  feedback->setProgress( current * step );
151  current++;
152  }
153  }
154 
155 
156  QVariantMap outputs;
157  outputs.insert( QStringLiteral( "OUTPUT" ), matchingSinkId );
158  if ( nonMatchingSink )
159  outputs.insert( QStringLiteral( "FAIL_OUTPUT" ), nonMatchingSinkId );
160  return outputs;
161 }
162 
164 
Class for parsing and evaluation of expressions (formerly called "search strings").
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.
Invalid geometry checks should always be skipped. This flag can be useful for algorithms which always...
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:55
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.
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
Definition: qgsprocessing.h:53
bool nextFeature(QgsFeature &f)
Contains information about the context in which a processing algorithm is executed.
Any vector layer with geometry.
Definition: qgsprocessing.h:47