Skip to content
Permalink
Browse files

[Geometry checker] Initial multi-layer support

  • Loading branch information
manisandro committed Mar 30, 2017
1 parent e3fc73f commit 31cc65df4946dd9a052fa65cdaa3d6b3aaa4a915
Showing with 1,488 additions and 1,086 deletions.
  1. +1 −0 src/plugins/geometry_checker/CMakeLists.txt
  2. +44 −37 src/plugins/geometry_checker/checks/qgsgeometryanglecheck.cpp
  3. +5 −5 src/plugins/geometry_checker/checks/qgsgeometryanglecheck.h
  4. +48 −33 src/plugins/geometry_checker/checks/qgsgeometryareacheck.cpp
  5. +8 −8 src/plugins/geometry_checker/checks/qgsgeometryareacheck.h
  6. +31 −20 src/plugins/geometry_checker/checks/qgsgeometrycheck.cpp
  7. +22 −11 src/plugins/geometry_checker/checks/qgsgeometrycheck.h
  8. +38 −31 src/plugins/geometry_checker/checks/qgsgeometrycontainedcheck.cpp
  9. +6 −4 src/plugins/geometry_checker/checks/qgsgeometrycontainedcheck.h
  10. +22 −15 src/plugins/geometry_checker/checks/qgsgeometrydegeneratepolygoncheck.cpp
  11. +4 −4 src/plugins/geometry_checker/checks/qgsgeometrydegeneratepolygoncheck.h
  12. +45 −38 src/plugins/geometry_checker/checks/qgsgeometryduplicatecheck.cpp
  13. +8 −6 src/plugins/geometry_checker/checks/qgsgeometryduplicatecheck.h
  14. +30 −23 src/plugins/geometry_checker/checks/qgsgeometryduplicatenodescheck.cpp
  15. +4 −4 src/plugins/geometry_checker/checks/qgsgeometryduplicatenodescheck.h
  16. +100 −91 src/plugins/geometry_checker/checks/qgsgeometrygapcheck.cpp
  17. +9 −8 src/plugins/geometry_checker/checks/qgsgeometrygapcheck.h
  18. +23 −16 src/plugins/geometry_checker/checks/qgsgeometryholecheck.cpp
  19. +4 −4 src/plugins/geometry_checker/checks/qgsgeometryholecheck.h
  20. +25 −18 src/plugins/geometry_checker/checks/qgsgeometrymultipartcheck.cpp
  21. +4 −4 src/plugins/geometry_checker/checks/qgsgeometrymultipartcheck.h
  22. +50 −41 src/plugins/geometry_checker/checks/qgsgeometryoverlapcheck.cpp
  23. +10 −8 src/plugins/geometry_checker/checks/qgsgeometryoverlapcheck.h
  24. +37 −26 src/plugins/geometry_checker/checks/qgsgeometrysegmentlengthcheck.cpp
  25. +6 −6 src/plugins/geometry_checker/checks/qgsgeometrysegmentlengthcheck.h
  26. +58 −51 src/plugins/geometry_checker/checks/qgsgeometryselfcontactcheck.cpp
  27. +4 −4 src/plugins/geometry_checker/checks/qgsgeometryselfcontactcheck.h
  28. +50 −43 src/plugins/geometry_checker/checks/qgsgeometryselfintersectioncheck.cpp
  29. +6 −5 src/plugins/geometry_checker/checks/qgsgeometryselfintersectioncheck.h
  30. +32 −0 src/plugins/geometry_checker/checks/qgsgeometrysliverpolygoncheck.cpp
  31. +6 −15 src/plugins/geometry_checker/checks/qgsgeometrysliverpolygoncheck.h
  32. +31 −24 src/plugins/geometry_checker/checks/qgsgeometrytypecheck.cpp
  33. +7 −6 src/plugins/geometry_checker/checks/qgsgeometrytypecheck.h
  34. +56 −45 src/plugins/geometry_checker/qgsgeometrychecker.cpp
  35. +5 −8 src/plugins/geometry_checker/qgsgeometrychecker.h
  36. +58 −58 src/plugins/geometry_checker/qgsgeometrycheckfactory.cpp
  37. +4 −5 src/plugins/geometry_checker/qgsgeometrycheckfactory.h
  38. +2 −2 src/plugins/geometry_checker/ui/qgsgeometrycheckerdialog.cpp
  39. +2 −1 src/plugins/geometry_checker/ui/qgsgeometrycheckerdialog.h
  40. +9 −9 src/plugins/geometry_checker/ui/qgsgeometrycheckerfixsummarydialog.cpp
  41. +3 −4 src/plugins/geometry_checker/ui/qgsgeometrycheckerfixsummarydialog.h
  42. +100 −45 src/plugins/geometry_checker/ui/qgsgeometrycheckerresulttab.cpp
  43. +4 −4 src/plugins/geometry_checker/ui/qgsgeometrycheckerresulttab.h
  44. +137 −127 src/plugins/geometry_checker/ui/qgsgeometrycheckerresulttab.ui
  45. +247 −120 src/plugins/geometry_checker/ui/qgsgeometrycheckersetuptab.cpp
  46. +2 −3 src/plugins/geometry_checker/ui/qgsgeometrycheckersetuptab.h
  47. +72 −36 src/plugins/geometry_checker/ui/qgsgeometrycheckersetuptab.ui
  48. +3 −6 src/plugins/geometry_checker/ui/qgsgeometrycheckfixdialog.cpp
  49. +1 −2 src/plugins/geometry_checker/ui/qgsgeometrycheckfixdialog.h
  50. +2 −1 src/plugins/geometry_checker/utils/qgsfeaturepool.cpp
  51. +3 −1 src/plugins/geometry_checker/utils/qgsfeaturepool.h
