QGIS API Documentation 3.99.0-Master (d270888f95f)
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
16#include "qgsgeometrygapcheck.h"
17
18#include "qgsapplication.h"
19#include "qgscurve.h"
21#include "qgsfeaturepool.h"
22#include "qgsfeedback.h"
24#include "qgsgeometryengine.h"
25#include "qgspolygon.h"
26#include "qgsproject.h"
27#include "qgsvectorlayer.h"
28#include "qgsvectorlayerutils.h"
29
30#include <QString>
31
32#include "moc_qgsgeometrygapcheck.cpp"
33
34using namespace Qt::StringLiterals;
35
37 : QgsGeometryCheck( context, configuration )
38 , mGapThresholdMapUnits( configuration.value( u"gapThreshold"_s ).toDouble() )
39{
40}
41
42void QgsGeometryGapCheck::prepare( const QgsGeometryCheckContext *context, const QVariantMap &configuration )
43{
44 if ( configuration.value( u"allowedGapsEnabled"_s ).toBool() )
45 {
46 QgsVectorLayer *layer = context->project()->mapLayer<QgsVectorLayer *>( configuration.value( "allowedGapsLayer" ).toString() );
47 if ( layer )
48 {
49 mAllowedGapsLayer = layer;
50 mAllowedGapsSource = std::make_unique<QgsVectorLayerFeatureSource>( layer );
51
52 mAllowedGapsBuffer = configuration.value( u"allowedGapsBuffer"_s ).toDouble();
53 }
54 }
55 else
56 {
57 mAllowedGapsSource.reset();
58 }
59}
60
61QgsGeometryCheck::Result QgsGeometryGapCheck::collectErrors( const QMap<QString, QgsFeaturePool *> &featurePools, QList<QgsGeometryCheckError *> &errors, QStringList &messages, QgsFeedback *feedback, const LayerFeatureIds &ids ) const
62{
63 if ( feedback )
64 feedback->setProgress( feedback->progress() + 1.0 );
65
66 std::unique_ptr<QgsAbstractGeometry> allowedGapsGeom;
67 std::unique_ptr<QgsGeometryEngine> allowedGapsGeomEngine;
68
69 if ( mAllowedGapsSource )
70 {
71 QVector<QgsGeometry> allowedGaps;
72 QgsFeatureRequest request;
74 QgsFeatureIterator iterator = mAllowedGapsSource->getFeatures( request );
75 QgsFeature feature;
76
77 while ( iterator.nextFeature( feature ) )
78 {
79 if ( feedback && feedback->isCanceled() )
80 {
82 }
83
84 const QgsGeometry geom = feature.geometry();
85 const QgsGeometry gg = geom.buffer( mAllowedGapsBuffer, 20 );
86 allowedGaps.append( gg );
87 }
88
89 std::unique_ptr<QgsGeometryEngine> allowedGapsEngine( QgsGeometry::createGeometryEngine( nullptr, mContext->tolerance ) );
90
91 // Create union of allowed gaps
92 QString errMsg;
93 allowedGapsGeom.reset( allowedGapsEngine->combine( allowedGaps, &errMsg ) );
94 allowedGapsGeomEngine.reset( QgsGeometry::createGeometryEngine( allowedGapsGeom.get(), mContext->tolerance ) );
95 allowedGapsGeomEngine->prepareGeometry();
96 }
97
98 QVector<QgsGeometry> geomList;
99 QMap<QString, QSet<QVariant>> uniqueIds;
100 const QMap<QString, QgsFeatureIds> featureIds = ids.isEmpty() ? allLayerFeatureIds( featurePools ) : ids.toMap();
101 const QgsGeometryCheckerUtils::LayerFeatures layerFeatures( featurePools, featureIds, compatibleGeometryTypes(), nullptr, mContext, true );
102 for ( const QgsGeometryCheckerUtils::LayerFeature &layerFeature : layerFeatures )
103 {
104 if ( feedback && feedback->isCanceled() )
105 {
107 }
108
109 if ( context()->uniqueIdFieldIndex != -1 )
110 {
111 QgsGeometryCheck::Result result = checkUniqueId( layerFeature, uniqueIds );
112 if ( result != QgsGeometryCheck::Result::Success )
113 {
114 return result;
115 }
116 }
117
118 geomList.append( layerFeature.geometry() );
119 }
120
121 std::unique_ptr<QgsGeometryEngine> geomEngine( QgsGeometry::createGeometryEngine( nullptr, mContext->tolerance ) );
122
123 // Create union of geometry
124 QString errMsg;
125 const std::unique_ptr<QgsAbstractGeometry> unionGeom( geomEngine->combine( geomList, &errMsg ) );
126 if ( !unionGeom )
127 {
128 messages.append( tr( "Gap check: %1" ).arg( errMsg ) );
130 }
131
132 // Get envelope of union
133 geomEngine.reset( QgsGeometry::createGeometryEngine( unionGeom.get(), mContext->tolerance ) );
134 geomEngine->prepareGeometry();
135 std::unique_ptr<QgsAbstractGeometry> envelope( geomEngine->envelope( &errMsg ) );
136 if ( !envelope )
137 {
138 messages.append( tr( "Gap check: %1" ).arg( errMsg ) );
140 }
141
142 // Buffer envelope
143 geomEngine.reset( QgsGeometry::createGeometryEngine( envelope.get(), mContext->tolerance ) );
144 geomEngine->prepareGeometry();
145 QgsAbstractGeometry *bufEnvelope = geomEngine->buffer( 2, 0, Qgis::EndCapStyle::Square, Qgis::JoinStyle::Miter, 4. ); //#spellok //#spellok
146 envelope.reset( bufEnvelope );
147
148 // Compute difference between envelope and union to obtain gap polygons
149 geomEngine.reset( QgsGeometry::createGeometryEngine( envelope.get(), mContext->tolerance ) );
150 geomEngine->prepareGeometry();
151 std::unique_ptr<QgsAbstractGeometry> diffGeom( geomEngine->difference( unionGeom.get(), &errMsg ) );
152 if ( !diffGeom )
153 {
154 messages.append( tr( "Gap check: %1" ).arg( errMsg ) );
156 }
157
158 // For each gap polygon which does not lie on the boundary, get neighboring polygons and add error
159 QgsGeometryPartIterator parts = diffGeom->parts();
160 while ( parts.hasNext() )
161 {
162 if ( feedback && feedback->isCanceled() )
163 {
165 }
166
167 const QgsAbstractGeometry *gapGeom = parts.next();
168 // Skip the gap between features and boundingbox
169 const double spacing = context()->tolerance;
170 if ( gapGeom->boundingBox().snappedToGrid( spacing ) == envelope->boundingBox().snappedToGrid( spacing ) )
171 {
172 continue;
173 }
174
175 // Skip gaps above threshold
176 if ( ( mGapThresholdMapUnits > 0 && gapGeom->area() > mGapThresholdMapUnits ) || gapGeom->area() < mContext->reducedTolerance )
177 {
178 continue;
179 }
180
181 QgsRectangle gapAreaBBox = gapGeom->boundingBox();
182
183 // Get neighboring polygons
184 QMap<QString, QgsFeatureIds> neighboringIds;
185 const QgsGeometryCheckerUtils::LayerFeatures layerFeatures( featurePools, featureIds.keys(), gapAreaBBox, compatibleGeometryTypes(), mContext );
186 std::unique_ptr<QgsGeometryEngine> gapGeomEngine( QgsGeometry::createGeometryEngine( gapGeom, mContext->tolerance ) );
187 gapGeomEngine->prepareGeometry();
188 for ( const QgsGeometryCheckerUtils::LayerFeature &layerFeature : layerFeatures )
189 {
190 if ( feedback && feedback->isCanceled() )
191 {
193 }
194
195 const QgsGeometry geom = layerFeature.geometry();
196 if ( gapGeomEngine->distance( geom.constGet() ) < mContext->tolerance )
197 {
198 neighboringIds[layerFeature.layer()->id()].insert( layerFeature.feature().id() );
199 gapAreaBBox.combineExtentWith( geom.boundingBox() );
200 }
201 }
202
203 if ( neighboringIds.isEmpty() )
204 {
205 continue;
206 }
207
208 if ( allowedGapsGeomEngine && allowedGapsGeomEngine->contains( gapGeom ) )
209 {
210 continue;
211 }
212
213 // Add error
214 const double area = gapGeom->area();
215 const QgsRectangle gapBbox = gapGeom->boundingBox();
216 errors.append( new QgsGeometryGapCheckError( this, QString(), QgsGeometry( gapGeom->clone() ), neighboringIds, area, gapBbox, gapAreaBBox ) );
217 }
219}
220
221void QgsGeometryGapCheck::fixError( const QMap<QString, QgsFeaturePool *> &featurePools, QgsGeometryCheckError *error, int method, const QMap<QString, int> & /*mergeAttributeIndices*/, Changes &changes ) const
222{
223 const QMetaEnum metaEnum = QMetaEnum::fromType<QgsGeometryGapCheck::ResolutionMethod>();
224 if ( !metaEnum.isValid() || !metaEnum.valueToKey( method ) )
225 {
226 error->setFixFailed( tr( "Unknown method" ) );
227 }
228 else
229 {
230 const ResolutionMethod methodValue = static_cast<ResolutionMethod>( method );
231 switch ( methodValue )
232 {
233 case NoChange:
234 error->setFixed( method );
235 break;
236
237 case MergeLongestEdge:
238 {
239 QString errMsg;
240 if ( mergeWithNeighbor( featurePools, static_cast<QgsGeometryGapCheckError *>( error ), changes, errMsg, LongestSharedEdge ) )
241 {
242 error->setFixed( method );
243 }
244 else
245 {
246 error->setFixFailed( tr( "Failed to merge with neighbor: %1" ).arg( errMsg ) );
247 }
248 break;
249 }
250
251 case AddToAllowedGaps:
252 {
253 QgsVectorLayer *layer = qobject_cast<QgsVectorLayer *>( mAllowedGapsLayer.data() );
254 if ( layer )
255 {
256 if ( !layer->isEditable() && !layer->startEditing() )
257 {
258 error->setFixFailed( tr( "Could not start editing layer %1" ).arg( layer->name() ) );
259 }
260 else
261 {
262 const QgsFeature feature = QgsVectorLayerUtils::createFeature( layer, error->geometry() );
264 if ( !layer->addFeatures( features ) )
265 {
266 error->setFixFailed( tr( "Could not add feature to layer %1" ).arg( layer->name() ) );
267 }
268 else
269 {
270 error->setFixed( method );
271 }
272 }
273 }
274 else
275 {
276 error->setFixFailed( tr( "Allowed gaps layer could not be resolved" ) );
277 }
278 break;
279 }
280
281 case CreateNewFeature:
282 {
283 QgsGeometryGapCheckError *gapCheckError = static_cast<QgsGeometryGapCheckError *>( error );
284 QgsVectorLayer *layer = qobject_cast<QgsVectorLayer *>( context()->project()->mapLayer( gapCheckError->neighbors().keys().first() ) );
285 if ( layer )
286 {
287 const QgsGeometry geometry = error->geometry();
290 if ( !layer->addFeature( feature ) )
291 {
292 error->setFixFailed( tr( "Could not add feature" ) );
293 }
294 else
295 {
296 error->setFixed( method );
297 }
298 }
299 else
300 {
301 error->setFixFailed( tr( "Could not resolve target layer %1 to add feature" ).arg( error->layerId() ) );
302 }
303 break;
304 }
305
306 case MergeLargestArea:
307 {
308 QString errMsg;
309 if ( mergeWithNeighbor( featurePools, static_cast<QgsGeometryGapCheckError *>( error ), changes, errMsg, LargestArea ) )
310 {
311 error->setFixed( method );
312 }
313 else
314 {
315 error->setFixFailed( tr( "Failed to merge with neighbor: %1" ).arg( errMsg ) );
316 }
317 break;
318 }
319 }
320 }
321}
322
323bool QgsGeometryGapCheck::mergeWithNeighbor( const QMap<QString, QgsFeaturePool *> &featurePools, QgsGeometryGapCheckError *err, Changes &changes, QString &errMsg, Condition condition ) const
324{
325 double maxVal = 0.;
326 QString mergeLayerId;
327 QgsFeature mergeFeature;
328 int mergePartIdx = -1;
329
330 const QgsGeometry geometry = err->geometry();
331 const QgsAbstractGeometry *errGeometry = QgsGeometryCheckerUtils::getGeomPart( geometry.constGet(), 0 );
332
333 const auto layerIds = err->neighbors().keys();
334 QList<QgsFeature> neighbours;
335
336 // Search for touching neighboring geometries
337 for ( const QString &layerId : layerIds )
338 {
339 QgsFeaturePool *featurePool = featurePools.value( layerId );
340 if ( !featurePool )
341 {
342 return false;
343 }
344 std::unique_ptr<QgsAbstractGeometry> errLayerGeom( errGeometry->clone() );
345 const QgsCoordinateTransform ct( featurePool->crs(), mContext->mapCrs, mContext->transformContext );
346 errLayerGeom->transform( ct, Qgis::TransformDirection::Reverse );
347
348 const auto featureIds = err->neighbors().value( layerId );
349
350 for ( const QgsFeatureId testId : featureIds )
351 {
352 QgsFeature feature;
353 if ( !featurePool->getFeature( testId, feature ) )
354 {
355 continue;
356 }
357
358 QgsGeometry transformedGeometry = feature.geometry();
359 transformedGeometry.transform( ct );
360 feature.setGeometry( transformedGeometry );
361 neighbours.append( feature );
362 }
363
364 for ( const QgsFeature &testFeature : neighbours )
365 {
366 const QgsGeometry featureGeom = testFeature.geometry();
367 const QgsAbstractGeometry *testGeom = featureGeom.constGet();
368 for ( int iPart = 0, nParts = testGeom->partCount(); iPart < nParts; ++iPart )
369 {
370 double val = 0;
371 switch ( condition )
372 {
373 case LongestSharedEdge:
374 val = QgsGeometryCheckerUtils::sharedEdgeLength( errLayerGeom.get(), QgsGeometryCheckerUtils::getGeomPart( testGeom, iPart ), mContext->reducedTolerance );
375 break;
376
377 case LargestArea:
378 // We might get a neighbour where we touch only a corner
379 if ( QgsGeometryCheckerUtils::sharedEdgeLength( errLayerGeom.get(), QgsGeometryCheckerUtils::getGeomPart( testGeom, iPart ), mContext->reducedTolerance ) > 0 )
380 val = QgsGeometryCheckerUtils::getGeomPart( testGeom, iPart )->area();
381 break;
382 }
383
384 if ( val > maxVal )
385 {
386 maxVal = val;
387 mergeFeature = testFeature;
388 mergePartIdx = iPart;
389 mergeLayerId = layerId;
390 }
391 }
392 }
393 }
394
395 if ( maxVal == 0. )
396 {
397 return false;
398 }
399
400 // Create an index of all neighbouring vertices
401 QgsSpatialIndex neighbourVerticesIndex( QgsSpatialIndex::Flag::FlagStoreFeatureGeometries );
402 int id = 0;
403 for ( const QgsFeature &neighbour : neighbours )
404 {
405 QgsVertexIterator vit = neighbour.geometry().vertices();
406 while ( vit.hasNext() )
407 {
408 const QgsPoint pt = vit.next();
409 QgsFeature f;
410 f.setId( id ); // required for SpatialIndex to return the correct result
411 f.setGeometry( QgsGeometry( pt.clone() ) );
412 neighbourVerticesIndex.addFeature( f );
413 id++;
414 }
415 }
416
417 // Snap to the closest vertex
418 QgsPolyline snappedRing;
419 QgsVertexIterator iterator = errGeometry->vertices();
420 while ( iterator.hasNext() )
421 {
422 const QgsPoint pt = iterator.next();
423 const QgsGeometry closestGeom = neighbourVerticesIndex.geometry( neighbourVerticesIndex.nearestNeighbor( QgsPointXY( pt ) ).first() );
424 if ( !closestGeom.isEmpty() )
425 {
426 snappedRing.append( QgsPoint( closestGeom.vertexAt( 0 ) ) );
427 }
428 }
429
430 auto snappedErrGeom = std::make_unique<QgsPolygon>();
431 snappedErrGeom->setExteriorRing( new QgsLineString( snappedRing ) );
432
433 // Merge geometries
434 QgsFeaturePool *featurePool = featurePools[mergeLayerId];
435 std::unique_ptr<QgsAbstractGeometry> errLayerGeom( snappedErrGeom->clone() );
436 const QgsCoordinateTransform ct( featurePool->crs(), mContext->mapCrs, mContext->transformContext );
437 errLayerGeom->transform( ct, Qgis::TransformDirection::Reverse );
438 const QgsGeometry mergeFeatureGeom = mergeFeature.geometry();
439 const QgsAbstractGeometry *mergeGeom = mergeFeatureGeom.constGet();
440 std::unique_ptr<QgsGeometryEngine> geomEngine( QgsGeometry::createGeometryEngine( errLayerGeom.get(), 0 ) );
441 std::unique_ptr<QgsAbstractGeometry> combinedGeom( geomEngine->combine( QgsGeometryCheckerUtils::getGeomPart( mergeGeom, mergePartIdx ), &errMsg ) );
442 if ( !combinedGeom || combinedGeom->isEmpty() || !QgsWkbTypes::isSingleType( combinedGeom->wkbType() ) )
443 {
444 return false;
445 }
446
447 // Add merged polygon to destination geometry
448 replaceFeatureGeometryPart( featurePools, mergeLayerId, mergeFeature, mergePartIdx, combinedGeom.release(), changes );
449
450 return true;
451}
452
453
455{
456 QStringList methods = QStringList()
457 << tr( "Add gap area to neighboring polygon with longest shared edge" )
458 << tr( "No action" );
459 if ( mAllowedGapsSource )
460 methods << tr( "Add gap to allowed exceptions" );
461
462 return methods;
463}
464
465QList<QgsGeometryCheckResolutionMethod> QgsGeometryGapCheck::availableResolutionMethods() const
466{
467 QList<QgsGeometryCheckResolutionMethod> fixes {
468 QgsGeometryCheckResolutionMethod( MergeLongestEdge, tr( "Add to longest shared edge" ), tr( "Add the gap area to the neighbouring polygon with the longest shared edge." ), false ),
469 QgsGeometryCheckResolutionMethod( CreateNewFeature, tr( "Create new feature" ), tr( "Create a new feature from the gap area." ), false ),
470 QgsGeometryCheckResolutionMethod( MergeLargestArea, tr( "Add to largest neighbouring area" ), tr( "Add the gap area to the neighbouring polygon with the largest area." ), false )
471 };
472
473 if ( mAllowedGapsSource )
474 fixes << QgsGeometryCheckResolutionMethod( AddToAllowedGaps, tr( "Add Gap to Allowed Exceptions" ), tr( "Create a new feature from the gap geometry on the allowed exceptions layer." ), true );
475
476 fixes << QgsGeometryCheckResolutionMethod( NoChange, tr( "No action" ), tr( "Do not perform any action and mark this error as fixed." ), false );
477
478 return fixes;
479}
480
482{
483 return factoryDescription();
484}
485
487{
488 return factoryId();
489}
490
492{
493 return factoryFlags();
494}
495
497QString QgsGeometryGapCheck::factoryDescription()
498{
499 return tr( "Gap" );
500}
501
502QString QgsGeometryGapCheck::factoryId()
503{
504 return u"QgsGeometryGapCheck"_s;
505}
506
507QgsGeometryCheck::Flags QgsGeometryGapCheck::factoryFlags()
508{
510}
511
512QList<Qgis::GeometryType> QgsGeometryGapCheck::factoryCompatibleGeometryTypes()
513{
515}
516
517bool QgsGeometryGapCheck::factoryIsCompatible( QgsVectorLayer *layer ) SIP_SKIP
518{
519 return factoryCompatibleGeometryTypes().contains( layer->geometryType() );
520}
521
522QgsGeometryCheck::CheckType QgsGeometryGapCheck::factoryCheckType()
523{
525}
527
529{
530 return mContextBoundingBox;
531}
532
534{
535 QgsGeometryGapCheckError *err = dynamic_cast<QgsGeometryGapCheckError *>( other );
536 return err && err->location().distanceCompare( location(), mCheck->context()->reducedTolerance ) && err->neighbors() == neighbors();
537}
538
540{
541 QgsGeometryGapCheckError *err = dynamic_cast<QgsGeometryGapCheckError *>( other );
542 return err && err->layerId() == layerId() && err->neighbors() == neighbors();
543}
544
546{
548 // Static cast since this should only get called if isEqual == true
549 const QgsGeometryGapCheckError *err = static_cast<const QgsGeometryGapCheckError *>( other );
550 mNeighbors = err->mNeighbors;
551 mGapAreaBBox = err->mGapAreaBBox;
552}
553
558
560{
561 return mGapAreaBBox;
562}
563
564QMap<QString, QgsFeatureIds> QgsGeometryGapCheckError::involvedFeatures() const
565{
566 return mNeighbors;
567}
568
570{
572 return QgsApplication::getThemeIcon( u"/algorithms/mAlgorithmCheckGeometry.svg"_s );
573 else
574 return QgsApplication::getThemeIcon( u"/checks/SliverOrGap.svg"_s );
575}
@ Polygon
Polygons.
Definition qgis.h:368
@ Miter
Use mitered joins.
Definition qgis.h:2181
@ Square
Square cap (extends past start/end of line by buffer distance).
Definition qgis.h:2169
@ Reverse
Reverse/inverse transform (from destination to source).
Definition qgis.h:2731
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.
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.
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:60
void setId(QgsFeatureId id)
Sets the feature id for this feature.
QgsGeometry geometry
Definition qgsfeature.h:71
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:55
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition qgsfeedback.h:63
double progress() const
Returns the current progress reported by the feedback object.
Definition qgsfeedback.h:79
Base configuration for geometry checks.
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
QgsGeometryCheckError(const QgsGeometryCheck *check, const QgsGeometryCheckerUtils::LayerFeature &layerFeature, const QgsPointXY &errorLocation, QgsVertexId vidx=QgsVertexId(), const QVariant &value=QVariant(), ValueType valueType=ValueOther)
Create a new geometry check error with the parent check and for the layerFeature pair at the errorLoc...
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.
Implements a resolution for problems detected in geometry checks.
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 properties.
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.
Result checkUniqueId(const QgsGeometryCheckerUtils::LayerFeature layerFeature, QMap< QString, QSet< QVariant > > &uniqueIds) const
Checks that there are no duplicated unique IDs.
Result
Result of the geometry checker operation.
@ Canceled
User canceled calculation.
@ GeometryOverlayError
Error performing geometry overlay operation.
@ Success
Operation completed successfully.
QgsGeometryCheck(const QgsGeometryCheckContext *context, const QVariantMap &configuration)
Create a new geometry check.
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.
QgsGeometryGapCheckError(const QgsGeometryCheck *check, const QString &layerId, const QgsGeometry &geometry, const QMap< QString, QgsFeatureIds > &neighbors, double area, const QgsRectangle &gapAreaBBox, const QgsRectangle &contextArea)
Create a new gap check error produced by check on the layer layerId.
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...
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.
QgsGeometryCheck::Result collectErrors(const QMap< QString, QgsFeaturePool * > &featurePools, QList< QgsGeometryCheckError * > &errors, QStringList &messages, QgsFeedback *feedback, const LayerFeatureIds &ids=LayerFeatureIds()) const override
The main worker method.
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...
QString name
Definition qgsmaplayer.h:87
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:270
QgsPoint * clone() const override
Clones the geometry by performing a deep copy.
Definition qgspoint.cpp:111
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...
@ 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 dataset.
bool isEditable() const final
Returns true if the provider is in editing mode.
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 addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) final
Adds a single feature to the sink.
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 Q_INVOKABLE bool isSingleType(Qgis::WkbType type)
Returns true if the WKB type is a single type.
#define SIP_SKIP
Definition qgis_sip.h:134
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:30
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