QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
qgsalgorithmextractbylocation.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsalgorithmextractbylocation.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#include "qgsgeometryengine.h"
20#include "qgsvectorlayer.h"
22
24
25void QgsLocationBasedAlgorithm::addPredicateParameter()
26{
27 std::unique_ptr< QgsProcessingParameterEnum > predicateParam( new QgsProcessingParameterEnum( QStringLiteral( "PREDICATE" ),
28 QObject::tr( "Where the features (geometric predicate)" ),
29 predicateOptionsList(), true, QVariant::fromValue( QList< int >() << 0 ) ) );
30
31 QVariantMap predicateMetadata;
32 QVariantMap widgetMetadata;
33 widgetMetadata.insert( QStringLiteral( "useCheckBoxes" ), true );
34 widgetMetadata.insert( QStringLiteral( "columns" ), 2 );
35 predicateMetadata.insert( QStringLiteral( "widget_wrapper" ), widgetMetadata );
36 predicateParam->setMetadata( predicateMetadata );
37
38 addParameter( predicateParam.release() );
39}
40
41QgsLocationBasedAlgorithm::Predicate QgsLocationBasedAlgorithm::reversePredicate( QgsLocationBasedAlgorithm::Predicate predicate ) const
42{
43 switch ( predicate )
44 {
45 case Intersects:
46 return Intersects;
47 case Contains:
48 return Within;
49 case Disjoint:
50 return Disjoint;
51 case IsEqual:
52 return IsEqual;
53 case Touches:
54 return Touches;
55 case Overlaps:
56 return Overlaps;
57 case Within:
58 return Contains;
59 case Crosses:
60 return Crosses;
61 }
62 // no warnings
63 return Intersects;
64}
65
66QStringList QgsLocationBasedAlgorithm::predicateOptionsList() const
67{
68 return QStringList() << QObject::tr( "intersect" )
69 << QObject::tr( "contain" )
70 << QObject::tr( "disjoint" )
71 << QObject::tr( "equal" )
72 << QObject::tr( "touch" )
73 << QObject::tr( "overlap" )
74 << QObject::tr( "are within" )
75 << QObject::tr( "cross" );
76}
77
78void QgsLocationBasedAlgorithm::process( const QgsProcessingContext &context, QgsFeatureSource *targetSource,
79 QgsFeatureSource *intersectSource,
80 const QList< int > &selectedPredicates,
81 const std::function < void( const QgsFeature & ) > &handleFeatureFunction,
82 bool onlyRequireTargetIds,
83 QgsProcessingFeedback *feedback,
84 const QgsFeatureIds &skipTargetFeatureIds )
85{
86 // skip if there are no features to select from!
87 if ( targetSource->featureCount() == 0 )
88 return;
89
90 // skip if intersect layer is empty, unless we are looking for disjoints
91 if ( intersectSource->featureCount() == 0 &&
92 !selectedPredicates.contains( Disjoint ) )
93 return;
94
95 if ( targetSource->featureCount() > 0 && intersectSource->featureCount() > 0 &&
96 targetSource->featureCount() < intersectSource->featureCount() )
97 {
98 // joining FEWER features to a layer with MORE features. So we iterate over the FEW features and find matches from the MANY
99 processByIteratingOverTargetSource( context, targetSource, intersectSource,
100 selectedPredicates, handleFeatureFunction,
101 onlyRequireTargetIds, feedback, skipTargetFeatureIds );
102 }
103 else
104 {
105 // default -- iterate over the intersect source and match back to the target source. We do this on the assumption that the most common
106 // use case is joining a points layer to a polygon layer (e.g. findings points within a polygon), so by iterating
107 // over the polygons we can take advantage of prepared geometries for the spatial relationship test.
108
109 // TODO - consider using more heuristics to determine whether it's always best to iterate over the intersect
110 // source.
111 processByIteratingOverIntersectSource( context, targetSource, intersectSource,
112 selectedPredicates, handleFeatureFunction,
113 onlyRequireTargetIds, feedback, skipTargetFeatureIds );
114 }
115}
116
117void QgsLocationBasedAlgorithm::processByIteratingOverTargetSource( const QgsProcessingContext &context, QgsFeatureSource *targetSource,
118 QgsFeatureSource *intersectSource,
119 const QList< int > &selectedPredicates,
120 const std::function < void( const QgsFeature & ) > &handleFeatureFunction,
121 bool onlyRequireTargetIds,
122 QgsProcessingFeedback *feedback,
123 const QgsFeatureIds &skipTargetFeatureIds )
124{
126 feedback->pushWarning( QObject::tr( "No spatial index exists for intersect layer, performance will be severely degraded" ) );
127
128 QgsFeatureIds foundSet;
130 if ( onlyRequireTargetIds )
131 request.setNoAttributes();
132
133 QgsFeatureIterator fIt = targetSource->getFeatures( request );
134 double step = targetSource->featureCount() > 0 ? 100.0 / targetSource->featureCount() : 1;
135 int current = 0;
136 QgsFeature f;
137 std::unique_ptr< QgsGeometryEngine > engine;
138 while ( fIt.nextFeature( f ) )
139 {
140 if ( feedback->isCanceled() )
141 break;
142
143 // don't check features in skipTargetFeatureIds
144 if ( skipTargetFeatureIds.contains( f.id() ) )
145 continue;
146 if ( !f.hasGeometry() )
147 continue;
148
149 engine.reset();
150
151 QgsRectangle bbox = f.geometry().boundingBox();
152 request = QgsFeatureRequest().setFilterRect( bbox ).setNoAttributes().setDestinationCrs( targetSource->sourceCrs(), context.transformContext() );
153
154 QgsFeatureIterator testFeatureIt = intersectSource->getFeatures( request );
155 QgsFeature testFeature;
156 bool isMatch = false;
157 bool isDisjoint = true;
158 while ( testFeatureIt.nextFeature( testFeature ) )
159 {
160 if ( feedback->isCanceled() )
161 break;
162
163 if ( !engine )
164 {
165 engine.reset( QgsGeometry::createGeometryEngine( f.geometry().constGet() ) );
166 engine->prepareGeometry();
167 }
168
169 for ( int predicate : selectedPredicates )
170 {
171 switch ( static_cast< Predicate>( predicate ) )
172 {
173 case Intersects:
174 isMatch = engine->intersects( testFeature.geometry().constGet() );
175 break;
176 case Contains:
177 isMatch = engine->contains( testFeature.geometry().constGet() );
178 break;
179 case Disjoint:
180 if ( engine->intersects( testFeature.geometry().constGet() ) )
181 {
182 isDisjoint = false;
183 }
184 break;
185 case IsEqual:
186 isMatch = engine->isEqual( testFeature.geometry().constGet() );
187 break;
188 case Touches:
189 isMatch = engine->touches( testFeature.geometry().constGet() );
190 break;
191 case Overlaps:
192 isMatch = engine->overlaps( testFeature.geometry().constGet() );
193 break;
194 case Within:
195 isMatch = engine->within( testFeature.geometry().constGet() );
196 break;
197 case Crosses:
198 isMatch = engine->crosses( testFeature.geometry().constGet() );
199 break;
200 }
201
202 if ( isMatch )
203 break;
204 }
205
206 if ( isMatch )
207 {
208 foundSet.insert( f.id() );
209 handleFeatureFunction( f );
210 break;
211 }
212 }
213 if ( isDisjoint && selectedPredicates.contains( Disjoint ) )
214 {
215 foundSet.insert( f.id() );
216 handleFeatureFunction( f );
217 }
218
219 current += 1;
220 feedback->setProgress( current * step );
221 }
222}
223
224void QgsLocationBasedAlgorithm::processByIteratingOverIntersectSource( const QgsProcessingContext &context, QgsFeatureSource *targetSource,
225 QgsFeatureSource *intersectSource,
226 const QList< int > &selectedPredicates,
227 const std::function < void( const QgsFeature & ) > &handleFeatureFunction,
228 bool onlyRequireTargetIds,
229 QgsProcessingFeedback *feedback,
230 const QgsFeatureIds &skipTargetFeatureIds )
231{
233 feedback->pushWarning( QObject::tr( "No spatial index exists for input layer, performance will be severely degraded" ) );
234
235 // build a list of 'reversed' predicates, because in this function
236 // we actually test the reverse of what the user wants (allowing us
237 // to prepare geometries and optimise the algorithm)
238 QList< Predicate > predicates;
239 predicates.reserve( selectedPredicates.count() );
240 for ( int i : selectedPredicates )
241 {
242 predicates << reversePredicate( static_cast< Predicate >( i ) );
243 }
244
245 QgsFeatureIds disjointSet;
246 if ( predicates.contains( Disjoint ) )
247 disjointSet = targetSource->allFeatureIds();
248
249 QgsFeatureIds foundSet;
251 QgsFeatureIterator fIt = intersectSource->getFeatures( request );
252 double step = intersectSource->featureCount() > 0 ? 100.0 / intersectSource->featureCount() : 1;
253 int current = 0;
254 QgsFeature f;
255 std::unique_ptr< QgsGeometryEngine > engine;
256 while ( fIt.nextFeature( f ) )
257 {
258 if ( feedback->isCanceled() )
259 break;
260
261 if ( !f.hasGeometry() )
262 continue;
263
264 engine.reset();
265
266 QgsRectangle bbox = f.geometry().boundingBox();
267 request = QgsFeatureRequest().setFilterRect( bbox );
268 if ( onlyRequireTargetIds )
269 request.setNoAttributes();
270
271 QgsFeatureIterator testFeatureIt = targetSource->getFeatures( request );
272 QgsFeature testFeature;
273 while ( testFeatureIt.nextFeature( testFeature ) )
274 {
275 if ( feedback->isCanceled() )
276 break;
277
278 if ( skipTargetFeatureIds.contains( testFeature.id() ) )
279 {
280 // don't check features in skipTargetFeatureIds
281 continue;
282 }
283 if ( foundSet.contains( testFeature.id() ) )
284 {
285 // already added this one, no need for further tests
286 continue;
287 }
288 if ( predicates.count() == 1 && predicates.at( 0 ) == Disjoint && !disjointSet.contains( testFeature.id() ) )
289 {
290 // calculating only the disjoint set, and we've already eliminated this feature so no need for further tests
291 continue;
292 }
293
294 if ( !engine )
295 {
296 engine.reset( QgsGeometry::createGeometryEngine( f.geometry().constGet() ) );
297 engine->prepareGeometry();
298 }
299
300 bool isMatch = false;
301
302 for ( Predicate predicate : std::as_const( predicates ) )
303 {
304 switch ( predicate )
305 {
306 case Intersects:
307 isMatch = engine->intersects( testFeature.geometry().constGet() );
308 break;
309 case Contains:
310 isMatch = engine->contains( testFeature.geometry().constGet() );
311 break;
312 case Disjoint:
313 if ( engine->intersects( testFeature.geometry().constGet() ) )
314 {
315 disjointSet.remove( testFeature.id() );
316 }
317 break;
318 case IsEqual:
319 isMatch = engine->isEqual( testFeature.geometry().constGet() );
320 break;
321 case Touches:
322 isMatch = engine->touches( testFeature.geometry().constGet() );
323 break;
324 case Overlaps:
325 isMatch = engine->overlaps( testFeature.geometry().constGet() );
326 break;
327 case Within:
328 isMatch = engine->within( testFeature.geometry().constGet() );
329 break;
330 case Crosses:
331 isMatch = engine->crosses( testFeature.geometry().constGet() );
332 break;
333 }
334 if ( isMatch )
335 break;
336 }
337
338 if ( isMatch )
339 {
340 foundSet.insert( testFeature.id() );
341 handleFeatureFunction( testFeature );
342 }
343
344 }
345
346 current += 1;
347 feedback->setProgress( current * step );
348 }
349
350 if ( predicates.contains( Disjoint ) )
351 {
352 disjointSet = disjointSet.subtract( foundSet );
353 QgsFeatureRequest disjointReq = QgsFeatureRequest().setFilterFids( disjointSet );
354 if ( onlyRequireTargetIds )
356 QgsFeatureIterator disjointIt = targetSource->getFeatures( disjointReq );
357 QgsFeature f;
358 while ( disjointIt.nextFeature( f ) )
359 {
360 handleFeatureFunction( f );
361 }
362 }
363}
364
365
366//
367// QgsSelectByLocationAlgorithm
368//
369
370void QgsSelectByLocationAlgorithm::initAlgorithm( const QVariantMap & )
371{
372 QStringList methods = QStringList() << QObject::tr( "creating new selection" )
373 << QObject::tr( "adding to current selection" )
374 << QObject::tr( "selecting within current selection" )
375 << QObject::tr( "removing from current selection" );
376
377 addParameter( new QgsProcessingParameterVectorLayer( QStringLiteral( "INPUT" ), QObject::tr( "Select features from" ),
378 QList< int >() << QgsProcessing::TypeVectorAnyGeometry ) );
379 addPredicateParameter();
380 addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INTERSECT" ),
381 QObject::tr( "By comparing to the features from" ),
382 QList< int >() << QgsProcessing::TypeVectorAnyGeometry ) );
383
384 addParameter( new QgsProcessingParameterEnum( QStringLiteral( "METHOD" ),
385 QObject::tr( "Modify current selection by" ),
386 methods, false, 0 ) );
387}
388
389QString QgsSelectByLocationAlgorithm::name() const
390{
391 return QStringLiteral( "selectbylocation" );
392}
393
394QgsProcessingAlgorithm::Flags QgsSelectByLocationAlgorithm::flags() const
395{
397}
398
399QString QgsSelectByLocationAlgorithm::displayName() const
400{
401 return QObject::tr( "Select by location" );
402}
403
404QStringList QgsSelectByLocationAlgorithm::tags() const
405{
406 return QObject::tr( "select,intersects,intersecting,disjoint,touching,within,contains,overlaps,relation" ).split( ',' );
407}
408
409QString QgsSelectByLocationAlgorithm::group() const
410{
411 return QObject::tr( "Vector selection" );
412}
413
414QString QgsSelectByLocationAlgorithm::groupId() const
415{
416 return QStringLiteral( "vectorselection" );
417}
418
419QString QgsSelectByLocationAlgorithm::shortHelpString() const
420{
421 return QObject::tr( "This algorithm creates a selection in a vector layer. The criteria for selecting "
422 "features is based on the spatial relationship between each feature and the features in an additional layer." );
423}
424
425QgsSelectByLocationAlgorithm *QgsSelectByLocationAlgorithm::createInstance() const
426{
427 return new QgsSelectByLocationAlgorithm();
428}
429
430QVariantMap QgsSelectByLocationAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
431{
432 QgsVectorLayer *selectLayer = parameterAsVectorLayer( parameters, QStringLiteral( "INPUT" ), context );
433 if ( !selectLayer )
434 throw QgsProcessingException( QObject::tr( "Could not load source layer for INPUT" ) );
435
436 Qgis::SelectBehavior method = static_cast< Qgis::SelectBehavior >( parameterAsEnum( parameters, QStringLiteral( "METHOD" ), context ) );
437 std::unique_ptr< QgsFeatureSource > intersectSource( parameterAsSource( parameters, QStringLiteral( "INTERSECT" ), context ) );
438 if ( !intersectSource )
439 throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INTERSECT" ) ) );
440
441 const QList< int > selectedPredicates = parameterAsEnums( parameters, QStringLiteral( "PREDICATE" ), context );
442
443 QgsFeatureIds selectedIds;
444 auto addToSelection = [&]( const QgsFeature & feature )
445 {
446 selectedIds.insert( feature.id() );
447 };
448 switch ( method )
449 {
452 {
453 // When subsetting or removing we only need to check already selected features
454 std::unique_ptr< QgsVectorLayerSelectedFeatureSource > selectLayerSelected( new QgsVectorLayerSelectedFeatureSource( selectLayer ) );
455 process( context, selectLayerSelected.get(), intersectSource.get(), selectedPredicates, addToSelection, true, feedback );
456 break;
457 }
459 // When adding we can skip checking already selected features
460 process( context, selectLayer, intersectSource.get(), selectedPredicates, addToSelection, true, feedback, selectLayer->selectedFeatureIds() );
461 break;
463 process( context, selectLayer, intersectSource.get(), selectedPredicates, addToSelection, true, feedback );
464 break;
465 }
466
467 selectLayer->selectByIds( selectedIds, method );
468 QVariantMap results;
469 results.insert( QStringLiteral( "OUTPUT" ), parameters.value( QStringLiteral( "INPUT" ) ) );
470 return results;
471}
472
473
474//
475// QgsExtractByLocationAlgorithm
476//
477
478void QgsExtractByLocationAlgorithm::initAlgorithm( const QVariantMap & )
479{
480 addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ),
481 QObject::tr( "Extract features from" ),
482 QList< int >() << QgsProcessing::TypeVectorAnyGeometry ) );
483 addPredicateParameter();
484 addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INTERSECT" ),
485 QObject::tr( "By comparing to the features from" ),
486 QList< int >() << QgsProcessing::TypeVectorAnyGeometry ) );
487
488 addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Extracted (location)" ) ) );
489}
490
491QString QgsExtractByLocationAlgorithm::name() const
492{
493 return QStringLiteral( "extractbylocation" );
494}
495
496QString QgsExtractByLocationAlgorithm::displayName() const
497{
498 return QObject::tr( "Extract by location" );
499}
500
501QStringList QgsExtractByLocationAlgorithm::tags() const
502{
503 return QObject::tr( "extract,filter,intersects,intersecting,disjoint,touching,within,contains,overlaps,relation" ).split( ',' );
504}
505
506QString QgsExtractByLocationAlgorithm::group() const
507{
508 return QObject::tr( "Vector selection" );
509}
510
511QString QgsExtractByLocationAlgorithm::groupId() const
512{
513 return QStringLiteral( "vectorselection" );
514}
515
516QString QgsExtractByLocationAlgorithm::shortHelpString() const
517{
518 return QObject::tr( "This algorithm creates a new vector layer that only contains matching features from an "
519 "input layer. The criteria for adding features to the resulting layer is defined "
520 "based on the spatial relationship between each feature and the features in an additional layer." );
521}
522
523QgsExtractByLocationAlgorithm *QgsExtractByLocationAlgorithm::createInstance() const
524{
525 return new QgsExtractByLocationAlgorithm();
526}
527
528QVariantMap QgsExtractByLocationAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
529{
530 std::unique_ptr< QgsFeatureSource > input( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
531 if ( !input )
532 throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
533 std::unique_ptr< QgsFeatureSource > intersectSource( parameterAsSource( parameters, QStringLiteral( "INTERSECT" ), context ) );
534 if ( !intersectSource )
535 throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INTERSECT" ) ) );
536
537 const QList< int > selectedPredicates = parameterAsEnums( parameters, QStringLiteral( "PREDICATE" ), context );
538 QString dest;
539 std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, input->fields(), input->wkbType(), input->sourceCrs() ) );
540
541 if ( !sink )
542 throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
543
544 auto addToSink = [&]( const QgsFeature & feature )
545 {
546 QgsFeature f = feature;
547 if ( !sink->addFeature( f, QgsFeatureSink::FastInsert ) )
548 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, QStringLiteral( "OUTPUT" ) ) );
549 };
550 process( context, input.get(), intersectSource.get(), selectedPredicates, addToSink, false, feedback );
551
552 QVariantMap results;
553 results.insert( QStringLiteral( "OUTPUT" ), dest );
554 return results;
555}
556
558
559
SelectBehavior
Specifies how a selection should be applied.
Definition: qgis.h:798
@ SetSelection
Set selection, removing any existing selection.
@ AddToSelection
Add selection to current selection.
@ IntersectSelection
Modify current selection to include only select features which match.
@ RemoveFromSelection
Remove from current selection.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets the feature IDs that should be fetched.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
QgsFeatureRequest & setDestinationCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets the destination crs for feature's geometries.
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
QgsFeatureRequest & setNoAttributes()
Set that no attributes will be fetched.
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
@ FastInsert
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
An interface for objects which provide features via a getFeatures method.
virtual QgsCoordinateReferenceSystem sourceCrs() const =0
Returns the coordinate reference system for features in the source.
@ SpatialIndexNotPresent
No spatial index exists for the source.
virtual QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const =0
Returns an iterator for the features in the source.
virtual long long featureCount() const =0
Returns the number of features contained in the source, or -1 if the feature count is unknown.
virtual QgsFeatureIds allFeatureIds() const
Returns a list of all feature IDs for features present in the source.
virtual SpatialIndexPresence hasSpatialIndex() const
Returns an enum value representing the presence of a valid spatial index on the source,...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
QgsGeometry geometry
Definition: qgsfeature.h:67
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:233
Q_GADGET QgsFeatureId id
Definition: qgsfeature.h:64
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:63
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine representing the specified geometry.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
virtual Flags flags() const
Returns the flags indicating how and when the algorithm operates and should be exposed to users.
@ FlagNotAvailableInStandaloneTool
Algorithm should not be available from the standalone "qgis_process" tool. Used to flag algorithms wh...
@ FlagNoThreading
Algorithm is not thread safe and cannot be run in a background thread, e.g. for algorithms which mani...
Contains information about the context in which a processing algorithm is executed.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
Custom exception class for processing related exceptions.
Definition: qgsexception.h:83
Base class for providing feedback from a processing algorithm.
virtual void pushWarning(const QString &warning)
Pushes a warning informational message from the algorithm.
An enum based parameter for processing algorithms, allowing for selection from predefined values.
A feature sink output for processing algorithms.
An input feature source (such as vector layers) parameter for processing algorithms.
A vector layer (with or without geometry) parameter for processing algorithms.
@ TypeVectorAnyGeometry
Any vector layer with geometry.
Definition: qgsprocessing.h:48
A rectangle specified with double values.
Definition: qgsrectangle.h:42
QgsFeatureSource subclass for the selected features from a QgsVectorLayer.
Represents a vector layer which manages a vector based data sets.
Q_INVOKABLE const QgsFeatureIds & selectedFeatureIds() const
Returns a list of the selected features IDs in this layer.
Q_INVOKABLE void selectByIds(const QgsFeatureIds &ids, Qgis::SelectBehavior behavior=Qgis::SelectBehavior::SetSelection)
Selects matching features using a list of feature IDs.
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:37