@@ -20,6 +20,7 @@ SET (geometrychecker_SRCS
checks/qgsgeometrysegmentlengthcheck.cpp
checks/qgsgeometryselfcontactcheck.cpp
checks/qgsgeometryselfintersectioncheck.cpp
checks/qgsgeometrysliverpolygoncheck.cpp
checks/qgsgeometrytypecheck.cpp
ui/qgsgeometrycheckerdialog.cpp
ui/qgsgeometrycheckersetuptab.cpp
@@ -17,61 +17,68 @@
#include "qgsgeometryutils.h"
#include "../utils/qgsfeaturepool.h"

void QgsGeometryAngleCheck::collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &/*messages*/, QAtomicInt *progressCounter, const QgsFeatureIds &ids ) const
void QgsGeometryAngleCheck::collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &/*messages*/, QAtomicInt *progressCounter, const QMap<QString, QgsFeatureIds> &ids ) const
{
const QgsFeatureIds &featureIds = ids.isEmpty() ? mFeaturePool->getFeatureIds() : ids;
Q_FOREACH ( QgsFeatureId featureid, featureIds )
QMap<QString, QgsFeatureIds> featureIds = ids.isEmpty() ? allLayerFeatureIds() : ids;
for ( const QString &layerId : featureIds.keys() )
{
if ( progressCounter ) progressCounter->fetchAndAddRelaxed( 1 );
QgsFeature feature;
if ( !mFeaturePool->get( featureid, feature ) )
if ( !getCompatibility( getFeaturePool( layerId )->getLayer()->geometryType() ) )
{
continue;
}
QgsGeometry g = feature.geometry();
const QgsAbstractGeometry *geom = g.geometry();
for ( int iPart = 0, nParts = geom->partCount(); iPart < nParts; ++iPart )
for ( QgsFeatureId featureid : featureIds[layerId] )
{
for ( int iRing = 0, nRings = geom->ringCount( iPart ); iRing < nRings; ++iRing )
if ( progressCounter ) progressCounter->fetchAndAddRelaxed( 1 );
QgsFeature feature;
if ( !getFeaturePool( layerId )->get( featureid, feature ) )
{
int nVerts = QgsGeometryCheckerUtils::polyLineSize( geom, iPart, iRing );
// Less than three points, no angles to check
if ( nVerts < 3 )
{
continue;
}
for ( int iVert = 0; iVert < nVerts; ++iVert )
continue;
}
QgsGeometry g = feature.geometry();
const QgsAbstractGeometry *geom = g.geometry();
for ( int iPart = 0, nParts = geom->partCount(); iPart < nParts; ++iPart )
{
for ( int iRing = 0, nRings = geom->ringCount( iPart ); iRing < nRings; ++iRing )
{
const QgsPoint &p1 = geom->vertexAt( QgsVertexId( iPart, iRing, ( iVert - 1 + nVerts ) % nVerts ) );
const QgsPoint &p2 = geom->vertexAt( QgsVertexId( iPart, iRing, iVert ) );
const QgsPoint &p3 = geom->vertexAt( QgsVertexId( iPart, iRing, ( iVert + 1 ) % nVerts ) );
QgsVector v21, v23;
try
int nVerts = QgsGeometryCheckerUtils::polyLineSize( geom, iPart, iRing );
// Less than three points, no angles to check
if ( nVerts < 3 )
{
v21 = QgsVector( p1.x() - p2.x(), p1.y() - p2.y() ).normalized();
v23 = QgsVector( p3.x() - p2.x(), p3.y() - p2.y() ).normalized();
}
catch ( const QgsException & )
{
// Zero length vectors
continue;
}

double angle = std::acos( v21 * v23 ) / M_PI * 180.0;
if ( angle < mMinAngle )
for ( int iVert = 0; iVert < nVerts; ++iVert )
{
errors.append( new QgsGeometryCheckError( this, featureid, p2, QgsVertexId( iPart, iRing, iVert ), angle ) );
const QgsPoint &p1 = geom->vertexAt( QgsVertexId( iPart, iRing, ( iVert - 1 + nVerts ) % nVerts ) );
const QgsPoint &p2 = geom->vertexAt( QgsVertexId( iPart, iRing, iVert ) );
const QgsPoint &p3 = geom->vertexAt( QgsVertexId( iPart, iRing, ( iVert + 1 ) % nVerts ) );
QgsVector v21, v23;
try
{
v21 = QgsVector( p1.x() - p2.x(), p1.y() - p2.y() ).normalized();
v23 = QgsVector( p3.x() - p2.x(), p3.y() - p2.y() ).normalized();
}
catch ( const QgsException & )
{
// Zero length vectors
continue;
}

double angle = std::acos( v21 * v23 ) / M_PI * 180.0;
if ( angle < mMinAngle )
{
errors.append( new QgsGeometryCheckError( this, layerId, featureid, p2, QgsVertexId( iPart, iRing, iVert ), angle ) );
}
}
}
}
}
}
}

