QGIS API Documentation 3.32.0-Lima (311a8cb8a6)
qgsoverlayutils.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsoverlayutils.cpp
3 ---------------------
4 Date : April 2018
5 Copyright : (C) 2018 by Martin Dobias
6 Email : wonder dot sk at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16#include "qgsoverlayutils.h"
17
18#include "qgsgeometryengine.h"
19#include "qgsfeature.h"
20#include "qgsfeaturerequest.h"
21#include "qgsfeaturesource.h"
23#include "qgsspatialindex.h"
24
26
27bool QgsOverlayUtils::sanitizeIntersectionResult( QgsGeometry &geom, Qgis::GeometryType geometryType, SanitizeFlags flags )
28{
29 if ( geom.isNull() )
30 {
31 // TODO: not sure if this ever happens - if it does, that means GEOS failed badly - would be good to have a test for such situation
32 throw QgsProcessingException( QStringLiteral( "%1\n\n%2" ).arg( QObject::tr( "GEOS geoprocessing error: intersection failed." ), geom.lastError() ) );
33 }
34
35 // Intersection of geometries may give use also geometries we do not want in our results.
36 // For example, two square polygons touching at the corner have a point as the intersection, but no area.
37 // In other cases we may get a mixture of geometries in the output - we want to keep only the expected types.
39 {
40 // try to filter out irrelevant parts with different geometry type than what we want
41 geom.convertGeometryCollectionToSubclass( geometryType );
42 if ( geom.isEmpty() )
43 return false;
44 }
45
46 if ( QgsWkbTypes::geometryType( geom.wkbType() ) != geometryType )
47 {
48 // we can't make use of this resulting geometry
49 return false;
50 }
51
52 if ( geometryType != Qgis::GeometryType::Point
53 || !( flags & SanitizeFlag::DontPromotePointGeometryToMultiPoint ) )
54 {
55 // some data providers are picky about the geometries we pass to them: we can't add single-part geometries
56 // when we promised multi-part geometries, so ensure we have the right type
57 geom.convertToMultiType();
58 }
59
60 return true;
61}
62
63
65static bool sanitizeDifferenceResult( QgsGeometry &geom, Qgis::GeometryType geometryType, QgsOverlayUtils::SanitizeFlags flags )
66{
67 if ( geom.isNull() )
68 {
69 // TODO: not sure if this ever happens - if it does, that means GEOS failed badly - would be good to have a test for such situation
70 throw QgsProcessingException( QStringLiteral( "%1\n\n%2" ).arg( QObject::tr( "GEOS geoprocessing error: difference failed." ), geom.lastError() ) );
71 }
72
73 //fix geometry collections
75 {
76 // try to filter out irrelevant parts with different geometry type than what we want
77 geom.convertGeometryCollectionToSubclass( geometryType );
78 }
79
80
81 // if geomB covers the whole source geometry, we get an empty geometry collection
82 if ( geom.isEmpty() )
83 return false;
84
85 if ( geometryType != Qgis::GeometryType::Point
86 || !( flags & QgsOverlayUtils::SanitizeFlag::DontPromotePointGeometryToMultiPoint ) )
87 {
88 // some data providers are picky about the geometries we pass to them: we can't add single-part geometries
89 // when we promised multi-part geometries, so ensure we have the right type
90 geom.convertToMultiType();
91 }
92
93 return true;
94}
95
96
97static QString writeFeatureError()
98{
99 return QObject::tr( "Could not write feature" );
100}
101
102void QgsOverlayUtils::difference( const QgsFeatureSource &sourceA, const QgsFeatureSource &sourceB, QgsFeatureSink &sink, QgsProcessingContext &context, QgsProcessingFeedback *feedback, long &count, long totalCount, QgsOverlayUtils::DifferenceOutput outputAttrs, const QgsGeometryParameters &parameters, SanitizeFlags flags )
103{
105 QgsFeatureRequest requestB;
106 requestB.setNoAttributes();
107 if ( outputAttrs != OutputBA )
108 requestB.setDestinationCrs( sourceA.sourceCrs(), context.transformContext() );
109
110 double step = sourceB.featureCount() > 0 ? 100.0 / static_cast< double >( sourceB.featureCount() ) : 1;
111 long long i = 0;
112 QgsFeatureIterator fi = sourceB.getFeatures( requestB );
113
114 feedback->setProgressText( QObject::tr( "Creating spatial index" ) );
115 const QgsSpatialIndex indexB( fi, [&]( const QgsFeature & )->bool
116 {
117 i++;
118 if ( feedback->isCanceled() )
119 return false;
120
121 feedback->setProgress( static_cast< double >( i ) * step );
122
123 return true;
124 } );
125
126 if ( feedback->isCanceled() )
127 return;
128
129 const int fieldsCountA = sourceA.fields().count();
130 const int fieldsCountB = sourceB.fields().count();
131 QgsAttributes attrs;
132 attrs.resize( outputAttrs == OutputA ? fieldsCountA : ( fieldsCountA + fieldsCountB ) );
133
134 if ( totalCount == 0 )
135 totalCount = 1; // avoid division by zero
136
137 feedback->setProgressText( QObject::tr( "Calculating difference" ) );
138
139 QgsFeature featA;
140 QgsFeatureRequest requestA;
141 requestA.setInvalidGeometryCheck( context.invalidGeometryCheck() );
142 if ( outputAttrs == OutputBA )
143 requestA.setDestinationCrs( sourceB.sourceCrs(), context.transformContext() );
144 QgsFeatureIterator fitA = sourceA.getFeatures( requestA );
145 while ( fitA.nextFeature( featA ) )
146 {
147 if ( feedback->isCanceled() )
148 break;
149
150 if ( featA.hasGeometry() )
151 {
152 QgsGeometry geom( featA.geometry() );
153 const QgsFeatureIds intersects = qgis::listToSet( indexB.intersects( geom.boundingBox() ) );
154
155 QgsFeatureRequest request;
156 request.setFilterFids( intersects );
157 request.setNoAttributes();
158 if ( outputAttrs != OutputBA )
159 request.setDestinationCrs( sourceA.sourceCrs(), context.transformContext() );
160
161 std::unique_ptr< QgsGeometryEngine > engine;
162 if ( !intersects.isEmpty() )
163 {
164 // use prepared geometries for faster intersection tests
165 engine.reset( QgsGeometry::createGeometryEngine( geom.constGet() ) );
166 engine->prepareGeometry();
167 }
168
169 QVector<QgsGeometry> geometriesB;
170 QgsFeature featB;
171 QgsFeatureIterator fitB = sourceB.getFeatures( request );
172 while ( fitB.nextFeature( featB ) )
173 {
174 if ( feedback->isCanceled() )
175 break;
176
177 if ( engine->intersects( featB.geometry().constGet() ) )
178 geometriesB << featB.geometry();
179 }
180
181 if ( !geometriesB.isEmpty() )
182 {
183 const QgsGeometry geomB = QgsGeometry::unaryUnion( geometriesB, parameters );
184 if ( !geomB.lastError().isEmpty() )
185 {
186 // This may happen if input geometries from a layer do not line up well (for example polygons
187 // that are nearly touching each other, but there is a very tiny overlap or gap at one of the edges).
188 // It is possible to get rid of this issue in two steps:
189 // 1. snap geometries with a small tolerance (e.g. 1cm) using QgsGeometrySnapperSingleSource
190 // 2. fix geometries (removes polygons collapsed to lines etc.) using MakeValid
191 throw QgsProcessingException( QStringLiteral( "%1\n\n%2" ).arg( QObject::tr( "GEOS geoprocessing error: unary union failed." ), geomB.lastError() ) );
192 }
193 geom = geom.difference( geomB, parameters );
194 }
195
196 if ( !geom.isNull() && !sanitizeDifferenceResult( geom, geometryType, flags ) )
197 continue;
198
199 const QgsAttributes attrsA( featA.attributes() );
200 switch ( outputAttrs )
201 {
202 case OutputA:
203 attrs = attrsA;
204 break;
205 case OutputAB:
206 for ( int i = 0; i < fieldsCountA; ++i )
207 attrs[i] = attrsA[i];
208 break;
209 case OutputBA:
210 for ( int i = 0; i < fieldsCountA; ++i )
211 attrs[i + fieldsCountB] = attrsA[i];
212 break;
213 }
214
215 QgsFeature outFeat;
216 outFeat.setGeometry( geom );
217 outFeat.setAttributes( attrs );
218 if ( !sink.addFeature( outFeat, QgsFeatureSink::FastInsert ) )
219 throw QgsProcessingException( writeFeatureError() );
220 }
221 else
222 {
223 // TODO: should we write out features that do not have geometry?
224 if ( !sink.addFeature( featA, QgsFeatureSink::FastInsert ) )
225 throw QgsProcessingException( writeFeatureError() );
226 }
227
228 ++count;
229 feedback->setProgress( count / static_cast< double >( totalCount ) * 100. );
230 }
231}
232
233
234void QgsOverlayUtils::intersection( const QgsFeatureSource &sourceA, const QgsFeatureSource &sourceB, QgsFeatureSink &sink, QgsProcessingContext &context, QgsProcessingFeedback *feedback, long &count, long totalCount, const QList<int> &fieldIndicesA, const QList<int> &fieldIndicesB, const QgsGeometryParameters &parameters )
235{
237 const int attrCount = fieldIndicesA.count() + fieldIndicesB.count();
238
239 QgsFeatureRequest request;
240 request.setNoAttributes();
241 request.setDestinationCrs( sourceA.sourceCrs(), context.transformContext() );
242
243 QgsFeature outFeat;
244
245 double step = sourceB.featureCount() > 0 ? 100.0 / static_cast< double >( sourceB.featureCount() ) : 1;
246 long long i = 0;
247 QgsFeatureIterator fi = sourceB.getFeatures( request );
248 feedback->setProgressText( QObject::tr( "Creating spatial index" ) );
249 const QgsSpatialIndex indexB( fi, [&]( const QgsFeature & )->bool
250 {
251 i++;
252 if ( feedback->isCanceled() )
253 return false;
254
255 feedback->setProgress( static_cast< double >( i ) * step );
256
257 return true;
258 } );
259
260 if ( feedback->isCanceled() )
261 return;
262
263 if ( totalCount == 0 )
264 totalCount = 1; // avoid division by zero
265
266 feedback->setProgressText( QObject::tr( "Calculating intersection" ) );
267
268 QgsFeature featA;
269 QgsFeatureIterator fitA = sourceA.getFeatures( QgsFeatureRequest().setSubsetOfAttributes( fieldIndicesA ) );
270 while ( fitA.nextFeature( featA ) )
271 {
272 if ( feedback->isCanceled() )
273 break;
274
275 if ( !featA.hasGeometry() )
276 continue;
277
278 const QgsGeometry geom( featA.geometry() );
279 const QgsFeatureIds intersects = qgis::listToSet( indexB.intersects( geom.boundingBox() ) );
280
281 QgsFeatureRequest request;
282 request.setFilterFids( intersects );
283 request.setDestinationCrs( sourceA.sourceCrs(), context.transformContext() );
284 request.setSubsetOfAttributes( fieldIndicesB );
285
286 std::unique_ptr< QgsGeometryEngine > engine;
287 if ( !intersects.isEmpty() )
288 {
289 // use prepared geometries for faster intersection tests
290 engine.reset( QgsGeometry::createGeometryEngine( geom.constGet() ) );
291 engine->prepareGeometry();
292 }
293
294 QgsAttributes outAttributes( attrCount );
295 const QgsAttributes attrsA( featA.attributes() );
296 for ( int i = 0; i < fieldIndicesA.count(); ++i )
297 outAttributes[i] = attrsA[fieldIndicesA[i]];
298
299 QgsFeature featB;
300 QgsFeatureIterator fitB = sourceB.getFeatures( request );
301 while ( fitB.nextFeature( featB ) )
302 {
303 if ( feedback->isCanceled() )
304 break;
305
306 const QgsGeometry tmpGeom( featB.geometry() );
307 if ( !engine->intersects( tmpGeom.constGet() ) )
308 continue;
309
310 QgsGeometry intGeom = geom.intersection( tmpGeom, parameters );
311 if ( !sanitizeIntersectionResult( intGeom, geometryType ) )
312 continue;
313
314 const QgsAttributes attrsB( featB.attributes() );
315 for ( int i = 0; i < fieldIndicesB.count(); ++i )
316 outAttributes[fieldIndicesA.count() + i] = attrsB[fieldIndicesB[i]];
317
318 outFeat.setGeometry( intGeom );
319 outFeat.setAttributes( outAttributes );
320 if ( !sink.addFeature( outFeat, QgsFeatureSink::FastInsert ) )
321 throw QgsProcessingException( writeFeatureError() );
322 }
323
324 ++count;
325 feedback->setProgress( count / static_cast<double >( totalCount ) * 100. );
326 }
327}
328
329void QgsOverlayUtils::resolveOverlaps( const QgsFeatureSource &source, QgsFeatureSink &sink, QgsProcessingFeedback *feedback, const QgsGeometryParameters &parameters, SanitizeFlags flags )
330{
331 long count = 0;
332 const long totalCount = source.featureCount();
333 if ( totalCount == 0 )
334 return; // nothing to do here
335
336 QgsFeatureId newFid = -1;
337
339
340 QgsFeatureRequest requestOnlyGeoms;
341 requestOnlyGeoms.setNoAttributes();
342
343 QgsFeatureRequest requestOnlyAttrs;
344 requestOnlyAttrs.setFlags( QgsFeatureRequest::NoGeometry );
345
346 QgsFeatureRequest requestOnlyIds;
347 requestOnlyIds.setFlags( QgsFeatureRequest::NoGeometry );
348 requestOnlyIds.setNoAttributes();
349
350 // make a set of used feature IDs so that we do not try to reuse them for newly added features
351 QgsFeature f;
352 QSet<QgsFeatureId> fids;
353 QgsFeatureIterator it = source.getFeatures( requestOnlyIds );
354 while ( it.nextFeature( f ) )
355 {
356 if ( feedback->isCanceled() )
357 return;
358
359 fids.insert( f.id() );
360 }
361
362 QHash<QgsFeatureId, QgsGeometry> geometries;
363 QgsSpatialIndex index;
364 QHash<QgsFeatureId, QList<QgsFeatureId> > intersectingIds; // which features overlap a particular area
365
366 // resolve intersections
367
368 it = source.getFeatures( requestOnlyGeoms );
369 while ( it.nextFeature( f ) )
370 {
371 if ( feedback->isCanceled() )
372 return;
373
374 const QgsFeatureId fid1 = f.id();
375 QgsGeometry g1 = f.geometry();
376 std::unique_ptr< QgsGeometryEngine > g1engine;
377
378 geometries.insert( fid1, g1 );
379 index.addFeature( f );
380
381 const QgsRectangle bbox( f.geometry().boundingBox() );
382 const QList<QgsFeatureId> ids = index.intersects( bbox );
383 for ( const QgsFeatureId fid2 : ids )
384 {
385 if ( fid1 == fid2 )
386 continue;
387
388 if ( !g1engine )
389 {
390 // use prepared geometries for faster intersection tests
391 g1engine.reset( QgsGeometry::createGeometryEngine( g1.constGet() ) );
392 g1engine->prepareGeometry();
393 }
394
395 const QgsGeometry g2 = geometries.value( fid2 );
396 if ( !g1engine->intersects( g2.constGet() ) )
397 continue;
398
399 QgsGeometry geomIntersection = g1.intersection( g2, parameters );
400 if ( !sanitizeIntersectionResult( geomIntersection, geometryType ) )
401 continue;
402
403 //
404 // add intersection geometry
405 //
406
407 // figure out new fid
408 while ( fids.contains( newFid ) )
409 --newFid;
410 fids.insert( newFid );
411
412 geometries.insert( newFid, geomIntersection );
413 QgsFeature fx( newFid );
414 fx.setGeometry( geomIntersection );
415
416 index.addFeature( fx );
417
418 // figure out which feature IDs belong to this intersection. Some of the IDs can be of the newly
419 // created geometries - in such case we need to retrieve original IDs
420 QList<QgsFeatureId> lst;
421 if ( intersectingIds.contains( fid1 ) )
422 lst << intersectingIds.value( fid1 );
423 else
424 lst << fid1;
425 if ( intersectingIds.contains( fid2 ) )
426 lst << intersectingIds.value( fid2 );
427 else
428 lst << fid2;
429 intersectingIds.insert( newFid, lst );
430
431 //
432 // update f1
433 //
434
435 QgsGeometry g12 = g1.difference( g2, parameters );
436
437 index.deleteFeature( f );
438 geometries.remove( fid1 );
439
440 if ( sanitizeDifferenceResult( g12, geometryType, flags ) )
441 {
442 geometries.insert( fid1, g12 );
443
444 QgsFeature f1x( fid1 );
445 f1x.setGeometry( g12 );
446 index.addFeature( f1x );
447 }
448
449 //
450 // update f2
451 //
452
453 QgsGeometry g21 = g2.difference( g1, parameters );
454
455 QgsFeature f2old( fid2 );
456 f2old.setGeometry( g2 );
457 index.deleteFeature( f2old );
458
459 geometries.remove( fid2 );
460
461 if ( sanitizeDifferenceResult( g21, geometryType, flags ) )
462 {
463 geometries.insert( fid2, g21 );
464
465 QgsFeature f2x( fid2 );
466 f2x.setGeometry( g21 );
467 index.addFeature( f2x );
468 }
469
470 // update our temporary copy of the geometry to what is left from it
471 g1 = g12;
472 g1engine.reset();
473 }
474
475 ++count;
476 feedback->setProgress( count / static_cast< double >( totalCount ) * 100. );
477 }
478 if ( feedback->isCanceled() )
479 return;
480
481 // release some memory of structures we don't need anymore
482
483 fids.clear();
484 index = QgsSpatialIndex();
485
486 // load attributes
487
488 QHash<QgsFeatureId, QgsAttributes> attributesHash;
489 it = source.getFeatures( requestOnlyAttrs );
490 while ( it.nextFeature( f ) )
491 {
492 if ( feedback->isCanceled() )
493 return;
494
495 attributesHash.insert( f.id(), f.attributes() );
496 }
497
498 // store stuff in the sink
499
500 for ( auto i = geometries.constBegin(); i != geometries.constEnd(); ++i )
501 {
502 if ( feedback->isCanceled() )
503 return;
504
505 QgsFeature outFeature( i.key() );
506 outFeature.setGeometry( i.value() );
507
508 if ( intersectingIds.contains( i.key() ) )
509 {
510 const QList<QgsFeatureId> ids = intersectingIds.value( i.key() );
511 for ( const QgsFeatureId id : ids )
512 {
513 outFeature.setAttributes( attributesHash.value( id ) );
514 if ( !sink.addFeature( outFeature, QgsFeatureSink::FastInsert ) )
515 throw QgsProcessingException( writeFeatureError() );
516 }
517 }
518 else
519 {
520 outFeature.setAttributes( attributesHash.value( i.key() ) );
521 if ( !sink.addFeature( outFeature, QgsFeatureSink::FastInsert ) )
522 throw QgsProcessingException( writeFeatureError() );
523 }
524 }
525}
526
GeometryType
The geometry types are used to group Qgis::WkbType in a coarse way.
Definition: qgis.h:227
@ GeometryCollection
GeometryCollection.
A vector of attributes.
Definition: qgsattributes.h:59
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 & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that 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 & setInvalidGeometryCheck(InvalidGeometryCheck check)
Sets invalid geometry checking behavior.
An interface for objects which accept features via addFeature(s) methods.
virtual bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags())
Adds a single feature to the sink.
@ 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 QgsFields fields() const =0
Returns the fields associated with features in the source.
virtual QgsCoordinateReferenceSystem sourceCrs() const =0
Returns the coordinate reference system for features in the source.
virtual Qgis::WkbType wkbType() const =0
Returns the geometry type for features returned by this 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.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
QgsAttributes attributes
Definition: qgsfeature.h:65
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
Definition: qgsfeature.cpp:160
QgsGeometry geometry
Definition: qgsfeature.h:67
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:230
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:167
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
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
Encapsulates parameters under which a geometry operation is performed.
Definition: qgsgeometry.h:111
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:164
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
QgsGeometry difference(const QgsGeometry &geometry, const QgsGeometryParameters &parameters=QgsGeometryParameters()) const
Returns a geometry representing the points making up this geometry that do not make up other.
Q_GADGET bool isNull
Definition: qgsgeometry.h:166
Qgis::WkbType wkbType() const SIP_HOLDGIL
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine representing the specified geometry.
QString lastError() const SIP_HOLDGIL
Returns an error string referring to the last error encountered either when this geometry was created...
QgsGeometry intersection(const QgsGeometry &geometry, const QgsGeometryParameters &parameters=QgsGeometryParameters()) const
Returns a geometry representing the points shared by this geometry and other.
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
bool convertGeometryCollectionToSubclass(Qgis::GeometryType geomType)
Converts geometry collection to a the desired geometry type subclass (multi-point,...
bool convertToMultiType()
Converts single type geometry into multitype geometry e.g.
static QgsGeometry unaryUnion(const QVector< QgsGeometry > &geometries, const QgsGeometryParameters &parameters=QgsGeometryParameters())
Compute the unary union on a list of geometries.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
Contains information about the context in which a processing algorithm is executed.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
QgsFeatureRequest::InvalidGeometryCheck invalidGeometryCheck() const
Returns the behavior used for checking invalid geometries in input layers.
Custom exception class for processing related exceptions.
Definition: qgsexception.h:84
Base class for providing feedback from a processing algorithm.
virtual void setProgressText(const QString &text)
Sets a progress report text string.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
A spatial index for QgsFeature objects.
QList< QgsFeatureId > intersects(const QgsRectangle &rectangle) const
Returns a list of features with a bounding box which intersects the specified rectangle.
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) override
Adds a feature to the index.
bool deleteFeature(const QgsFeature &feature)
Removes a feature from the index.
static Qgis::GeometryType geometryType(Qgis::WkbType type) SIP_HOLDGIL
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:865
static Qgis::WkbType multiType(Qgis::WkbType type) SIP_HOLDGIL
Returns the multi type for a WKB type.
Definition: qgswkbtypes.h:201
static Qgis::WkbType flatType(Qgis::WkbType type) SIP_HOLDGIL
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:629
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:37
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28