diff --git a/src/plugins/geometry_checker/CMakeLists.txt b/src/plugins/geometry_checker/CMakeLists.txt index 08800440531..2baba325bcb 100644 --- a/src/plugins/geometry_checker/CMakeLists.txt +++ b/src/plugins/geometry_checker/CMakeLists.txt @@ -18,6 +18,7 @@ SET (geometrychecker_SRCS checks/qgsgeometrymultipartcheck.cpp checks/qgsgeometrycontainedcheck.cpp checks/qgsgeometryoverlapcheck.cpp + checks/qgsgeometrypointcoveredbylinecheck.cpp checks/qgsgeometrysegmentlengthcheck.cpp checks/qgsgeometryselfcontactcheck.cpp checks/qgsgeometryselfintersectioncheck.cpp @@ -55,6 +56,7 @@ SET (geometrychecker_MOC_HDRS checks/qgsgeometrymultipartcheck.h checks/qgsgeometrycontainedcheck.h checks/qgsgeometryoverlapcheck.h + checks/qgsgeometrypointcoveredbylinecheck.h checks/qgsgeometrysegmentlengthcheck.h checks/qgsgeometryselfcontactcheck.h checks/qgsgeometryselfintersectioncheck.h diff --git a/src/plugins/geometry_checker/checks/qgsgeometrypointcoveredbylinecheck.cpp b/src/plugins/geometry_checker/checks/qgsgeometrypointcoveredbylinecheck.cpp new file mode 100644 index 00000000000..29becf2aaf3 --- /dev/null +++ b/src/plugins/geometry_checker/checks/qgsgeometrypointcoveredbylinecheck.cpp @@ -0,0 +1,86 @@ +/*************************************************************************** + qgsgeometrypointcoveredbylinecheck.cpp + --------------------- + begin : June 2017 + copyright : (C) 2017 by Sandro Mani / Sourcepole AG + email : smani at sourcepole dot 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 "qgsgeometrypointcoveredbylinecheck.h" +#include "qgslinestring.h" +#include "../utils/qgsfeaturepool.h" + +void QgsGeometryPointCoveredByLineCheck::collectErrors( QList &errors, QStringList &/*messages*/, QAtomicInt *progressCounter, const QMap &ids ) const +{ + QMap featureIds = ids.isEmpty() ? allLayerFeatureIds() : ids; + QgsGeometryCheckerUtils::LayerFeatures layerFeatures( mContext->featurePools, featureIds, mCompatibleGeometryTypes, progressCounter, true ); + for ( const QgsGeometryCheckerUtils::LayerFeature &layerFeature : layerFeatures ) + { + const QgsAbstractGeometry *geom = layerFeature.geometry(); + for ( int iPart = 0, nParts = geom->partCount(); iPart < nParts; ++iPart ) + { + const QgsPoint *point = dynamic_cast( QgsGeometryCheckerUtils::getGeomPart( geom, iPart ) ); + if ( !point ) + { + // Should not happen + continue; + } + // Check that point lies on a line + bool touches = false; + QgsRectangle rect( point->x() - mContext->tolerance, point->y() - mContext->tolerance, + point->x() + mContext->tolerance, point->y() + mContext->tolerance ); + QgsGeometryCheckerUtils::LayerFeatures checkFeatures( mContext->featurePools, featureIds.keys(), rect, {QgsWkbTypes::LineGeometry} ); + for ( const QgsGeometryCheckerUtils::LayerFeature &checkFeature : checkFeatures ) + { + const QgsAbstractGeometry *testGeom = checkFeature.geometry(); + for ( int jPart = 0, mParts = testGeom->partCount(); jPart < mParts; ++jPart ) + { + const QgsLineString *testLine = dynamic_cast( QgsGeometryCheckerUtils::getGeomPart( testGeom, jPart ) ); + if ( !testLine ) + { + continue; + } + if ( QgsGeometryCheckerUtils::pointOnLine( *point, testLine, mContext->tolerance ) ) + { + touches = true; + break; + } + } + if ( touches == true ) + { + break; + } + } + if ( touches == true ) + { + continue; + } + errors.append( new QgsGeometryCheckError( this, layerFeature, *point, QgsVertexId( iPart, 0, 0 ) ) ); + } + } +} + +void QgsGeometryPointCoveredByLineCheck::fixError( QgsGeometryCheckError *error, int method, const QMap & /*mergeAttributeIndices*/, Changes & /*changes*/ ) const +{ + if ( method == NoChange ) + { + error->setFixed( method ); + } + else + { + error->setFixFailed( tr( "Unknown method" ) ); + } +} + +QStringList QgsGeometryPointCoveredByLineCheck::getResolutionMethods() const +{ + static QStringList methods = QStringList() << tr( "No action" ); + return methods; +} diff --git a/src/plugins/geometry_checker/checks/qgsgeometrypointcoveredbylinecheck.h b/src/plugins/geometry_checker/checks/qgsgeometrypointcoveredbylinecheck.h new file mode 100644 index 00000000000..a65896474a6 --- /dev/null +++ b/src/plugins/geometry_checker/checks/qgsgeometrypointcoveredbylinecheck.h @@ -0,0 +1,38 @@ +/*************************************************************************** + qgsgeometrypointcoveredbylinecheck.h + --------------------- + begin : June 2017 + copyright : (C) 2017 by Sandro Mani / Sourcepole AG + email : smani at sourcepole dot 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. * + * * + ***************************************************************************/ + +#ifndef QGSGEOMETRYPOINTCOVEREDBYLINECHECK_H +#define QGSGEOMETRYPOINTCOVEREDBYLINECHECK_H + +#include "qgsgeometrycheck.h" + +class QgsGeometryPointCoveredByLineCheck : public QgsGeometryCheck +{ + Q_OBJECT + + public: + QgsGeometryPointCoveredByLineCheck( QgsGeometryCheckerContext *context ) + : QgsGeometryCheck( FeatureNodeCheck, {QgsWkbTypes::PointGeometry}, context ) + {} + void collectErrors( QList &errors, QStringList &messages, QAtomicInt *progressCounter = nullptr, const QMap &ids = QMap() ) const override; + void fixError( QgsGeometryCheckError *error, int method, const QMap &mergeAttributeIndices, Changes &changes ) const override; + QStringList getResolutionMethods() const override; + QString errorDescription() const override { return tr( "Point not covered by line" ); } + QString errorName() const override { return QStringLiteral( "QgsGeometryPointCoveredByLineCheck" ); } + private: + enum ResolutionMethod { NoChange }; +}; + +#endif // QGSGEOMETRYPOINTCOVEREDBYLINECHECK_H diff --git a/src/plugins/geometry_checker/qgsgeometrycheckfactory.cpp b/src/plugins/geometry_checker/qgsgeometrycheckfactory.cpp index 1ed89a0b1cf..60486752b5b 100644 --- a/src/plugins/geometry_checker/qgsgeometrycheckfactory.cpp +++ b/src/plugins/geometry_checker/qgsgeometrycheckfactory.cpp @@ -27,6 +27,7 @@ #include "checks/qgsgeometryholecheck.h" #include "checks/qgsgeometrymultipartcheck.h" #include "checks/qgsgeometryoverlapcheck.h" +#include "checks/qgsgeometrypointcoveredbylinecheck.h" #include "checks/qgsgeometrysegmentlengthcheck.h" #include "checks/qgsgeometryselfcontactcheck.h" #include "checks/qgsgeometryselfintersectioncheck.h" @@ -356,6 +357,34 @@ REGISTER_QGS_GEOMETRY_CHECK_FACTORY( QgsGeometryCheckFactoryT void QgsGeometryCheckFactoryT::restorePrevious( Ui::QgsGeometryCheckerSetupTab &ui ) const +{ + ui.checkPointCoveredByLine->setChecked( QgsSettings().value( sSettingsGroup + "checkPointCoveredByLine" ).toBool() ); +} + +template<> bool QgsGeometryCheckFactoryT::checkApplicability( Ui::QgsGeometryCheckerSetupTab &ui, int nPoint, int /*nLineString*/, int /*nPolygon*/ ) const +{ + ui.checkPointCoveredByLine->setEnabled( nPoint > 0 ); + return ui.checkPointCoveredByLine->isEnabled(); +} + +template<> QgsGeometryCheck *QgsGeometryCheckFactoryT::createInstance( QgsGeometryCheckerContext *context, const Ui::QgsGeometryCheckerSetupTab &ui ) const +{ + QgsSettings().setValue( sSettingsGroup + "checkPointCoveredByLine", ui.checkPointCoveredByLine->isChecked() ); + if ( ui.checkPointCoveredByLine->isEnabled() && ui.checkPointCoveredByLine->isChecked() ) + { + return new QgsGeometryPointCoveredByLineCheck( context ); + } + else + { + return nullptr; + } +} + +REGISTER_QGS_GEOMETRY_CHECK_FACTORY( QgsGeometryCheckFactoryT ) + +/////////////////////////////////////////////////////////////////////////////// + template<> void QgsGeometryCheckFactoryT::restorePrevious( Ui::QgsGeometryCheckerSetupTab &ui ) const { ui.checkBoxSegmentLength->setChecked( QgsSettings().value( sSettingsGroup + "checkSegmentLength" ).toBool() ); diff --git a/src/plugins/geometry_checker/ui/qgsgeometrycheckersetuptab.ui b/src/plugins/geometry_checker/ui/qgsgeometrycheckersetuptab.ui index aea7dcd4e41..d4dbd9d0b5d 100644 --- a/src/plugins/geometry_checker/ui/qgsgeometrycheckersetuptab.ui +++ b/src/plugins/geometry_checker/ui/qgsgeometrycheckersetuptab.ui @@ -43,7 +43,7 @@ 0 0 626 - 872 + 895 @@ -485,30 +485,16 @@ 2 - - + + + + + 0 + 0 + + - Check for duplicates - - - - - - - 6 - - - 999999999.000000000000000 - - - - - - - 6 - - - 999999999.000000000000000 + Check for gaps smaller than (map units sqr.) @@ -525,16 +511,10 @@ - - - - - 0 - 0 - - + + - Check for gaps smaller than (map units sqr.) + Check for duplicates @@ -545,13 +525,40 @@ - + + + + 6 + + + 999999999.000000000000000 + + + + <i>Note: Topology checks are performed in the current map CRS.</i> + + + + 6 + + + 999999999.000000000000000 + + + + + + + Points must be covered by lines + + + diff --git a/src/plugins/geometry_checker/utils/qgsgeometrycheckerutils.cpp b/src/plugins/geometry_checker/utils/qgsgeometrycheckerutils.cpp index 46b1ab66864..a285715c846 100644 --- a/src/plugins/geometry_checker/utils/qgsgeometrycheckerutils.cpp +++ b/src/plugins/geometry_checker/utils/qgsgeometrycheckerutils.cpp @@ -213,7 +213,7 @@ namespace QgsGeometryCheckerUtils { QgsPoint p1 = line->vertexAt( QgsVertexId( 0, 0, i ) ); QgsPoint p2 = line->vertexAt( QgsVertexId( 0, 0, i + 1 ) ); - double dist = pointLineDist( p1, p2, 1 ); + double dist = pointLineDist( p1, p2, p ); if ( dist < tol ) { return true;