-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
A topology check for missing vertices on polygon boundaries of neighbouring polygons.
- Loading branch information
Showing
3 changed files
with
173 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
119 changes: 119 additions & 0 deletions
119
src/analysis/vector/geometry_checker/qgsgeometrymissingvertexcheck.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
/*************************************************************************** | ||
qgsgeometrymissingvertexcheck.cpp | ||
--------------------- | ||
begin : September 2018 | ||
copyright : (C) 2018 Matthias Kuhn | ||
email : matthias@opengis.ch | ||
*************************************************************************** | ||
* * | ||
* This program is free software; you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
***************************************************************************/ | ||
|
||
#include "qgsgeometrymissingvertexcheck.h" | ||
|
||
#include "qgsfeaturepool.h" | ||
#include "qgsgeometrycollection.h" | ||
#include "qgscurvepolygon.h" | ||
#include "qgscurve.h" | ||
#include "qgslinestring.h" | ||
#include "qgsgeometryengine.h" | ||
#include "qgsgeometryutils.h" | ||
|
||
void QgsGeometryMissingVertexCheck::collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &messages, QAtomicInt *progressCounter, const QMap<QString, QgsFeatureIds> &ids ) const | ||
{ | ||
Q_UNUSED( messages ); | ||
if ( progressCounter ) | ||
progressCounter->fetchAndAddRelaxed( 1 ); | ||
|
||
QMap<QString, QgsFeatureIds> featureIds = ids.isEmpty() ? allLayerFeatureIds() : ids; | ||
|
||
QgsFeaturePool *featurePool = mContext->featurePools.value( featureIds.firstKey() ); | ||
|
||
const QgsGeometryCheckerUtils::LayerFeatures layerFeatures( mContext->featurePools, featureIds, mCompatibleGeometryTypes, nullptr, mContext, true ); | ||
|
||
for ( const QgsGeometryCheckerUtils::LayerFeature &layerFeature : layerFeatures ) | ||
{ | ||
const QgsAbstractGeometry *geom = layerFeature.geometry().constGet(); | ||
|
||
if ( QgsCurvePolygon *polygon = qgsgeometry_cast<QgsCurvePolygon *>( geom ) ) | ||
{ | ||
processPolygon( polygon, featurePool, errors, layerFeature ); | ||
} | ||
else if ( QgsGeometryCollection *collection = qgsgeometry_cast<QgsGeometryCollection *>( geom ) ) | ||
{ | ||
const int numGeometries = collection->numGeometries(); | ||
for ( int i = 0; i < numGeometries; ++i ) | ||
{ | ||
if ( QgsCurvePolygon *polygon = qgsgeometry_cast<QgsCurvePolygon *>( collection->geometryN( i ) ) ) | ||
{ | ||
processPolygon( polygon, featurePool, errors, layerFeature ); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
void QgsGeometryMissingVertexCheck::fixError( QgsGeometryCheckError *error, int method, const QMap<QString, int> &mergeAttributeIndices, Changes &changes ) const | ||
{ | ||
Q_UNUSED( mergeAttributeIndices ); | ||
Q_UNUSED( changes ); | ||
if ( method == NoChange ) | ||
{ | ||
error->setFixed( method ); | ||
} | ||
} | ||
|
||
QStringList QgsGeometryMissingVertexCheck::resolutionMethods() const | ||
{ | ||
static QStringList methods = QStringList() << tr( "No action" ); | ||
return methods; | ||
} | ||
|
||
void QgsGeometryMissingVertexCheck::processPolygon( const QgsCurvePolygon *polygon, QgsFeaturePool *featurePool, QList<QgsGeometryCheckError *> &errors, const QgsGeometryCheckerUtils::LayerFeature &layerFeature ) const | ||
{ | ||
std::unique_ptr<QgsGeometryCollection> boundaries = qgis::make_unique<QgsGeometryCollection>(); | ||
|
||
std::unique_ptr< QgsGeometryEngine > geomEngine = QgsGeometryCheckerUtils::createGeomEngine( polygon->exteriorRing(), mContext->tolerance ); | ||
boundaries->addGeometry( geomEngine->buffer( mContext->tolerance, 5 ) ); | ||
|
||
const int numRings = polygon->numInteriorRings(); | ||
for ( int i = 0; i < numRings; ++i ) | ||
{ | ||
geomEngine = QgsGeometryCheckerUtils::createGeomEngine( polygon->exteriorRing(), mContext->tolerance ); | ||
boundaries->addGeometry( geomEngine->buffer( mContext->tolerance, 5 ) ); | ||
} | ||
|
||
geomEngine = QgsGeometryCheckerUtils::createGeomEngine( boundaries.get(), mContext->tolerance ); | ||
|
||
const QgsFeatureIds fids = featurePool->getIntersects( boundaries->boundingBox() ); | ||
|
||
QgsFeature feature; | ||
for ( QgsFeatureId fid : fids ) | ||
{ | ||
if ( fid == layerFeature.feature().id() ) | ||
continue; | ||
|
||
if ( featurePool->getFeature( fid, feature ) ) | ||
{ | ||
QgsVertexIterator vertexIterator = feature.geometry().vertices(); | ||
while ( vertexIterator.hasNext() ) | ||
{ | ||
const QgsPoint &pt = vertexIterator.next(); | ||
if ( geomEngine->intersects( &pt ) ) | ||
{ | ||
QgsVertexId vertexId; | ||
QgsPoint closestVertex = QgsGeometryUtils::closestVertex( *polygon, pt, vertexId ); | ||
|
||
if ( closestVertex.distance( pt ) > mContext->tolerance ) | ||
{ | ||
errors.append( new QgsGeometryCheckError( this, layerFeature, QgsPointXY( pt ) ) ); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
52 changes: 52 additions & 0 deletions
52
src/analysis/vector/geometry_checker/qgsgeometrymissingvertexcheck.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/*************************************************************************** | ||
qgsgeometrymissingvertexcheck.h | ||
--------------------- | ||
begin : September 2018 | ||
copyright : (C) 2018 Matthias Kuhn | ||
email : matthias@opengis.ch | ||
*************************************************************************** | ||
* * | ||
* This program is free software; you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
***************************************************************************/ | ||
|
||
#define SIP_NO_FILE | ||
|
||
#ifndef QGSGEOMETRYMISSINGVERTEXCHECK_H | ||
#define QGSGEOMETRYMISSINGVERTEXCHECK_H | ||
|
||
#include "qgsgeometrycheck.h" | ||
|
||
class QgsCurvePolygon; | ||
|
||
/** | ||
* \ingroup analysis | ||
* | ||
* A topology check for missing vertices. | ||
* Any vertex which is on the border of another polygon but no corresponding vertex | ||
* can be found on the other polygon will be reported as an error. | ||
* | ||
* \since QGIS 3.4 | ||
*/ | ||
class ANALYSIS_EXPORT QgsGeometryMissingVertexCheck : public QgsGeometryCheck | ||
{ | ||
public: | ||
explicit QgsGeometryMissingVertexCheck( QgsGeometryCheckerContext *context ) | ||
: QgsGeometryCheck( LayerCheck, {QgsWkbTypes::PolygonGeometry}, context ) | ||
{} | ||
void collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &messages, QAtomicInt *progressCounter = nullptr, const QMap<QString, QgsFeatureIds> &ids = QMap<QString, QgsFeatureIds>() ) const override; | ||
void fixError( QgsGeometryCheckError *error, int method, const QMap<QString, int> &mergeAttributeIndices, Changes &changes ) const override; | ||
QStringList resolutionMethods() const override; | ||
QString errorDescription() const override { return tr( "Missing Vertex" ); } | ||
QString errorName() const override { return QStringLiteral( "QgsGeometryMissingVertexCheck" ); } | ||
|
||
enum ResolutionMethod { NoChange }; | ||
|
||
private: | ||
void processPolygon( const QgsCurvePolygon *polygon, QgsFeaturePool *featurePool, QList<QgsGeometryCheckError *> &errors, const QgsGeometryCheckerUtils::LayerFeature &layerFeature ) const; | ||
}; | ||
|
||
#endif // QGSGEOMETRYMISSINGVERTEXCHECK_ |