QGIS API Documentation  3.22.4-Białowieża (ce8e65e95e)
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 "qgsgeometrycollection.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 
31 QgsGeometryGapCheck::QgsGeometryGapCheck( const QgsGeometryCheckContext *context, const QVariantMap &configuration )
32  : QgsGeometryCheck( context, configuration )
33  , mGapThresholdMapUnits( configuration.value( QStringLiteral( "gapThreshold" ) ).toDouble() )
34 {
35 }
36 
37 void 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 
56 void 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 
196 void 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() );
238  QgsFeatureList features = QgsVectorLayerUtils::makeFeatureCompatible( feature, layer );
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();
265  QgsFeature feature = QgsVectorLayerUtils::createFeature( layer, geometry, QgsAttributeMap(), &context );
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 
299 bool 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 
437 QList<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 
459 QString QgsGeometryGapCheck::id() const
460 {
461  return factoryId();
462 }
463 
464 QgsGeometryCheck::Flags QgsGeometryGapCheck::flags() const
465 {
466  return factoryFlags();
467 }
468 
470 QString QgsGeometryGapCheck::factoryDescription()
471 {
472  return tr( "Gap" );
473 }
474 
475 QString QgsGeometryGapCheck::factoryId()
476 {
477  return QStringLiteral( "QgsGeometryGapCheck" );
478 }
479 
480 QgsGeometryCheck::Flags QgsGeometryGapCheck::factoryFlags()
481 {
483 }
484 
485 QList<QgsWkbTypes::GeometryType> QgsGeometryGapCheck::factoryCompatibleGeometryTypes()
486 {
488 }
489 
490 bool QgsGeometryGapCheck::factoryIsCompatible( QgsVectorLayer *layer ) SIP_SKIP
491 {
492  return factoryCompatibleGeometryTypes().contains( layer->geometryType() );
493 }
494 
495 QgsGeometryCheck::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 
537 QMap<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 QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
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.
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:115
QgsGeometry geometry
Definition: qgsfeature.h:67
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:163
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.
const QString & layerId() const
The id of the layer on which this error has been detected.
@ 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
const QgsPointXY & location() const
The location of the error in map units.
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.
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.
const QMap< QString, QgsFeatureIds > & neighbors() const
A map of layers and feature ids of the neighbors of the gap.
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.
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 thr...
QList< QgsGeometryCheckResolutionMethod > availableResolutionMethods() const override
Returns a list of available resolution methods.
QList< QgsWkbTypes::GeometryType > compatibleGeometryTypes() const override
A list of geometry types for which this check can be performed.
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:44
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:101
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:467
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:38
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:882
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