QGIS API Documentation 3.27.0-Master (9c08adf5ef)
qgsgeometrygapcheck.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsgeometrygapcheck.cpp
3 ---------------------
4 begin : September 2015
5 copyright : (C) 2014 by Sandro Mani / Sourcepole AG
6 email : smani at sourcepole dot ch
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
17#include "qgsgeometryengine.h"
18#include "qgsgeometrygapcheck.h"
20#include "qgsfeaturepool.h"
21#include "qgsvectorlayer.h"
22#include "qgsvectorlayerutils.h"
23#include "qgsfeedback.h"
24#include "qgsapplication.h"
25#include "qgsproject.h"
27#include "qgspolygon.h"
28#include "qgscurve.h"
29#include "qgssnappingutils.h"
30
31QgsGeometryGapCheck::QgsGeometryGapCheck( const QgsGeometryCheckContext *context, const QVariantMap &configuration )
32 : QgsGeometryCheck( context, configuration )
33 , mGapThresholdMapUnits( configuration.value( QStringLiteral( "gapThreshold" ) ).toDouble() )
34{
35}
36
37void QgsGeometryGapCheck::prepare( const QgsGeometryCheckContext *context, const QVariantMap &configuration )
38{
39 if ( configuration.value( QStringLiteral( "allowedGapsEnabled" ) ).toBool() )
40 {
41 QgsVectorLayer *layer = context->project()->mapLayer<QgsVectorLayer *>( configuration.value( "allowedGapsLayer" ).toString() );
42 if ( layer )
43 {
44 mAllowedGapsLayer = layer;
45 mAllowedGapsSource = std::make_unique<QgsVectorLayerFeatureSource>( layer );
46
47 mAllowedGapsBuffer = configuration.value( QStringLiteral( "allowedGapsBuffer" ) ).toDouble();
48 }
49 }
50 else
51 {
52 mAllowedGapsSource.reset();
53 }
54}
55
56void QgsGeometryGapCheck::collectErrors( const QMap<QString, QgsFeaturePool *> &featurePools, QList<QgsGeometryCheckError *> &errors, QStringList &messages, QgsFeedback *feedback, const LayerFeatureIds &ids ) const
57{
58 if ( feedback )
59 feedback->setProgress( feedback->progress() + 1.0 );
60
61 std::unique_ptr<QgsAbstractGeometry> allowedGapsGeom;
62 std::unique_ptr<QgsGeometryEngine> allowedGapsGeomEngine;
63
64 if ( mAllowedGapsSource )
65 {
66 QVector<QgsGeometry> allowedGaps;
67 QgsFeatureRequest request;
69 QgsFeatureIterator iterator = mAllowedGapsSource->getFeatures( request );
70 QgsFeature feature;
71
72 while ( iterator.nextFeature( feature ) )
73 {
74 const QgsGeometry geom = feature.geometry();
75 const QgsGeometry gg = geom.buffer( mAllowedGapsBuffer, 20 );
76 allowedGaps.append( gg );
77 }
78
79 std::unique_ptr< QgsGeometryEngine > allowedGapsEngine = QgsGeometryCheckerUtils::createGeomEngine( nullptr, mContext->tolerance );
80
81 // Create union of allowed gaps
82 QString errMsg;
83 allowedGapsGeom.reset( allowedGapsEngine->combine( allowedGaps, &errMsg ) );
84 allowedGapsGeomEngine = QgsGeometryCheckerUtils::createGeomEngine( allowedGapsGeom.get(), mContext->tolerance );
85 allowedGapsGeomEngine->prepareGeometry();
86 }
87
88 QVector<QgsGeometry> geomList;
89 const QMap<QString, QgsFeatureIds> featureIds = ids.isEmpty() ? allLayerFeatureIds( featurePools ) : ids.toMap();
90 const QgsGeometryCheckerUtils::LayerFeatures layerFeatures( featurePools, featureIds, compatibleGeometryTypes(), nullptr, mContext, true );
91 for ( const QgsGeometryCheckerUtils::LayerFeature &layerFeature : layerFeatures )
92 {
93 geomList.append( layerFeature.geometry() );
94
95 if ( feedback && feedback->isCanceled() )
96 {
97 geomList.clear();
98 break;
99 }
100 }
101
102 if ( geomList.isEmpty() )
103 {
104 return;
105 }
106
107 std::unique_ptr< QgsGeometryEngine > geomEngine = QgsGeometryCheckerUtils::createGeomEngine( nullptr, mContext->tolerance );
108
109 // Create union of geometry
110 QString errMsg;
111 const std::unique_ptr<QgsAbstractGeometry> unionGeom( geomEngine->combine( geomList, &errMsg ) );
112 if ( !unionGeom )
113 {
114 messages.append( tr( "Gap check: %1" ).arg( errMsg ) );
115 return;
116 }
117
118 // Get envelope of union
119 geomEngine = QgsGeometryCheckerUtils::createGeomEngine( unionGeom.get(), mContext->tolerance );
120 geomEngine->prepareGeometry();
121 std::unique_ptr<QgsAbstractGeometry> envelope( geomEngine->envelope( &errMsg ) );
122 if ( !envelope )
123 {
124 messages.append( tr( "Gap check: %1" ).arg( errMsg ) );
125 return;
126 }
127
128 // Buffer envelope
129 geomEngine = QgsGeometryCheckerUtils::createGeomEngine( envelope.get(), mContext->tolerance );
130 geomEngine->prepareGeometry();
131 QgsAbstractGeometry *bufEnvelope = geomEngine->buffer( 2, 0, Qgis::EndCapStyle::Square, Qgis::JoinStyle::Miter, 4. ); //#spellok //#spellok
132 envelope.reset( bufEnvelope );
133
134 // Compute difference between envelope and union to obtain gap polygons
135 geomEngine = QgsGeometryCheckerUtils::createGeomEngine( envelope.get(), mContext->tolerance );
136 geomEngine->prepareGeometry();
137 std::unique_ptr<QgsAbstractGeometry> diffGeom( geomEngine->difference( unionGeom.get(), &errMsg ) );
138 if ( !diffGeom )
139 {
140 messages.append( tr( "Gap check: %1" ).arg( errMsg ) );
141 return;
142 }
143
144 // For each gap polygon which does not lie on the boundary, get neighboring polygons and add error
145 QgsGeometryPartIterator parts = diffGeom->parts();
146 while ( parts.hasNext() )
147 {
148 const QgsAbstractGeometry *gapGeom = parts.next();
149 // Skip the gap between features and boundingbox
150 const double spacing = context()->tolerance;
151 if ( gapGeom->boundingBox().snappedToGrid( spacing ) == envelope->boundingBox().snappedToGrid( spacing ) )
152 {
153 continue;
154 }
155
156 // Skip gaps above threshold
157 if ( ( mGapThresholdMapUnits > 0 && gapGeom->area() > mGapThresholdMapUnits ) || gapGeom->area() < mContext->reducedTolerance )
158 {
159 continue;
160 }
161
162 QgsRectangle gapAreaBBox = gapGeom->boundingBox();
163
164 // Get neighboring polygons
165 QMap<QString, QgsFeatureIds> neighboringIds;
166 const QgsGeometryCheckerUtils::LayerFeatures layerFeatures( featurePools, featureIds.keys(), gapAreaBBox, compatibleGeometryTypes(), mContext );
167 std::unique_ptr< QgsGeometryEngine > gapGeomEngine = QgsGeometryCheckerUtils::createGeomEngine( gapGeom, mContext->tolerance );
168 gapGeomEngine->prepareGeometry();
169 for ( const QgsGeometryCheckerUtils::LayerFeature &layerFeature : layerFeatures )
170 {
171 const QgsGeometry geom = layerFeature.geometry();
172 if ( gapGeomEngine->distance( geom.constGet() ) < mContext->tolerance )
173 {
174 neighboringIds[layerFeature.layer()->id()].insert( layerFeature.feature().id() );
175 gapAreaBBox.combineExtentWith( geom.boundingBox() );
176 }
177 }
178
179 if ( neighboringIds.isEmpty() )
180 {
181 continue;
182 }
183
184 if ( allowedGapsGeomEngine && allowedGapsGeomEngine->contains( gapGeom ) )
185 {
186 continue;
187 }
188
189 // Add error
190 const double area = gapGeom->area();
191 const QgsRectangle gapBbox = gapGeom->boundingBox();
192 errors.append( new QgsGeometryGapCheckError( this, QString(), QgsGeometry( gapGeom->clone() ), neighboringIds, area, gapBbox, gapAreaBBox ) );
193 }
194}
195
196void QgsGeometryGapCheck::fixError( const QMap<QString, QgsFeaturePool *> &featurePools, QgsGeometryCheckError *error, int method, const QMap<QString, int> & /*mergeAttributeIndices*/, Changes &changes ) const
197{
198 const QMetaEnum metaEnum = QMetaEnum::fromType<QgsGeometryGapCheck::ResolutionMethod>();
199 if ( !metaEnum.isValid() || !metaEnum.valueToKey( method ) )
200 {
201 error->setFixFailed( tr( "Unknown method" ) );
202 }
203 else
204 {
205 const ResolutionMethod methodValue = static_cast<ResolutionMethod>( method );
206 switch ( methodValue )
207 {
208 case NoChange:
209 error->setFixed( method );
210 break;
211
212 case MergeLongestEdge:
213 {
214 QString errMsg;
215 if ( mergeWithNeighbor( featurePools, static_cast<QgsGeometryGapCheckError *>( error ), changes, errMsg, LongestSharedEdge ) )
216 {
217 error->setFixed( method );
218 }
219 else
220 {
221 error->setFixFailed( tr( "Failed to merge with neighbor: %1" ).arg( errMsg ) );
222 }
223 break;
224 }
225
226 case AddToAllowedGaps:
227 {
228 QgsVectorLayer *layer = qobject_cast<QgsVectorLayer *>( mAllowedGapsLayer.data() );
229 if ( layer )
230 {
231 if ( !layer->isEditable() && !layer->startEditing() )
232 {
233 error->setFixFailed( tr( "Could not start editing layer %1" ).arg( layer->name() ) );
234 }
235 else
236 {
237 const QgsFeature feature = QgsVectorLayerUtils::createFeature( layer, error->geometry() );
239 if ( !layer->addFeatures( features ) )
240 {
241 error->setFixFailed( tr( "Could not add feature to layer %1" ).arg( layer->name() ) );
242 }
243 else
244 {
245 error->setFixed( method );
246 }
247 }
248 }
249 else
250 {
251 error->setFixFailed( tr( "Allowed gaps layer could not be resolved" ) );
252 }
253 break;
254 }
255
256 case CreateNewFeature:
257 {
258 QgsGeometryGapCheckError *gapCheckError = static_cast<QgsGeometryGapCheckError *>( error );
259 QgsProject *project = QgsProject::instance();
260 QgsVectorLayer *layer = qobject_cast<QgsVectorLayer *>( project->mapLayer( gapCheckError->neighbors().keys().first() ) );
261 if ( layer )
262 {
263 const QgsGeometry geometry = error->geometry();
266 if ( !layer->addFeature( feature ) )
267 {
268 error->setFixFailed( tr( "Could not add feature" ) );
269 }
270 else
271 {
272 error->setFixed( method );
273 }
274 }
275 else
276 {
277 error->setFixFailed( tr( "Could not resolve target layer %1 to add feature" ).arg( error->layerId() ) );
278 }
279 break;
280 }
281
282 case MergeLargestArea:
283 {
284 QString errMsg;
285 if ( mergeWithNeighbor( featurePools, static_cast<QgsGeometryGapCheckError *>( error ), changes, errMsg, LargestArea ) )
286 {
287 error->setFixed( method );
288 }
289 else
290 {
291 error->setFixFailed( tr( "Failed to merge with neighbor: %1" ).arg( errMsg ) );
292 }
293 break;
294 }
295 }
296 }
297}
298
299bool QgsGeometryGapCheck::mergeWithNeighbor( const QMap<QString, QgsFeaturePool *> &featurePools, QgsGeometryGapCheckError *err, Changes &changes, QString &errMsg, Condition condition ) const
300{
301 double maxVal = 0.;
302 QString mergeLayerId;
303 QgsFeature mergeFeature;
304 int mergePartIdx = -1;
305
306 const QgsGeometry geometry = err->geometry();
307 const QgsAbstractGeometry *errGeometry = QgsGeometryCheckerUtils::getGeomPart( geometry.constGet(), 0 );
308
309 const auto layerIds = err->neighbors().keys();
310 QList<QgsFeature> neighbours;
311
312 // Search for touching neighboring geometries
313 for ( const QString &layerId : layerIds )
314 {
315 QgsFeaturePool *featurePool = featurePools.value( layerId );
316 std::unique_ptr<QgsAbstractGeometry> errLayerGeom( errGeometry->clone() );
317 const QgsCoordinateTransform ct( featurePool->crs(), mContext->mapCrs, mContext->transformContext );
318 errLayerGeom->transform( ct, Qgis::TransformDirection::Reverse );
319
320 const auto featureIds = err->neighbors().value( layerId );
321
322 for ( const QgsFeatureId testId : featureIds )
323 {
324 QgsFeature feature;
325 if ( !featurePool->getFeature( testId, feature ) )
326 {
327 continue;
328 }
329
330 QgsGeometry transformedGeometry = feature.geometry();
331 transformedGeometry.transform( ct );
332 feature.setGeometry( transformedGeometry );
333 neighbours.append( feature );
334 }
335
336 for ( const QgsFeature &testFeature : neighbours )
337 {
338 const QgsGeometry featureGeom = testFeature.geometry();
339 const QgsAbstractGeometry *testGeom = featureGeom.constGet();
340 for ( int iPart = 0, nParts = testGeom->partCount(); iPart < nParts; ++iPart )
341 {
342 double val = 0;
343 switch ( condition )
344 {
345 case LongestSharedEdge:
347 break;
348
349 case LargestArea:
350 // We might get a neighbour where we touch only a corner
352 val = QgsGeometryCheckerUtils::getGeomPart( testGeom, iPart )->area();
353 break;
354 }
355
356 if ( val > maxVal )
357 {
358 maxVal = val;
359 mergeFeature = testFeature;
360 mergePartIdx = iPart;
361 mergeLayerId = layerId;
362 }
363 }
364 }
365 }
366
367 if ( maxVal == 0. )
368 {
369 return false;
370 }
371
372 // Create an index of all neighbouring vertices
373 QgsSpatialIndex neighbourVerticesIndex( QgsSpatialIndex::Flag::FlagStoreFeatureGeometries );
374 int id = 0;
375 for ( const QgsFeature &neighbour : neighbours )
376 {
377 QgsVertexIterator vit = neighbour.geometry().vertices();
378 while ( vit.hasNext() )
379 {
380 const QgsPoint pt = vit.next();
381 QgsFeature f;
382 f.setId( id ); // required for SpatialIndex to return the correct result
383 f.setGeometry( QgsGeometry( pt.clone() ) );
384 neighbourVerticesIndex.addFeature( f );
385 id++;
386 }
387 }
388
389 // Snap to the closest vertex
390 QgsPolyline snappedRing;
391 QgsVertexIterator iterator = errGeometry->vertices();
392 while ( iterator.hasNext() )
393 {
394 const QgsPoint pt = iterator.next();
395 const QgsGeometry closestGeom = neighbourVerticesIndex.geometry( neighbourVerticesIndex.nearestNeighbor( QgsPointXY( pt ) ).first() );
396 if ( !closestGeom.isEmpty() )
397 {
398 snappedRing.append( QgsPoint( closestGeom.vertexAt( 0 ) ) );
399 }
400 }
401
402 std::unique_ptr<QgsPolygon> snappedErrGeom = std::make_unique<QgsPolygon>();
403 snappedErrGeom->setExteriorRing( new QgsLineString( snappedRing ) );
404
405 // Merge geometries
406 QgsFeaturePool *featurePool = featurePools[ mergeLayerId ];
407 std::unique_ptr<QgsAbstractGeometry> errLayerGeom( snappedErrGeom->clone() );
408 const QgsCoordinateTransform ct( featurePool->crs(), mContext->mapCrs, mContext->transformContext );
409 errLayerGeom->transform( ct, Qgis::TransformDirection::Reverse );
410 const QgsGeometry mergeFeatureGeom = mergeFeature.geometry();
411 const QgsAbstractGeometry *mergeGeom = mergeFeatureGeom.constGet();
412 std::unique_ptr< QgsGeometryEngine > geomEngine = QgsGeometryCheckerUtils::createGeomEngine( errLayerGeom.get(), 0 );
413 std::unique_ptr<QgsAbstractGeometry> combinedGeom( geomEngine->combine( QgsGeometryCheckerUtils::getGeomPart( mergeGeom, mergePartIdx ), &errMsg ) );
414 if ( !combinedGeom || combinedGeom->isEmpty() || !QgsWkbTypes::isSingleType( combinedGeom->wkbType() ) )
415 {
416 return false;
417 }
418
419 // Add merged polygon to destination geometry
420 replaceFeatureGeometryPart( featurePools, mergeLayerId, mergeFeature, mergePartIdx, combinedGeom.release(), changes );
421
422 return true;
423}
424
425
427{
428 QStringList methods = QStringList()
429 << tr( "Add gap area to neighboring polygon with longest shared edge" )
430 << tr( "No action" );
431 if ( mAllowedGapsSource )
432 methods << tr( "Add gap to allowed exceptions" );
433
434 return methods;
435}
436
437QList<QgsGeometryCheckResolutionMethod> QgsGeometryGapCheck::availableResolutionMethods() const
438{
439 QList<QgsGeometryCheckResolutionMethod> fixes
440 {
441 QgsGeometryCheckResolutionMethod( MergeLongestEdge, tr( "Add to longest shared edge" ), tr( "Add the gap area to the neighbouring polygon with the longest shared edge." ), false ),
442 QgsGeometryCheckResolutionMethod( CreateNewFeature, tr( "Create new feature" ), tr( "Create a new feature from the gap area." ), false ),
443 QgsGeometryCheckResolutionMethod( MergeLargestArea, tr( "Add to largest neighbouring area" ), tr( "Add the gap area to the neighbouring polygon with the largest area." ), false )
444 };
445
446 if ( mAllowedGapsSource )
447 fixes << QgsGeometryCheckResolutionMethod( AddToAllowedGaps, tr( "Add Gap to Allowed Exceptions" ), tr( "Create a new feature from the gap geometry on the allowed exceptions layer." ), true );
448
449 fixes << QgsGeometryCheckResolutionMethod( NoChange, tr( "No action" ), tr( "Do not perform any action and mark this error as fixed." ), false );
450
451 return fixes;
452}
453
455{
456 return factoryDescription();
457}
458
460{
461 return factoryId();
462}
463
464QgsGeometryCheck::Flags QgsGeometryGapCheck::flags() const
465{
466 return factoryFlags();
467}
468
470QString QgsGeometryGapCheck::factoryDescription()
471{
472 return tr( "Gap" );
473}
474
475QString QgsGeometryGapCheck::factoryId()
476{
477 return QStringLiteral( "QgsGeometryGapCheck" );
478}
479
480QgsGeometryCheck::Flags QgsGeometryGapCheck::factoryFlags()
481{
483}
484
485QList<QgsWkbTypes::GeometryType> QgsGeometryGapCheck::factoryCompatibleGeometryTypes()
486{
488}
489
490bool QgsGeometryGapCheck::factoryIsCompatible( QgsVectorLayer *layer ) SIP_SKIP
491{
492 return factoryCompatibleGeometryTypes().contains( layer->geometryType() );
493}
494
495QgsGeometryCheck::CheckType QgsGeometryGapCheck::factoryCheckType()
496{
498}
500
502{
503 return mContextBoundingBox;
504}
505
507{
508 QgsGeometryGapCheckError *err = dynamic_cast<QgsGeometryGapCheckError *>( other );
510}
511
513{
514 QgsGeometryGapCheckError *err = dynamic_cast<QgsGeometryGapCheckError *>( other );
515 return err && err->layerId() == layerId() && err->neighbors() == neighbors();
516}
517
519{
521 // Static cast since this should only get called if isEqual == true
522 const QgsGeometryGapCheckError *err = static_cast<const QgsGeometryGapCheckError *>( other );
523 mNeighbors = err->mNeighbors;
524 mGapAreaBBox = err->mGapAreaBBox;
525}
526
528{
529 return true;
530}
531
533{
534 return mGapAreaBBox;
535}
536
537QMap<QString, QgsFeatureIds> QgsGeometryGapCheckError::involvedFeatures() const
538{
539 return mNeighbors;
540}
541
543{
544
546 return QgsApplication::getThemeIcon( QStringLiteral( "/algorithms/mAlgorithmCheckGeometry.svg" ) );
547 else
548 return QgsApplication::getThemeIcon( QStringLiteral( "/checks/SliverOrGap.svg" ) );
549}
Abstract base class for all geometries.
QgsVertexIterator vertices() const
Returns a read-only, Java-style iterator for traversal of vertices of all the geometry,...
virtual QgsRectangle boundingBox() const =0
Returns the minimal bounding box for the geometry.
virtual int partCount() const =0
Returns count of parts contained in the geometry.
virtual double area() const
Returns the planar, 2-dimensional area of the geometry.
virtual QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
Class for doing transforms between two map coordinate systems.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
A feature pool is based on a vector layer and caches features.
QgsCoordinateReferenceSystem crs() const
The coordinate reference system of this layer.
bool getFeature(QgsFeatureId id, QgsFeature &feature)
Retrieves the feature with the specified id into feature.
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
void setId(QgsFeatureId id)
Sets the feature id for this feature.
Definition: qgsfeature.cpp:122
QgsGeometry geometry
Definition: qgsfeature.h:67
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:170
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition: qgsfeedback.h:45
double progress() const SIP_HOLDGIL
Returns the current progress reported by the feedback object.
Definition: qgsfeedback.h:80
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
Base configuration for geometry checks.
const QgsProject * project() const
The project can be used to resolve additional layers.
const double reducedTolerance
The tolerance to allow for in geometry checks.
const QgsCoordinateTransformContext transformContext
The coordinate transform context with which transformations will be done.
const QgsCoordinateReferenceSystem mapCrs
The coordinate system in which calculations should be done.
const double tolerance
The tolerance to allow for in geometry checks.
This represents an error reported by a geometry check.
@ StatusFixed
The error is fixed.
Status status() const
The status of the error.
virtual void update(const QgsGeometryCheckError *other)
Update this error with the information from other.
const QgsGeometryCheck * mCheck
void setFixed(int method)
Set the status to fixed and specify the method that has been used to fix the error.
void setFixFailed(const QString &reason)
Set the error status to failed and specify the reason for failure.
QgsGeometry geometry() const
The geometry of the error in map units.
const QString & layerId() const
The id of the layer on which this error has been detected.
const QgsPointXY & location() const
The location of the error in map units.
This class implements a resolution for problems detected in geometry checks.
This class implements a geometry check.
QMap< QString, QMap< QgsFeatureId, QList< QgsGeometryCheck::Change > > > Changes
A collection of changes.
void replaceFeatureGeometryPart(const QMap< QString, QgsFeaturePool * > &featurePools, const QString &layerId, QgsFeature &feature, int partIdx, QgsAbstractGeometry *newPartGeom, Changes &changes) const
Replaces a part in a feature geometry.
const QgsGeometryCheckContext * mContext
@ AvailableInValidation
This geometry check should be available in layer validation on the vector layer peroperties.
CheckType
The type of a check.
@ LayerCheck
The check controls a whole layer (topology checks)
QMap< QString, QgsFeatureIds > allLayerFeatureIds(const QMap< QString, QgsFeaturePool * > &featurePools) const
Returns all layers and feature ids.
const QgsGeometryCheckContext * context() const
Returns the context.
A layer feature combination to uniquely identify and access a feature in a set of layers.
Contains a set of layers and feature ids in those layers to pass to a geometry check.
static std::unique_ptr< QgsGeometryEngine > createGeomEngine(const QgsAbstractGeometry *geometry, double tolerance)
static QgsAbstractGeometry * getGeomPart(QgsAbstractGeometry *geom, int partIdx)
static double sharedEdgeLength(const QgsAbstractGeometry *geom1, const QgsAbstractGeometry *geom2, double tol)
static bool pointsFuzzyEqual(const QgsPointXY &p1, const QgsPointXY &p2, double tol)
Determine whether two points are equal up to the specified tolerance.
An error produced by a QgsGeometryGapCheck.
void update(const QgsGeometryCheckError *other) override
Update this error with the information from other.
QMap< QString, QgsFeatureIds > involvedFeatures() const override
Returns a list of involved features.
bool closeMatch(QgsGeometryCheckError *other) const override
Check if this error is almost equal to other.
QIcon icon() const override
Returns an icon that should be shown for this kind of error.
QgsRectangle affectedAreaBBox() const override
The bounding box of the affected area of the error.
QgsRectangle contextBoundingBox() const override
The context of the error.
bool isEqual(QgsGeometryCheckError *other) const override
Check if this error is equal to other.
bool handleChanges(const QgsGeometryCheck::Changes &) override
Apply a list of changes.
const QMap< QString, QgsFeatureIds > & neighbors() const
A map of layers and feature ids of the neighbors of the gap.
QgsGeometryGapCheck(const QgsGeometryCheckContext *context, const QVariantMap &configuration)
The configuration accepts a "gapThreshold" key which specifies the maximum gap size in squared map un...
QList< QgsWkbTypes::GeometryType > compatibleGeometryTypes() const override
A list of geometry types for which this check can be performed.
void collectErrors(const QMap< QString, QgsFeaturePool * > &featurePools, QList< QgsGeometryCheckError * > &errors, QStringList &messages, QgsFeedback *feedback, const LayerFeatureIds &ids=LayerFeatureIds()) const override
The main worker method.
Q_DECL_DEPRECATED QStringList resolutionMethods() const override
Returns a list of descriptions for available resolutions for errors.
QString description() const override
Returns a human readable description for this check.
void fixError(const QMap< QString, QgsFeaturePool * > &featurePools, QgsGeometryCheckError *error, int method, const QMap< QString, int > &mergeAttributeIndices, Changes &changes) const override
Fixes the error error with the specified method.
void prepare(const QgsGeometryCheckContext *context, const QVariantMap &configuration) override
Will be run in the main thread before collectErrors() is called (which may be run from a background t...
QList< QgsGeometryCheckResolutionMethod > availableResolutionMethods() const override
Returns a list of available resolution methods.
QString id() const override
Returns an id for this check.
ResolutionMethod
Resolution methods for geometry gap checks.
@ CreateNewFeature
Create a new feature with the gap geometry.
@ AddToAllowedGaps
Add gap geometry to allowed gaps layer.
@ MergeLongestEdge
Merge the gap with the polygon with the longest shared edge.
@ NoChange
Do not handle the error.
@ MergeLargestArea
Merge with neighbouring polygon with largest area.
QgsGeometryCheck::Flags flags() const override
Flags for this geometry check.
Java-style iterator for traversal of parts of a geometry.
bool hasNext() const SIP_HOLDGIL
Find out whether there are more parts.
QgsAbstractGeometry * next()
Returns next part of the geometry (undefined behavior if hasNext() returns false before calling next(...
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:125
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
QgsPoint vertexAt(int atVertex) const
Returns coordinates of a vertex.
QgsGeometry buffer(double distance, int segments) const
Returns a buffer region around this geometry having the given width and with a specified number of se...
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:45
QString name
Definition: qgsmaplayer.h:76
A class to represent a 2D point.
Definition: qgspointxy.h:59
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:49
QgsPoint * clone() const override
Clones the geometry by performing a deep copy.
Definition: qgspoint.cpp:104
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition: qgsproject.h:104
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:480
Q_INVOKABLE QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle.
Definition: qgsrectangle.h:391
QgsRectangle snappedToGrid(double spacing) const
Returns a copy of this rectangle that is snapped to a grid with the specified spacing between the gri...
A spatial index for QgsFeature objects.
static QgsFeatureList makeFeatureCompatible(const QgsFeature &feature, const QgsVectorLayer *layer, QgsFeatureSink::SinkFlags sinkFlags=QgsFeatureSink::SinkFlags())
Converts input feature to be compatible with the given layer.
static QgsFeature createFeature(const QgsVectorLayer *layer, const QgsGeometry &geometry=QgsGeometry(), const QgsAttributeMap &attributes=QgsAttributeMap(), QgsExpressionContext *context=nullptr)
Creates a new feature ready for insertion into a layer.
Represents a vector layer which manages a vector based data sets.
Q_INVOKABLE bool startEditing()
Makes the layer editable.
bool addFeatures(QgsFeatureList &features, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) FINAL
Adds a list of features to the sink.
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) FINAL
Adds a single feature to the sink.
Java-style iterator for traversal of vertices of a geometry.
bool hasNext() const
Find out whether there are more vertices.
QgsPoint next()
Returns next vertex of the geometry (undefined behavior if hasNext() returns false before calling nex...
static bool isSingleType(Type type) SIP_HOLDGIL
Returns true if the WKB type is a single type.
Definition: qgswkbtypes.h:852
#define SIP_SKIP
Definition: qgis_sip.h:126
QMap< int, QVariant > QgsAttributeMap
Definition: qgsattributes.h:41
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:917
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28
QList< int > QgsAttributeList
Definition: qgsfield.h:26
QgsPointSequence QgsPolyline
Polyline as represented as a vector of points.
Definition: qgsgeometry.h:72
A list of layers and feature ids for each of these layers.
QMap< QString, QgsFeatureIds > toMap() const