Skip to content

Commit

Permalink
[Geometry checker] Add point must be covered by line check
Browse files Browse the repository at this point in the history
  • Loading branch information
manisandro committed Oct 23, 2017
1 parent 7fb1c55 commit ee47d42
Show file tree
Hide file tree
Showing 6 changed files with 197 additions and 35 deletions.
2 changes: 2 additions & 0 deletions src/plugins/geometry_checker/CMakeLists.txt
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
@@ -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<QgsGeometryCheckError *> &errors, QStringList &/*messages*/, QAtomicInt *progressCounter, const QMap<QString, QgsFeatureIds> &ids ) const
{
QMap<QString, QgsFeatureIds> 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<const QgsPoint *>( 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<const QgsLineString *>( 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<QString, int> & /*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;
}
@@ -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<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( "Point not covered by line" ); }
QString errorName() const override { return QStringLiteral( "QgsGeometryPointCoveredByLineCheck" ); }
private:
enum ResolutionMethod { NoChange };
};

#endif // QGSGEOMETRYPOINTCOVEREDBYLINECHECK_H
29 changes: 29 additions & 0 deletions src/plugins/geometry_checker/qgsgeometrycheckfactory.cpp
Expand Up @@ -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"
Expand Down Expand Up @@ -356,6 +357,34 @@ REGISTER_QGS_GEOMETRY_CHECK_FACTORY( QgsGeometryCheckFactoryT<QgsGeometryOverlap

///////////////////////////////////////////////////////////////////////////////

template<> void QgsGeometryCheckFactoryT<QgsGeometryPointCoveredByLineCheck>::restorePrevious( Ui::QgsGeometryCheckerSetupTab &ui ) const
{
ui.checkPointCoveredByLine->setChecked( QgsSettings().value( sSettingsGroup + "checkPointCoveredByLine" ).toBool() );
}

template<> bool QgsGeometryCheckFactoryT<QgsGeometryPointCoveredByLineCheck>::checkApplicability( Ui::QgsGeometryCheckerSetupTab &ui, int nPoint, int /*nLineString*/, int /*nPolygon*/ ) const
{
ui.checkPointCoveredByLine->setEnabled( nPoint > 0 );
return ui.checkPointCoveredByLine->isEnabled();
}

template<> QgsGeometryCheck *QgsGeometryCheckFactoryT<QgsGeometryPointCoveredByLineCheck>::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<QgsGeometryPointCoveredByLineCheck> )

///////////////////////////////////////////////////////////////////////////////

template<> void QgsGeometryCheckFactoryT<QgsGeometrySegmentLengthCheck>::restorePrevious( Ui::QgsGeometryCheckerSetupTab &ui ) const
{
ui.checkBoxSegmentLength->setChecked( QgsSettings().value( sSettingsGroup + "checkSegmentLength" ).toBool() );
Expand Down
75 changes: 41 additions & 34 deletions src/plugins/geometry_checker/ui/qgsgeometrycheckersetuptab.ui
Expand Up @@ -43,7 +43,7 @@
<x>0</x>
<y>0</y>
<width>626</width>
<height>872</height>
<height>895</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_4">
Expand Down Expand Up @@ -485,30 +485,16 @@
<property name="spacing">
<number>2</number>
</property>
<item row="0" column="0">
<widget class="QCheckBox" name="checkBoxDuplicates">
<property name="text">
<string>Check for duplicates</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBoxOverlapArea">
<property name="decimals">
<number>6</number>
</property>
<property name="maximum">
<double>999999999.000000000000000</double>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBoxGapArea">
<property name="decimals">
<number>6</number>
<item row="3" column="0">
<widget class="QCheckBox" name="checkBoxGaps">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximum">
<double>999999999.000000000000000</double>
<property name="text">
<string>Check for gaps smaller than (map units sqr.)</string>
</property>
</widget>
</item>
Expand All @@ -525,16 +511,10 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="checkBoxGaps">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item row="0" column="0">
<widget class="QCheckBox" name="checkBoxDuplicates">
<property name="text">
<string>Check for gaps smaller than (map units sqr.)</string>
<string>Check for duplicates</string>
</property>
</widget>
</item>
Expand All @@ -545,13 +525,40 @@
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<item row="3" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBoxGapArea">
<property name="decimals">
<number>6</number>
</property>
<property name="maximum">
<double>999999999.000000000000000</double>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QLabel" name="label">
<property name="text">
<string>&lt;i&gt;Note: Topology checks are performed in the current map CRS.&lt;/i&gt;</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBoxOverlapArea">
<property name="decimals">
<number>6</number>
</property>
<property name="maximum">
<double>999999999.000000000000000</double>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QCheckBox" name="checkPointCoveredByLine">
<property name="text">
<string>Points must be covered by lines</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
Expand Down
Expand Up @@ -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;
Expand Down

0 comments on commit ee47d42

Please sign in to comment.