void QgsGeometryAngleCheck::fixError( QgsGeometryCheckError *error, int method, int /*mergeAttributeIndex*/, Changes &changes ) const
void QgsGeometryAngleCheck::fixError( QgsGeometryCheckError *error, int method, const QMap<QString, int> & /*mergeAttributeIndices*/, Changes &changes ) const
{
QgsFeature feature;
if ( !mFeaturePool->get( error->featureId(), feature ) )
if ( !getFeaturePool( error->layerId() )->get( error->featureId(), feature ) )
{
error->setObsolete();
return;
@@ -132,15 +139,15 @@ void QgsGeometryAngleCheck::fixError( QgsGeometryCheckError *error, int method,
}
else
{
changes[error->featureId()].append( Change( ChangeNode, ChangeRemoved, vidx ) );
changes[error->layerId()][error->featureId()].append( Change( ChangeNode, ChangeRemoved, vidx ) );
if ( QgsGeometryUtils::sqrDistance2D( p1, p3 ) < QgsGeometryCheckPrecision::tolerance() * QgsGeometryCheckPrecision::tolerance()
&& QgsGeometryCheckerUtils::canDeleteVertex( geometry, vidx.part, vidx.ring ) &&
geometry->deleteVertex( error->vidx() ) ) // error->vidx points to p3 after removing p2
{
changes[error->featureId()].append( Change( ChangeNode, ChangeRemoved, QgsVertexId( vidx.part, vidx.ring, ( vidx.vertex + 1 ) % n ) ) );
changes[error->layerId()][error->featureId()].append( Change( ChangeNode, ChangeRemoved, QgsVertexId( vidx.part, vidx.ring, ( vidx.vertex + 1 ) % n ) ) );
}
feature.setGeometry( g );
mFeaturePool->updateFeature( feature );
getFeaturePool( error->layerId() )->updateFeature( feature );
error->setFixed( method );
}
}
@@ -23,12 +23,12 @@ class QgsGeometryAngleCheck : public QgsGeometryCheck
Q_OBJECT

public:
QgsGeometryAngleCheck( QgsFeaturePool *featurePool, double minAngle )
: QgsGeometryCheck( FeatureNodeCheck, featurePool )
, mMinAngle( minAngle )
QgsGeometryAngleCheck( const QMap<QString, QgsFeaturePool *> &featurePools, double minAngle )
: QgsGeometryCheck( FeatureNodeCheck, {QgsWkbTypes::LineGeometry, QgsWkbTypes::PolygonGeometry}, featurePools )
, mMinAngle( minAngle )
{}
void collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &messages, QAtomicInt *progressCounter = nullptr, const QgsFeatureIds &ids = QgsFeatureIds() ) const override;
void fixError( QgsGeometryCheckError *error, int method, int mergeAttributeIndex, Changes &changes ) const override;
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 getResolutionMethods() const override;
QString errorDescription() const override { return tr( "Minimal angle" ); }
QString errorName() const override { return QStringLiteral( "QgsGeometryAngleCheck" ); }
@@ -18,47 +18,54 @@
#include "qgsgeometryareacheck.h"
#include "../utils/qgsfeaturepool.h"

