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