Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #8008 from m-kuhn/missingVertexCheck
Add QgsGeometryMissingVertexCheck
- Loading branch information
Showing
5 changed files
with
216 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
133 changes: 133 additions & 0 deletions
133
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,133 @@ | ||
/*************************************************************************** | ||
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 "qgsmultipolygon.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 | ||
{ | ||
const QgsFeature ¤tFeature = layerFeature.feature(); | ||
std::unique_ptr<QgsMultiPolygon> boundaries = qgis::make_unique<QgsMultiPolygon>(); | ||
|
||
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 ); | ||
geomEngine->prepareGeometry(); | ||
|
||
const QgsFeatureIds fids = featurePool->getIntersects( boundaries->boundingBox() ); | ||
|
||
QgsFeature compareFeature; | ||
for ( QgsFeatureId fid : fids ) | ||
{ | ||
if ( fid == currentFeature.id() ) | ||
continue; | ||
|
||
if ( featurePool->getFeature( fid, compareFeature ) ) | ||
{ | ||
QgsVertexIterator vertexIterator = compareFeature.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 ) | ||
{ | ||
bool alreadyReported = false; | ||
for ( QgsGeometryCheckError *error : qgis::as_const( errors ) ) | ||
{ | ||
// Only list missing vertices once | ||
if ( error->featureId() == currentFeature.id() && error->location() == QgsPointXY( pt ) ) | ||
{ | ||
alreadyReported = true; | ||
break; | ||
} | ||
} | ||
if ( !alreadyReported ) | ||
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_ |
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
Binary file not shown.