void QgsGeometryAreaCheck::collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &/*messages*/, QAtomicInt *progressCounter, const QgsFeatureIds &ids ) const
void QgsGeometryAreaCheck::collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &/*messages*/, QAtomicInt *progressCounter, const QMap<QString, QgsFeatureIds> &ids ) const
{
const QgsFeatureIds &featureIds = ids.isEmpty() ? mFeaturePool->getFeatureIds() : ids;
Q_FOREACH ( QgsFeatureId featureid, featureIds )
QMap<QString, QgsFeatureIds> featureIds = ids.isEmpty() ? allLayerFeatureIds() : ids;
for ( const QString &layerId : featureIds.keys() )
{
if ( progressCounter ) progressCounter->fetchAndAddRelaxed( 1 );
QgsFeature feature;
if ( !mFeaturePool->get( featureid, feature ) )
if ( !getCompatibility( getFeaturePool( layerId )->getLayer()->geometryType() ) )
{
continue;
}

QgsGeometry g = feature.geometry();
QgsAbstractGeometry *geom = g.geometry();
if ( dynamic_cast<QgsGeometryCollection *>( geom ) )
for ( QgsFeatureId featureid : featureIds[layerId] )
{
QgsGeometryCollection *multiGeom = static_cast<QgsGeometryCollection *>( geom );
for ( int i = 0, n = multiGeom->numGeometries(); i < n; ++i )
if ( progressCounter ) progressCounter->fetchAndAddRelaxed( 1 );
QgsFeature feature;
if ( !getFeaturePool( layerId )->get( featureid, feature ) )
{
double value;
if ( checkThreshold( multiGeom->geometryN( i ), value ) )
continue;
}

QgsGeometry g = feature.geometry();
QgsAbstractGeometry *geom = g.geometry();
if ( dynamic_cast<QgsGeometryCollection *>( geom ) )
{
QgsGeometryCollection *multiGeom = static_cast<QgsGeometryCollection *>( geom );
for ( int i = 0, n = multiGeom->numGeometries(); i < n; ++i )
{
errors.append( new QgsGeometryCheckError( this, featureid, multiGeom->geometryN( i )->centroid(), QgsVertexId( i ), value, QgsGeometryCheckError::ValueArea ) );
double value;
if ( checkThreshold( layerId, multiGeom->geometryN( i ), value ) )
{
errors.append( new QgsGeometryCheckError( this, layerId, featureid, multiGeom->geometryN( i )->centroid(), QgsVertexId( i ), value, QgsGeometryCheckError::ValueArea ) );
}
}
}
}
else
{
double value;
if ( checkThreshold( geom, value ) )
else
{
errors.append( new QgsGeometryCheckError( this, featureid, geom->centroid(), QgsVertexId( 0 ), value, QgsGeometryCheckError::ValueArea ) );
double value;
if ( checkThreshold( layerId, geom, value ) )
{
errors.append( new QgsGeometryCheckError( this, layerId, featureid, geom->centroid(), QgsVertexId( 0 ), value, QgsGeometryCheckError::ValueArea ) );
}
}
}
}
}

