QGIS API Documentation 3.41.0-Master (3440c17df1d)
Loading...
Searching...
No Matches
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"
19#include "moc_qgsgeometrygapcheck.cpp"
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
30QgsGeometryGapCheck::QgsGeometryGapCheck( const QgsGeometryCheckContext *context, const QVariantMap &configuration )
31 : QgsGeometryCheck( context, configuration )
32 , mGapThresholdMapUnits( configuration.value( QStringLiteral( "gapThreshold" ) ).toDouble() )
33{
34}
35
36void QgsGeometryGapCheck::prepare( const QgsGeometryCheckContext *context, const QVariantMap &configuration )
37{
38 if ( configuration.value( QStringLiteral( "allowedGapsEnabled" ) ).toBool() )
39 {
40 QgsVectorLayer *layer = context->project()->mapLayer<QgsVectorLayer *>( configuration.value( "allowedGapsLayer" ).toString() );
41 if ( layer )
42 {
43 mAllowedGapsLayer = layer;
44 mAllowedGapsSource = std::make_unique<QgsVectorLayerFeatureSource>( layer );
45
46 mAllowedGapsBuffer = configuration.value( QStringLiteral( "allowedGapsBuffer" ) ).toDouble();
47 }
48 }
49 else
50 {
51 mAllowedGapsSource.reset();
52 }
53}
54
55void QgsGeometryGapCheck::collectErrors( const QMap<QString, QgsFeaturePool *> &featurePools, QList<QgsGeometryCheckError *> &errors, QStringList &messages, QgsFeedback *feedback, const LayerFeatureIds &ids ) const
56{
57 if ( feedback )
58 feedback->setProgress( feedback->progress() + 1.0 );
59
60 std::unique_ptr<QgsAbstractGeometry> allowedGapsGeom;
61 std::unique_ptr<QgsGeometryEngine> allowedGapsGeomEngine;
62
63 if ( mAllowedGapsSource )
64 {
65 QVector<QgsGeometry> allowedGaps;
66 QgsFeatureRequest request;
68 QgsFeatureIterator iterator = mAllowedGapsSource->getFeatures( request );
69 QgsFeature feature;
70
71 while ( iterator.nextFeature( feature ) )
72 {
73 const QgsGeometry geom = feature.geometry();
74 const QgsGeometry gg = geom.buffer( mAllowedGapsBuffer, 20 );
75 allowedGaps.append( gg );
76 }
77
78 std::unique_ptr< QgsGeometryEngine > allowedGapsEngine( QgsGeometry::createGeometryEngine( nullptr, mContext->tolerance ) );
79
80 // Create union of allowed gaps
81 QString errMsg;
82 allowedGapsGeom.reset( allowedGapsEngine->combine( allowedGaps, &errMsg ) );
83 allowedGapsGeomEngine.reset( QgsGeometry::createGeometryEngine( allowedGapsGeom.get(), mContext->tolerance ) );
84 allowedGapsGeomEngine->prepareGeometry();
85 }
86
87 QVector<QgsGeometry> geomList;
88 const QMap<QString, QgsFeatureIds> featureIds = ids.isEmpty() ? allLayerFeatureIds( featurePools ) : ids.toMap();
89 const QgsGeometryCheckerUtils::LayerFeatures layerFeatures( featurePools, featureIds, compatibleGeometryTypes(), nullptr, mContext, true );
90 for ( const QgsGeometryCheckerUtils::LayerFeature &layerFeature : layerFeatures )
91 {
92 geomList.append( layerFeature.geometry() );
93
94 if ( feedback && feedback->isCanceled() )
95 {
96 geomList.clear();
97 break;
98 }
99 }
100
101 if ( geomList.isEmpty() )
102 {
103 return;
104 }
105
106 std::unique_ptr< QgsGeometryEngine > geomEngine( QgsGeometry::createGeometryEngine( nullptr, mContext->tolerance ) );
107
108 // Create union of geometry
109 QString errMsg;
110 const std::unique_ptr<QgsAbstractGeometry> unionGeom( geomEngine->combine( geomList, &errMsg ) );
111 if ( !unionGeom )
112 {
113 messages.append( tr( "Gap check: %1" ).arg( errMsg ) );
114 return;
115 }
116
117 // Get envelope of union
118 geomEngine.reset( QgsGeometry::createGeometryEngine( unionGeom.get(), mContext->tolerance ) );
119 geomEngine->prepareGeometry();
120 std::unique_ptr<QgsAbstractGeometry> envelope( geomEngine->envelope( &errMsg ) );
121 if ( !envelope )
122 {
123 messages.append( tr( "Gap check: %1" ).arg( errMsg ) );
124 return;
125 }
126
127 // Buffer envelope
128 geomEngine.reset( QgsGeometry::createGeometryEngine( envelope.get(), mContext->tolerance ) );
129 geomEngine->prepareGeometry();
130 QgsAbstractGeometry *bufEnvelope = geomEngine->buffer( 2, 0, Qgis::EndCapStyle::Square, Qgis::JoinStyle::Miter, 4. ); //#spellok //#spellok
131 envelope.reset( bufEnvelope );
132
133 // Compute difference between envelope and union to obtain gap polygons
134 geomEngine.reset( QgsGeometry::createGeometryEngine( envelope.get(), mContext->tolerance ) );
135 geomEngine->prepareGeometry();
136 std::unique_ptr<QgsAbstractGeometry> diffGeom( geomEngine->difference( unionGeom.get(), &errMsg ) );
137 if ( !diffGeom )
138 {
139 messages.append( tr( "Gap check: %1" ).arg( errMsg ) );
140 return;
141 }
142
143 // For each gap polygon which does not lie on the boundary, get neighboring polygons and add error
144 QgsGeometryPartIterator parts = diffGeom->parts();
145 while ( parts.hasNext() )
146 {
147 const QgsAbstractGeometry *gapGeom = parts.next();
148 // Skip the gap between features and boundingbox
149 const double spacing = context()->tolerance;
150 if ( gapGeom->boundingBox().snappedToGrid( spacing ) == envelope->boundingBox().snappedToGrid( spacing ) )
151 {
152 continue;
153 }
154
155 // Skip gaps above threshold
156 if ( ( mGapThresholdMapUnits > 0 && gapGeom->area() > mGapThresholdMapUnits ) || gapGeom->area() < mContext->reducedTolerance )
157 {
158 continue;
159 }
160
161 QgsRectangle gapAreaBBox = gapGeom->boundingBox();
162
163 // Get neighboring polygons
164 QMap<QString, QgsFeatureIds> neighboringIds;
165 const QgsGeometryCheckerUtils::LayerFeatures layerFeatures( featurePools, featureIds.keys(), gapAreaBBox, compatibleGeometryTypes(), mContext );
166 std::unique_ptr< QgsGeometryEngine > gapGeomEngine( QgsGeometry::createGeometryEngine( gapGeom, mContext->tolerance ) );
167 gapGeomEngine->prepareGeometry();
168 for ( const QgsGeometryCheckerUtils::LayerFeature &layerFeature : layerFeatures )
169 {
170 const QgsGeometry geom = layerFeature.geometry();
171 if ( gapGeomEngine->distance( geom.constGet() ) < mContext->tolerance )
172 {
173 neighboringIds[layerFeature.layer()->id()].insert( layerFeature.feature().id() );
174 gapAreaBBox.combineExtentWith( geom.boundingBox() );
175 }
176 }
177
178 if ( neighboringIds.isEmpty() )
179 {
180 continue;
181 }
182
183 if ( allowedGapsGeomEngine && allowedGapsGeomEngine->contains( gapGeom ) )
184 {
185 continue;
186 }
187
188 // Add error
189 const double area = gapGeom->area();
190 const QgsRectangle gapBbox = gapGeom->boundingBox();
191 errors.append( new QgsGeometryGapCheckError( this, QString(), QgsGeometry( gapGeom->clone() ), neighboringIds, area, gapBbox, gapAreaBBox ) );
192 }
193}
194
195void QgsGeometryGapCheck::fixError( const QMap<QString, QgsFeaturePool *> &featurePools, QgsGeometryCheckError *error, int method, const QMap<QString, int> & /*mergeAttributeIndices*/, Changes &changes ) const
196{
197 const QMetaEnum metaEnum = QMetaEnum::fromType<QgsGeometryGapCheck::ResolutionMethod>();
198 if ( !metaEnum.isValid() || !metaEnum.valueToKey( method ) )
199 {
200 error->setFixFailed( tr( "Unknown method" ) );
201 }
202 else
203 {
204 const ResolutionMethod methodValue = static_cast<ResolutionMethod>( method );
205 switch ( methodValue )
206 {
207 case NoChange:
208 error->setFixed( method );
209 break;
210
211 case MergeLongestEdge:
212 {
213 QString errMsg;
214 if ( mergeWithNeighbor( featurePools, static_cast<QgsGeometryGapCheckError *>( error ), changes, errMsg, LongestSharedEdge ) )
215 {
216 error->setFixed( method );
217 }
218 else
219 {
220 error->setFixFailed( tr( "Failed to merge with neighbor: %1" ).arg( errMsg ) );
221 }
222 break;
223 }
224
225 case AddToAllowedGaps:
226 {
227 QgsVectorLayer *layer = qobject_cast<QgsVectorLayer *>( mAllowedGapsLayer.data() );
228 if ( layer )
229 {
230 if ( !layer->isEditable() && !layer->startEditing() )
231 {
232 error->setFixFailed( tr( "Could not start editing layer %1" ).arg( layer->name() ) );
233 }
234 else
235 {
236 const QgsFeature feature = QgsVectorLayerUtils::createFeature( layer, error->geometry() );
238 if ( !layer->addFeatures( features ) )
239 {
240 error->setFixFailed( tr( "Could not add feature to layer %1" ).arg( layer->name() ) );
241 }
242 else
243 {
244 error->setFixed( method );
245 }
246 }
247 }
248 else
249 {
250 error->setFixFailed( tr( "Allowed gaps layer could not be resolved" ) );
251 }
252 break;
253 }
254
255 case CreateNewFeature:
256 {
257 QgsGeometryGapCheckError *gapCheckError = static_cast<QgsGeometryGapCheckError *>( error );
258 QgsProject *project = QgsProject::instance();
259 QgsVectorLayer *layer = qobject_cast<QgsVectorLayer *>( project->mapLayer( gapCheckError->neighbors().keys().first() ) );
260 if ( layer )
261 {
262 const QgsGeometry geometry = error->geometry();
265 if ( !layer->addFeature( feature ) )
266 {
267 error->setFixFailed( tr( "Could not add feature" ) );
268 }
269 else
270 {
271 error->setFixed( method );
272 }
273 }
274 else
275 {
276 error->setFixFailed( tr( "Could not resolve target layer %1 to add feature" ).arg( error->layerId() ) );
277 }
278 break;
279 }
280
281 case MergeLargestArea:
282 {
283 QString errMsg;
284 if ( mergeWithNeighbor( featurePools, static_cast<QgsGeometryGapCheckError *>( error ), changes, errMsg, LargestArea ) )
285 {
286 error->setFixed( method );
287 }
288 else
289 {
290 error->setFixFailed( tr( "Failed to merge with neighbor: %1" ).arg( errMsg ) );
291 }
292 break;
293 }
294 }
295 }
296}
297
298bool QgsGeometryGapCheck::mergeWithNeighbor( const QMap<QString, QgsFeaturePool *> &featurePools, QgsGeometryGapCheckError *err, Changes &changes, QString &errMsg, Condition condition ) const
299{
300 double maxVal = 0.;
301 QString mergeLayerId;
302 QgsFeature mergeFeature;
303 int mergePartIdx = -1;
304
305 const QgsGeometry geometry = err->geometry();
306 const QgsAbstractGeometry *errGeometry = QgsGeometryCheckerUtils::getGeomPart( geometry.constGet(), 0 );
307
308 const auto layerIds = err->neighbors().keys();
309 QList<QgsFeature> neighbours;
310
311 // Search for touching neighboring geometries
312 for ( const QString &layerId : layerIds )
313 {
314 QgsFeaturePool *featurePool = featurePools.value( layerId );
315 std::unique_ptr<QgsAbstractGeometry> errLayerGeom( errGeometry->clone() );
316 const QgsCoordinateTransform ct( featurePool->crs(), mContext->mapCrs, mContext->transformContext );
317 errLayerGeom->transform( ct, Qgis::TransformDirection::Reverse );
318
319 const auto featureIds = err->neighbors().value( layerId );
320
321 for ( const QgsFeatureId testId : featureIds )
322 {
323 QgsFeature feature;
324 if ( !featurePool->getFeature( testId, feature ) )
325 {
326 continue;
327 }
328
329 QgsGeometry transformedGeometry = feature.geometry();
330 transformedGeometry.transform( ct );
331 feature.setGeometry( transformedGeometry );
332 neighbours.append( feature );
333 }
334
335 for ( const QgsFeature &testFeature : neighbours )
336 {
337 const QgsGeometry featureGeom = testFeature.geometry();
338 const QgsAbstractGeometry *testGeom = featureGeom.constGet();
339 for ( int iPart = 0, nParts = testGeom->partCount(); iPart < nParts; ++iPart )
340 {
341 double val = 0;
342 switch ( condition )
343 {
344 case LongestSharedEdge:
346 break;
347
348 case LargestArea:
349 // We might get a neighbour where we touch only a corner
351 val = QgsGeometryCheckerUtils::getGeomPart( testGeom, iPart )->area();
352 break;
353 }
354
355 if ( val > maxVal )
356 {
357 maxVal = val;
358 mergeFeature = testFeature;
359 mergePartIdx = iPart;
360 mergeLayerId = layerId;
361 }
362 }
363 }
364 }
365
366 if ( maxVal == 0. )
367 {
368 return false;
369 }
370
371 // Create an index of all neighbouring vertices
373 int id = 0;
374 for ( const QgsFeature &neighbour : neighbours )
375 {
376 QgsVertexIterator vit = neighbour.geometry().vertices();
377 while ( vit.hasNext() )
378 {
379 const QgsPoint pt = vit.next();
380 QgsFeature f;
381 f.setId( id ); // required for SpatialIndex to return the correct result
382 f.setGeometry( QgsGeometry( pt.clone() ) );
383 neighbourVerticesIndex.addFeature( f );
384 id++;
385 }
386 }
387
388 // Snap to the closest vertex
389 QgsPolyline snappedRing;
390 QgsVertexIterator iterator = errGeometry->vertices();
391 while ( iterator.hasNext() )
392 {
393 const QgsPoint pt = iterator.next();
394 const QgsGeometry closestGeom = neighbourVerticesIndex.geometry( neighbourVerticesIndex.nearestNeighbor( QgsPointXY( pt ) ).first() );
395 if ( !closestGeom.isEmpty() )
396 {
397 snappedRing.append( QgsPoint( closestGeom.vertexAt( 0 ) ) );
398 }
399 }
400
401 std::unique_ptr<QgsPolygon> snappedErrGeom = std::make_unique<QgsPolygon>();
402 snappedErrGeom->setExteriorRing( new QgsLineString( snappedRing ) );
403
404 // Merge geometries
405 QgsFeaturePool *featurePool = featurePools[ mergeLayerId ];
406 std::unique_ptr<QgsAbstractGeometry> errLayerGeom( snappedErrGeom->clone() );
407 const QgsCoordinateTransform ct( featurePool->crs(), mContext->mapCrs, mContext->transformContext );
408 errLayerGeom->transform( ct, Qgis::TransformDirection::Reverse );
409 const QgsGeometry mergeFeatureGeom = mergeFeature.geometry();
410 const QgsAbstractGeometry *mergeGeom = mergeFeatureGeom.constGet();
411 std::unique_ptr< QgsGeometryEngine > geomEngine( QgsGeometry::createGeometryEngine( errLayerGeom.get(), 0 ) );
412 std::unique_ptr<QgsAbstractGeometry> combinedGeom( geomEngine->combine( QgsGeometryCheckerUtils::getGeomPart( mergeGeom, mergePartIdx ), &errMsg ) );
413 if ( !combinedGeom || combinedGeom->isEmpty() || !QgsWkbTypes::isSingleType( combinedGeom->wkbType() ) )
414 {
415 return false;
416 }
417
418 // Add merged polygon to destination geometry
419 replaceFeatureGeometryPart( featurePools, mergeLayerId, mergeFeature, mergePartIdx, combinedGeom.release(), changes );
420
421 return true;
422}
423
424
426{
427 QStringList methods = QStringList()
428 << tr( "Add gap area to neighboring polygon with longest shared edge" )
429 << tr( "No action" );
430 if ( mAllowedGapsSource )
431 methods << tr( "Add gap to allowed exceptions" );
432
433 return methods;
434}
435
436QList<QgsGeometryCheckResolutionMethod> QgsGeometryGapCheck::availableResolutionMethods() const
437{
438 QList<QgsGeometryCheckResolutionMethod> fixes
439 {
440 QgsGeometryCheckResolutionMethod( MergeLongestEdge, tr( "Add to longest shared edge" ), tr( "Add the gap area to the neighbouring polygon with the longest shared edge." ), false ),
441 QgsGeometryCheckResolutionMethod( CreateNewFeature, tr( "Create new feature" ), tr( "Create a new feature from the gap area." ), false ),
442 QgsGeometryCheckResolutionMethod( MergeLargestArea, tr( "Add to largest neighbouring area" ), tr( "Add the gap area to the neighbouring polygon with the largest area." ), false )
443 };
444
445 if ( mAllowedGapsSource )
446 fixes << QgsGeometryCheckResolutionMethod( AddToAllowedGaps, tr( "Add Gap to Allowed Exceptions" ), tr( "Create a new feature from the gap geometry on the allowed exceptions layer." ), true );
447
448 fixes << QgsGeometryCheckResolutionMethod( NoChange, tr( "No action" ), tr( "Do not perform any action and mark this error as fixed." ), false );
449
450 return fixes;
451}
452
454{
455 return factoryDescription();
456}
457
459{
460 return factoryId();
461}
462
464{
465 return factoryFlags();
466}
467
469QString QgsGeometryGapCheck::factoryDescription()
470{
471 return tr( "Gap" );
472}
473
474QString QgsGeometryGapCheck::factoryId()
475{
476 return QStringLiteral( "QgsGeometryGapCheck" );
477}
478
479QgsGeometryCheck::Flags QgsGeometryGapCheck::factoryFlags()
480{
482}
483
484QList<Qgis::GeometryType> QgsGeometryGapCheck::factoryCompatibleGeometryTypes()
485{
487}
488
489bool QgsGeometryGapCheck::factoryIsCompatible( QgsVectorLayer *layer ) SIP_SKIP
490{
491 return factoryCompatibleGeometryTypes().contains( layer->geometryType() );
492}
493
494QgsGeometryCheck::CheckType QgsGeometryGapCheck::factoryCheckType()
495{
497}
499
501{
502 return mContextBoundingBox;
503}
504
506{
507 QgsGeometryGapCheckError *err = dynamic_cast<QgsGeometryGapCheckError *>( other );
508 return err && err->location().distanceCompare( location(), mCheck->context()->reducedTolerance ) && err->neighbors() == neighbors();
509}
510
512{
513 QgsGeometryGapCheckError *err = dynamic_cast<QgsGeometryGapCheckError *>( other );
514 return err && err->layerId() == layerId() && err->neighbors() == neighbors();
515}
516
518{
520 // Static cast since this should only get called if isEqual == true
521 const QgsGeometryGapCheckError *err = static_cast<const QgsGeometryGapCheckError *>( other );
522 mNeighbors = err->mNeighbors;
523 mGapAreaBBox = err->mGapAreaBBox;
524}
525
530
532{
533 return mGapAreaBBox;
534}
535
536QMap<QString, QgsFeatureIds> QgsGeometryGapCheckError::involvedFeatures() const
537{
538 return mNeighbors;
539}
540
542{
543
545 return QgsApplication::getThemeIcon( QStringLiteral( "/algorithms/mAlgorithmCheckGeometry.svg" ) );
546 else
547 return QgsApplication::getThemeIcon( QStringLiteral( "/checks/SliverOrGap.svg" ) );
548}
@ Polygon
Polygons.
@ Miter
Use mitered joins.
@ Square
Square cap (extends past start/end of line by buffer distance)
@ Reverse
Reverse/inverse transform (from destination to source)
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
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)
Fetch next feature and stores in f, returns true on success.
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:58
void setId(QgsFeatureId id)
Sets the feature id for this feature.
QgsGeometry geometry
Definition qgsfeature.h:69
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition qgsfeedback.h:44
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:53
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition qgsfeedback.h:61
double progress() const
Returns the current progress reported by the feedback object.
Definition qgsfeedback.h:77
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.
QFlags< Flag > Flags
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 QgsAbstractGeometry * getGeomPart(QgsAbstractGeometry *geom, int partIdx)
static double sharedEdgeLength(const QgsAbstractGeometry *geom1, const QgsAbstractGeometry *geom2, double tol)
An error produced by a QgsGeometryGapCheck.
QgsRectangle contextBoundingBox() const override
The context of the error.
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.
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...
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.
QList< Qgis::GeometryType > compatibleGeometryTypes() const override
A list of geometry types for which this check can be performed.
QgsGeometryCheck::Flags flags() const override
Flags for this geometry check.
Java-style iterator for traversal of parts of a geometry.
bool hasNext() const
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.
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false)
Transforms this geometry as described by the coordinate transform ct.
QgsPoint vertexAt(int atVertex) const
Returns coordinates of a vertex.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
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.
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...
Line string geometry type, with support for z-dimension and m-values.
QString name
Definition qgsmaplayer.h:80
A class to represent a 2D point.
Definition qgspointxy.h:60
bool distanceCompare(const QgsPointXY &other, double epsilon=4 *std::numeric_limits< double >::epsilon()) const
Compares this point with another point with a fuzzy tolerance using distance comparison.
Definition qgspointxy.h:268
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:105
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition qgsproject.h:107
static QgsProject * instance()
Returns the QgsProject singleton instance.
Q_INVOKABLE QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
A rectangle specified with double values.
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle.
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.
@ FlagStoreFeatureGeometries
Indicates that the spatial index should also store feature geometries. This requires more memory,...
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(Qgis::WkbType type)
Returns true if the WKB type is a single type.
#define SIP_SKIP
Definition qgis_sip.h:126
QMap< int, QVariant > QgsAttributeMap
QList< QgsFeature > QgsFeatureList
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
QList< int > QgsAttributeList
Definition qgsfield.h:27
QgsPointSequence QgsPolyline
Polyline as represented as a vector of points.
Definition qgsgeometry.h:70
A list of layers and feature ids for each of these layers.
QMap< QString, QgsFeatureIds > toMap() const