QGIS API Documentation  3.12.1-București (121cc00ff0)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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 #include "geos_c.h"
32 
33 QgsGeometryGapCheck::QgsGeometryGapCheck( const QgsGeometryCheckContext *context, const QVariantMap &configuration )
34  : QgsGeometryCheck( context, configuration )
35  , mGapThresholdMapUnits( configuration.value( QStringLiteral( "gapThreshold" ) ).toDouble() )
36 {
37 }
38 
39 void QgsGeometryGapCheck::prepare( const QgsGeometryCheckContext *context, const QVariantMap &configuration )
40 {
41  if ( configuration.value( QStringLiteral( "allowedGapsEnabled" ) ).toBool() )
42  {
43  QgsVectorLayer *layer = context->project()->mapLayer<QgsVectorLayer *>( configuration.value( "allowedGapsLayer" ).toString() );
44  if ( layer )
45  {
46  mAllowedGapsLayer = layer;
47  mAllowedGapsSource = qgis::make_unique<QgsVectorLayerFeatureSource>( layer );
48 
49  mAllowedGapsBuffer = configuration.value( QStringLiteral( "allowedGapsBuffer" ) ).toDouble();
50  }
51  }
52  else
53  {
54  mAllowedGapsSource.reset();
55  }
56 }
57 
58 void QgsGeometryGapCheck::collectErrors( const QMap<QString, QgsFeaturePool *> &featurePools, QList<QgsGeometryCheckError *> &errors, QStringList &messages, QgsFeedback *feedback, const LayerFeatureIds &ids ) const
59 {
60  if ( feedback )
61  feedback->setProgress( feedback->progress() + 1.0 );
62 
63  std::unique_ptr<QgsAbstractGeometry> allowedGapsGeom;
64  std::unique_ptr<QgsGeometryEngine> allowedGapsGeomEngine;
65 
66  if ( mAllowedGapsSource )
67  {
68  QVector<QgsGeometry> allowedGaps;
69  QgsFeatureRequest request;
71  QgsFeatureIterator iterator = mAllowedGapsSource->getFeatures( request );
72  QgsFeature feature;
73 
74  while ( iterator.nextFeature( feature ) )
75  {
76  QgsGeometry geom = feature.geometry();
77  QgsGeometry gg = geom.buffer( mAllowedGapsBuffer, 20 );
78  allowedGaps.append( gg );
79  }
80 
81  std::unique_ptr< QgsGeometryEngine > allowedGapsEngine = QgsGeometryCheckerUtils::createGeomEngine( nullptr, mContext->tolerance );
82 
83  // Create union of allowed gaps
84  QString errMsg;
85  allowedGapsGeom.reset( allowedGapsEngine->combine( allowedGaps, &errMsg ) );
86  allowedGapsGeomEngine = QgsGeometryCheckerUtils::createGeomEngine( allowedGapsGeom.get(), mContext->tolerance );
87  allowedGapsGeomEngine->prepareGeometry();
88  }
89 
90  QVector<QgsGeometry> geomList;
91  QMap<QString, QgsFeatureIds> featureIds = ids.isEmpty() ? allLayerFeatureIds( featurePools ) : ids.toMap();
92  const QgsGeometryCheckerUtils::LayerFeatures layerFeatures( featurePools, featureIds, compatibleGeometryTypes(), nullptr, mContext, true );
93  for ( const QgsGeometryCheckerUtils::LayerFeature &layerFeature : layerFeatures )
94  {
95  geomList.append( layerFeature.geometry() );
96 
97  if ( feedback && feedback->isCanceled() )
98  {
99  geomList.clear();
100  break;
101  }
102  }
103 
104  if ( geomList.isEmpty() )
105  {
106  return;
107  }
108 
109  std::unique_ptr< QgsGeometryEngine > geomEngine = QgsGeometryCheckerUtils::createGeomEngine( nullptr, mContext->tolerance );
110 
111  // Create union of geometry
112  QString errMsg;
113  std::unique_ptr<QgsAbstractGeometry> unionGeom( geomEngine->combine( geomList, &errMsg ) );
114  if ( !unionGeom )
115  {
116  messages.append( tr( "Gap check: %1" ).arg( errMsg ) );
117  return;
118  }
119 
120  // Get envelope of union
121  geomEngine = QgsGeometryCheckerUtils::createGeomEngine( unionGeom.get(), mContext->tolerance );
122  geomEngine->prepareGeometry();
123  std::unique_ptr<QgsAbstractGeometry> envelope( geomEngine->envelope( &errMsg ) );
124  if ( !envelope )
125  {
126  messages.append( tr( "Gap check: %1" ).arg( errMsg ) );
127  return;
128  }
129 
130  // Buffer envelope
131  geomEngine = QgsGeometryCheckerUtils::createGeomEngine( envelope.get(), mContext->tolerance );
132  geomEngine->prepareGeometry();
133  QgsAbstractGeometry *bufEnvelope = geomEngine->buffer( 2, 0, GEOSBUF_CAP_SQUARE, GEOSBUF_JOIN_MITRE, 4. ); //#spellok //#spellok
134  envelope.reset( bufEnvelope );
135 
136  // Compute difference between envelope and union to obtain gap polygons
137  geomEngine = QgsGeometryCheckerUtils::createGeomEngine( envelope.get(), mContext->tolerance );
138  geomEngine->prepareGeometry();
139  std::unique_ptr<QgsAbstractGeometry> diffGeom( geomEngine->difference( unionGeom.get(), &errMsg ) );
140  if ( !diffGeom )
141  {
142  messages.append( tr( "Gap check: %1" ).arg( errMsg ) );
143  return;
144  }
145 
146  // For each gap polygon which does not lie on the boundary, get neighboring polygons and add error
147  QgsGeometryPartIterator parts = diffGeom->parts();
148  while ( parts.hasNext() )
149  {
150  const QgsAbstractGeometry *gapGeom = parts.next();
151  // Skip the gap between features and boundingbox
152  const double spacing = context()->tolerance;
153  if ( gapGeom->boundingBox().snappedToGrid( spacing ) == envelope->boundingBox().snappedToGrid( spacing ) )
154  {
155  continue;
156  }
157 
158  // Skip gaps above threshold
159  if ( ( mGapThresholdMapUnits > 0 && gapGeom->area() > mGapThresholdMapUnits ) || gapGeom->area() < mContext->reducedTolerance )
160  {
161  continue;
162  }
163 
164  QgsRectangle gapAreaBBox = gapGeom->boundingBox();
165 
166  // Get neighboring polygons
167  QMap<QString, QgsFeatureIds> neighboringIds;
168  const QgsGeometryCheckerUtils::LayerFeatures layerFeatures( featurePools, featureIds.keys(), gapAreaBBox, compatibleGeometryTypes(), mContext );
169  for ( const QgsGeometryCheckerUtils::LayerFeature &layerFeature : layerFeatures )
170  {
171  const QgsGeometry geom = layerFeature.geometry();
173  {
174  neighboringIds[layerFeature.layer()->id()].insert( layerFeature.feature().id() );
175  gapAreaBBox.combineExtentWith( layerFeature.geometry().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  double area = gapGeom->area();
191  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  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  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  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() );
319 
320  const auto featureIds = err->neighbors().value( layerId );
321 
322  for ( 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;
343  switch ( condition )
344  {
345  case LongestSharedEdge:
347  break;
348 
349  case LargestArea:
350  val = QgsGeometryCheckerUtils::getGeomPart( testGeom, iPart )->area();
351  break;
352  }
353 
354  if ( val > maxVal )
355  {
356  maxVal = val;
357  mergeFeature = testFeature;
358  mergePartIdx = iPart;
359  mergeLayerId = layerId;
360  }
361  }
362  }
363  }
364 
365  if ( maxVal == 0. )
366  {
367  return false;
368  }
369 
370  QgsSpatialIndex neighbourIndex( QgsSpatialIndex::Flag::FlagStoreFeatureGeometries );
371  neighbourIndex.addFeatures( neighbours );
372 
373  QgsPolyline snappedRing;
374  QgsVertexIterator iterator = errGeometry->vertices();
375  while ( iterator.hasNext() )
376  {
377  QgsPoint pt = iterator.next();
378  QgsVertexId id;
379  QgsGeometry closestGeom = neighbourIndex.geometry( neighbourIndex.nearestNeighbor( QgsPointXY( pt ) ).first() );
380  if ( !closestGeom.isEmpty() )
381  {
382  QgsPoint closestPoint = QgsGeometryUtils::closestVertex( *closestGeom.constGet(), pt, id );
383  snappedRing.append( closestPoint );
384  }
385  }
386 
387  std::unique_ptr<QgsPolygon> snappedErrGeom = qgis::make_unique<QgsPolygon>();
388  snappedErrGeom->setExteriorRing( new QgsLineString( snappedRing ) );
389 
390  // Merge geometries
391  QgsFeaturePool *featurePool = featurePools[ mergeLayerId ];
392  std::unique_ptr<QgsAbstractGeometry> errLayerGeom( snappedErrGeom->clone() );
395  const QgsGeometry mergeFeatureGeom = mergeFeature.geometry();
396  const QgsAbstractGeometry *mergeGeom = mergeFeatureGeom.constGet();
397  std::unique_ptr< QgsGeometryEngine > geomEngine = QgsGeometryCheckerUtils::createGeomEngine( errLayerGeom.get(), 0 );
398  std::unique_ptr<QgsAbstractGeometry> combinedGeom( geomEngine->combine( QgsGeometryCheckerUtils::getGeomPart( mergeGeom, mergePartIdx ), &errMsg ) );
399  if ( !combinedGeom || combinedGeom->isEmpty() || !QgsWkbTypes::isSingleType( combinedGeom->wkbType() ) )
400  {
401  return false;
402  }
403 
404  // Add merged polygon to destination geometry
405  replaceFeatureGeometryPart( featurePools, mergeLayerId, mergeFeature, mergePartIdx, combinedGeom.release(), changes );
406 
407  return true;
408 }
409 
410 
412 {
413  QStringList methods = QStringList()
414  << tr( "Add gap area to neighboring polygon with longest shared edge" )
415  << tr( "No action" );
416  if ( mAllowedGapsSource )
417  methods << tr( "Add gap to allowed exceptions" );
418 
419  return methods;
420 }
421 
422 QList<QgsGeometryCheckResolutionMethod> QgsGeometryGapCheck::availableResolutionMethods() const
423 {
424  QList<QgsGeometryCheckResolutionMethod> fixes
425  {
426  QgsGeometryCheckResolutionMethod( MergeLongestEdge, tr( "Add to longest shared edge" ), tr( "Add the gap area to the neighbouring polygon with the longest shared edge." ), false ),
427  QgsGeometryCheckResolutionMethod( CreateNewFeature, tr( "Create new feature" ), tr( "Create a new feature from the gap area." ), false ),
428  QgsGeometryCheckResolutionMethod( MergeLargestArea, tr( "Add to largest neighbouring area" ), tr( "Add the gap area to the neighbouring polygon with the largest area." ), false )
429  };
430 
431  if ( mAllowedGapsSource )
432  fixes << QgsGeometryCheckResolutionMethod( AddToAllowedGaps, tr( "Add gap to allowed exceptions" ), tr( "Create a new feature from the gap geometry on the allowed exceptions layer." ), false );
433 
434  fixes << QgsGeometryCheckResolutionMethod( NoChange, tr( "No action" ), tr( "Do not perform any action and mark this error as fixed." ), false );
435 
436  return fixes;
437 }
438 
440 {
441  return factoryDescription();
442 }
443 
444 QString QgsGeometryGapCheck::id() const
445 {
446  return factoryId();
447 }
448 
449 QgsGeometryCheck::Flags QgsGeometryGapCheck::flags() const
450 {
451  return factoryFlags();
452 }
453 
455 QString QgsGeometryGapCheck::factoryDescription()
456 {
457  return tr( "Gap" );
458 }
459 
460 QString QgsGeometryGapCheck::factoryId()
461 {
462  return QStringLiteral( "QgsGeometryGapCheck" );
463 }
464 
465 QgsGeometryCheck::Flags QgsGeometryGapCheck::factoryFlags()
466 {
468 }
469 
470 QList<QgsWkbTypes::GeometryType> QgsGeometryGapCheck::factoryCompatibleGeometryTypes()
471 {
473 }
474 
475 bool QgsGeometryGapCheck::factoryIsCompatible( QgsVectorLayer *layer ) SIP_SKIP
476 {
477  return factoryCompatibleGeometryTypes().contains( layer->geometryType() );
478 }
479 
480 QgsGeometryCheck::CheckType QgsGeometryGapCheck::factoryCheckType()
481 {
483 }
485 
487 {
488  return mContextBoundingBox;
489 }
490 
492 {
493  QgsGeometryGapCheckError *err = dynamic_cast<QgsGeometryGapCheckError *>( other );
494  return err && QgsGeometryCheckerUtils::pointsFuzzyEqual( err->location(), location(), mCheck->context()->reducedTolerance ) && err->neighbors() == neighbors();
495 }
496 
498 {
499  QgsGeometryGapCheckError *err = dynamic_cast<QgsGeometryGapCheckError *>( other );
500  return err && err->layerId() == layerId() && err->neighbors() == neighbors();
501 }
502 
504 {
506  // Static cast since this should only get called if isEqual == true
507  const QgsGeometryGapCheckError *err = static_cast<const QgsGeometryGapCheckError *>( other );
508  mNeighbors = err->mNeighbors;
509  mGapAreaBBox = err->mGapAreaBBox;
510 }
511 
513 {
514  return true;
515 }
516 
518 {
519  return mGapAreaBBox;
520 }
521 
522 QMap<QString, QgsFeatureIds> QgsGeometryGapCheckError::involvedFeatures() const
523 {
524  return mNeighbors;
525 }
526 
528 {
529 
530  if ( status() == QgsGeometryCheckError::StatusFixed )
531  return QgsApplication::getThemeIcon( QStringLiteral( "/algorithms/mAlgorithmCheckGeometry.svg" ) );
532  else
533  return QgsApplication::getThemeIcon( QStringLiteral( "/checks/SliverOrGap.svg" ) );
534 }
Wrapper for iterator of features from vector data provider or vector layer.
QgsPointSequence QgsPolyline
Polyline as represented as a vector of points.
Definition: qgsgeometry.h:70
A rectangle specified with double values.
Definition: qgsrectangle.h:41
Java-style iterator for traversal of parts of a geometry.
static bool pointsFuzzyEqual(const QgsPointXY &p1, const QgsPointXY &p2, double tol)
Determine whether two points are equal up to the specified tolerance.
QList< QgsWkbTypes::GeometryType > compatibleGeometryTypes() const override
A list of geometry types for which this check can be performed.
QgsGeometry geometry(QgsFeatureId id) const
Returns the stored geometry for the indexed feature with matching id.
virtual void update(const QgsGeometryCheckError *other)
Update this error with the information from other.
bool closeMatch(QgsGeometryCheckError *other) const override
Check if this error is almost equal to other.
OperationResult transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection direction=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
static QgsAbstractGeometry * getGeomPart(QgsAbstractGeometry *geom, int partIdx)
double progress() const
Returns the current progress reported by the feedback object.
Definition: qgsfeedback.h:81
Java-style iterator for traversal of vertices of a geometry.
QgsPointXY transform(const QgsPointXY &point, TransformDirection direction=ForwardTransform) const SIP_THROW(QgsCsException)
Transform the point from the source CRS to the destination CRS.
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:571
QString description() const override
Returns a human readable description for this check.
A class to represent a 2D point.
Definition: qgspointxy.h:43
const QgsPointXY & location() const
The location of the error in map units.
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:64
Q_INVOKABLE bool startEditing()
Makes the layer editable.
QMap< QString, QgsFeatureIds > toMap() const
qint64 QgsFeatureId
Definition: qgsfeatureid.h:25
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
Base configuration for geometry checks.
Contains a set of layers and feature ids in those layers to pass to a geometry check.
CheckType
The type of a check.
Q_INVOKABLE QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:122
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
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...
Merge with neighbouring polygon with largest area.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
static QgsPoint closestVertex(const QgsAbstractGeometry &geom, const QgsPoint &pt, QgsVertexId &id)
Returns the closest vertex to a geometry for a specified point.
virtual QgsRectangle boundingBox() const =0
Returns the minimal bounding box for the geometry.
QgsRectangle snappedToGrid(double spacing) const
Returns a copy of this rectangle that is snapped to a grid with the specified spacing between the gri...
virtual QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
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.
void setFixFailed(const QString &reason)
Set the error status to failed and specify the reason for failure.
QIcon icon() const override
Returns an icon that should be shown for this kind of error.
Base class for feedback objects to be used for cancellation of something running in a worker thread...
Definition: qgsfeedback.h:45
An error produced by a QgsGeometryGapCheck.
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
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...
static double sharedEdgeLength(const QgsAbstractGeometry *geom1, const QgsAbstractGeometry *geom2, double tol)
void update(const QgsGeometryCheckError *other) override
Update this error with the information from other.
Utility class for identifying a unique vertex within a geometry.
#define SIP_SKIP
Definition: qgis_sip.h:126
Add gap geometry to allowed gaps layer.
Q_DECL_DEPRECATED QStringList resolutionMethods() const override
Returns a list of descriptions for available resolutions for errors.
bool getFeature(QgsFeatureId id, QgsFeature &feature)
Retrieves the feature with the specified id into feature.
A layer feature combination to uniquely identify and access a feature in a set of layers...
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
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.
QMap< int, QVariant > QgsAttributeMap
Definition: qgsattributes.h:38
QgsRectangle contextBoundingBox() const override
The context of the error.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
bool addFeatures(QgsFeatureList &features, QgsFeatureSink::Flags flags=nullptr) FINAL
Adds a list of features to the sink.
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
Encapsulates a QGIS project, including sets of map layers and their styles, layouts, annotations, canvases, etc.
Definition: qgsproject.h:91
const double reducedTolerance
The tolerance to allow for in geometry checks.
This class implements a geometry check.
virtual double area() const
Returns the planar, 2-dimensional area of the geometry.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer&#39;s project and layer.
QgsGeometryCheck::Flags flags() const override
Flags for this geometry check.
Abstract base class for all geometries.
QMap< QString, QgsFeatureIds > allLayerFeatureIds(const QMap< QString, QgsFeaturePool *> &featurePools) const
Returns all layers and feature ids.
const QString & layerId() const
The id of the layer on which this error has been detected.
ResolutionMethod
Resolution methods for geometry gap checks.
const QgsGeometryCheckContext * mContext
const QgsCoordinateReferenceSystem mapCrs
The coordinate system in which calculations should be done.
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:37
A list of layers and feature ids for each of these layers.
const QMap< QString, QgsFeatureIds > & neighbors() const
A map of layers and feature ids of the neighbors of the gap.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
QgsGeometry geometry() const
The geometry of the error in map units.
static bool isSingleType(Type type)
Returns true if the WKB type is a single type.
Definition: qgswkbtypes.h:696
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle...
Definition: qgsrectangle.h:359
QgsGeometryGapCheck(const QgsGeometryCheckContext *context, const QVariantMap &configuration)
The configuration accepts a "gapThreshold" key which specifies the maximum gap size in squared map un...
QMap< QString, QgsFeatureIds > involvedFeatures() const override
Returns a list of involved features.
A spatial index for QgsFeature objects.
QMap< QString, QMap< QgsFeatureId, QList< QgsGeometryCheck::Change > > > Changes
A collection of changes.
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:55
Transform from destination to source CRS.
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.
QgsAbstractGeometry * next()
Returns next part of the geometry (undefined behavior if hasNext() returns false before calling next(...
bool handleChanges(const QgsGeometryCheck::Changes &) override
Apply a list of changes.
const double tolerance
The tolerance to allow for in geometry checks.
A feature pool is based on a vector layer and caches features.
bool addFeatures(QgsFeatureList &features, QgsFeatureSink::Flags flags=nullptr) override
Adds a list of features to the index.
QgsPoint next()
Returns next vertex of the geometry (undefined behavior if hasNext() returns false before calling nex...
Create a new feature with the gap geometry.
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:43
QgsRectangle affectedAreaBBox() const override
The bounding box of the affected area of the error.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:450
void setFixed(int method)
Set the status to fixed and specify the method that has been used to fix the error.
Do not handle the error.
void setGeometry(const QgsGeometry &geometry)
Set the feature&#39;s geometry.
Definition: qgsfeature.cpp:137
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=nullptr) FINAL
Adds a single feature to the sink.
Class for doing transforms between two map coordinate systems.
const QgsProject * project() const
The project can be used to resolve additional layers.
void collectErrors(const QMap< QString, QgsFeaturePool *> &featurePools, QList< QgsGeometryCheckError *> &errors, QStringList &messages, QgsFeedback *feedback, const LayerFeatureIds &ids=LayerFeatureIds()) const override
The main worker method.
bool isEqual(QgsGeometryCheckError *other) const override
Check if this error is equal to other.
Q_INVOKABLE QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
QString name
Definition: qgsmaplayer.h:83
This class implements a resolution for problems detected in geometry checks.
QgsCoordinateReferenceSystem crs() const
The coordinate reference system of this layer.
QgsGeometry geometry
Definition: qgsfeature.h:67
const QgsGeometryCheckContext * context() const
Returns the context.
QList< int > QgsAttributeList
Definition: qgsfield.h:26
This represents an error reported by a geometry check.
static std::unique_ptr< QgsGeometryEngine > createGeomEngine(const QgsAbstractGeometry *geometry, double tolerance)
bool nextFeature(QgsFeature &f)
bool hasNext() const
Find out whether there are more vertices.
static QgsFeatureList makeFeatureCompatible(const QgsFeature &feature, const QgsVectorLayer *layer)
Converts input feature to be compatible with the given layer.
QList< QgsFeatureId > nearestNeighbor(const QgsPointXY &point, int neighbors=1, double maxDistance=0) const
Returns nearest neighbors to a point.
Represents a vector layer which manages a vector based data sets.
QgsVertexIterator vertices() const
Returns a read-only, Java-style iterator for traversal of vertices of all the geometry, including all geometry parts and rings.
QString id() const override
Returns an id for this check.
QList< QgsGeometryCheckResolutionMethod > availableResolutionMethods() const override
Returns a list of available resolution methods.
Merge the gap with the polygon with the longest shared edge.
bool hasNext() const
Find out whether there are more parts.
This geometry check should be available in layer validation on the vector layer peroperties.
virtual int partCount() const =0
Returns count of parts contained in the geometry.
The check controls a whole layer (topology checks)
const QgsCoordinateTransformContext transformContext
The coordinate transform context with which transformations will be done.