void QgsGeometryAreaCheck::fixError( QgsGeometryCheckError *error, int method, int mergeAttributeIndex, Changes &changes ) const
void QgsGeometryAreaCheck::fixError( QgsGeometryCheckError *error, int method, const QMap<QString, int> &mergeAttributeIndices, Changes &changes ) const
{
QgsFeature feature;
if ( !mFeaturePool->get( error->featureId(), feature ) )
if ( !getFeaturePool( error->layerId() )->get( error->featureId(), feature ) )
{
error->setObsolete();
return;
@@ -78,7 +85,7 @@ void QgsGeometryAreaCheck::fixError( QgsGeometryCheckError *error, int method, i
if ( dynamic_cast<QgsGeometryCollection *>( geom ) )
{
double value;
if ( !checkThreshold( static_cast<QgsGeometryCollection *>( geom )->geometryN( vidx.part ), value ) )
if ( !checkThreshold( error->layerId(), static_cast<QgsGeometryCollection *>( geom )->geometryN( vidx.part ), value ) )
{
error->setObsolete();
return;
@@ -87,7 +94,7 @@ void QgsGeometryAreaCheck::fixError( QgsGeometryCheckError *error, int method, i
else
{
double value;
if ( !checkThreshold( geom, value ) )
if ( !checkThreshold( error->layerId(), geom, value ) )
{
error->setObsolete();
return;
@@ -101,13 +108,13 @@ void QgsGeometryAreaCheck::fixError( QgsGeometryCheckError *error, int method, i
}
else if ( method == Delete )
{
deleteFeatureGeometryPart( feature, vidx.part, changes );
deleteFeatureGeometryPart( error->layerId(), feature, vidx.part, changes );
error->setFixed( method );
}
else if ( method == MergeLongestEdge || method == MergeLargestArea || method == MergeIdenticalAttribute )
{
QString errMsg;
if ( mergeWithNeighbor( feature, vidx.part, method, mergeAttributeIndex, changes, errMsg ) )
if ( mergeWithNeighbor( error->layerId(), feature, vidx.part, method, mergeAttributeIndices[error->layerId()], changes, errMsg ) )
{
error->setFixed( method );
}
@@ -122,20 +129,28 @@ void QgsGeometryAreaCheck::fixError( QgsGeometryCheckError *error, int method, i
}
}

bool QgsGeometryAreaCheck::mergeWithNeighbor( QgsFeature &feature, int partIdx, int method, int mergeAttributeIndex, Changes &changes, QString &errMsg ) const
bool QgsGeometryAreaCheck::checkThreshold( const QString &layerId, const QgsAbstractGeometry *geom, double &value ) const
{
value = geom->area();
double mapToLayerUnits = getFeaturePool( layerId )->getMapToLayerUnits();
double threshold = mThresholdMapUnits * mapToLayerUnits * mapToLayerUnits;
return value < threshold;
}

bool QgsGeometryAreaCheck::mergeWithNeighbor( const QString &layerId, QgsFeature &feature, int partIdx, int method, int mergeAttributeIndex, Changes &changes, QString &errMsg ) const
{
double maxVal = 0.;
QgsFeature mergeFeature;
int mergePartIdx = -1;
bool matchFound = false;
QgsGeometry g = feature.geometry();;
QgsGeometry g = feature.geometry();
QgsAbstractGeometry *geom = g.geometry();

// Search for touching neighboring geometries
Q_FOREACH ( QgsFeatureId testId, mFeaturePool->getIntersects( g.boundingBox() ) )
for ( QgsFeatureId testId : getFeaturePool( layerId )->getIntersects( g.boundingBox() ) )
{
QgsFeature testFeature;
if ( !mFeaturePool->get( testId, testFeature ) )
if ( !getFeaturePool( layerId )->get( testId, testFeature ) )
{
continue;
}
@@ -210,9 +225,9 @@ bool QgsGeometryAreaCheck::mergeWithNeighbor( QgsFeature &feature, int partIdx,
{
--mergePartIdx;
}
replaceFeatureGeometryPart( mergeFeature, mergePartIdx, combinedGeom, changes );
replaceFeatureGeometryPart( layerId, mergeFeature, mergePartIdx, combinedGeom, changes );
// Remove polygon from source geometry
deleteFeatureGeometryPart( feature, partIdx, changes );
deleteFeatureGeometryPart( layerId, feature, partIdx, changes );

return true;
}
@@ -25,23 +25,23 @@ class QgsGeometryAreaCheck : public QgsGeometryCheck
Q_OBJECT

public:
QgsGeometryAreaCheck( QgsFeaturePool *featurePool, double threshold )
: QgsGeometryCheck( FeatureCheck, featurePool )
, mThreshold( threshold )
QgsGeometryAreaCheck( const QMap<QString, QgsFeaturePool *> &featurePools, double thresholdMapUnits )
: QgsGeometryCheck( FeatureCheck, {QgsWkbTypes::PolygonGeometry}, featurePools )
, mThresholdMapUnits( thresholdMapUnits )
{}
void collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &messages, QAtomicInt *progressCounter = nullptr, const QgsFeatureIds &ids = QgsFeatureIds() ) const override;
void fixError( QgsGeometryCheckError *error, int method, int mergeAttributeIndex, Changes &changes ) const override;
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 getResolutionMethods() const override;
QString errorDescription() const override { return tr( "Minimal area" ); }
QString errorName() const override { return QStringLiteral( "QgsGeometryAreaCheck" ); }
private:
enum ResolutionMethod { MergeLongestEdge, MergeLargestArea, MergeIdenticalAttribute, Delete, NoChange };

bool mergeWithNeighbor( QgsFeature &feature, int partIdx, int method, int mergeAttributeIndex, Changes &changes, QString &errMsg ) const;
virtual bool checkThreshold( const QgsAbstractGeometry *geom, double &value ) const { value = geom->area(); return value < mThreshold; }
virtual bool checkThreshold( const QString &layerId, const QgsAbstractGeometry *geom, double &value ) const;
bool mergeWithNeighbor( const QString &layerId, QgsFeature &feature, int partIdx, int method, int mergeAttributeIndex, Changes &changes, QString &errMsg ) const;

protected:
double mThreshold;
double mThresholdMapUnits;
};

#endif // QGS_GEOMETRY_AREA_CHECK_H

0 comments on commit 31cc65d

Please sign in to comment.
You can’t perform that action at this time.