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