Skip to content

Commit 3842f42

Browse files
committed
[Geometry checker] Add line intersection check
1 parent b5208c0 commit 3842f42

File tree

7 files changed

+180
-3
lines changed

7 files changed

+180
-3
lines changed

src/plugins/geometry_checker/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ SET (geometrychecker_SRCS
1515
checks/qgsgeometrycheck.cpp
1616
checks/qgsgeometrygapcheck.cpp
1717
checks/qgsgeometryholecheck.cpp
18+
checks/qgsgeometrylineintersectioncheck.cpp
1819
checks/qgsgeometrymultipartcheck.cpp
1920
checks/qgsgeometrycontainedcheck.cpp
2021
checks/qgsgeometryoverlapcheck.cpp
@@ -53,6 +54,7 @@ SET (geometrychecker_MOC_HDRS
5354
checks/qgsgeometryduplicatenodescheck.h
5455
checks/qgsgeometrygapcheck.h
5556
checks/qgsgeometryholecheck.h
57+
checks/qgsgeometrylineintersectioncheck.h
5658
checks/qgsgeometrymultipartcheck.h
5759
checks/qgsgeometrycontainedcheck.h
5860
checks/qgsgeometryoverlapcheck.h
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/***************************************************************************
2+
qgsgeometrylineintersectioncheck.cpp
3+
---------------------
4+
begin : June 2017
5+
copyright : (C) 2017 by Sandro Mani / Sourcepole AG
6+
email : smani at sourcepole dot ch
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#include "qgsgeometrylineintersectioncheck.h"
17+
#include "qgslinestring.h"
18+
19+
void QgsGeometryLineIntersectionCheck::collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &/*messages*/, QAtomicInt *progressCounter, const QMap<QString, QgsFeatureIds> &ids ) const
20+
{
21+
QMap<QString, QgsFeatureIds> featureIds = ids.isEmpty() ? allLayerFeatureIds() : ids;
22+
QgsGeometryCheckerUtils::LayerFeatures layerFeatures( mContext->featurePools, featureIds, mCompatibleGeometryTypes, progressCounter, true );
23+
for ( const QgsGeometryCheckerUtils::LayerFeature &layerFeature : layerFeatures )
24+
{
25+
const QgsAbstractGeometry *geom = layerFeature.geometry();
26+
for ( int iPart = 0, nParts = geom->partCount(); iPart < nParts; ++iPart )
27+
{
28+
const QgsLineString *line = dynamic_cast<const QgsLineString *>( QgsGeometryCheckerUtils::getGeomPart( geom, iPart ) );
29+
if ( !line )
30+
{
31+
// Should not happen
32+
continue;
33+
}
34+
35+
// Check whether the line intersects with any other lines
36+
QgsGeometryCheckerUtils::LayerFeatures checkFeatures( mContext->featurePools, featureIds.keys(), line->boundingBox(), {QgsWkbTypes::LineGeometry} );
37+
for ( const QgsGeometryCheckerUtils::LayerFeature &checkFeature : checkFeatures )
38+
{
39+
if ( checkFeature.feature().id() == layerFeature.feature().id() )
40+
{
41+
// Skip current feature
42+
continue;
43+
}
44+
const QgsAbstractGeometry *testGeom = checkFeature.geometry();
45+
for ( int jPart = 0, mParts = testGeom->partCount(); jPart < mParts; ++jPart )
46+
{
47+
const QgsLineString *testLine = dynamic_cast<const QgsLineString *>( QgsGeometryCheckerUtils::getGeomPart( testGeom, jPart ) );
48+
if ( !testLine )
49+
{
50+
continue;
51+
}
52+
QgsPoint inter;
53+
if ( QgsGeometryCheckerUtils::linesIntersect( line, testLine, mContext->tolerance, inter ) )
54+
{
55+
errors.append( new QgsGeometryCheckError( this, layerFeature, inter ) );
56+
}
57+
}
58+
}
59+
}
60+
}
61+
}
62+
63+
void QgsGeometryLineIntersectionCheck::fixError( QgsGeometryCheckError *error, int method, const QMap<QString, int> & /*mergeAttributeIndices*/, Changes & /*changes*/ ) const
64+
{
65+
if ( method == NoChange )
66+
{
67+
error->setFixed( method );
68+
}
69+
else
70+
{
71+
error->setFixFailed( tr( "Unknown method" ) );
72+
}
73+
}
74+
75+
QStringList QgsGeometryLineIntersectionCheck::getResolutionMethods() const
76+
{
77+
static QStringList methods = QStringList() << tr( "No action" );
78+
return methods;
79+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/***************************************************************************
2+
qgsgeometrylineintersectioncheck.h
3+
---------------------
4+
begin : June 2017
5+
copyright : (C) 2017 by Sandro Mani / Sourcepole AG
6+
email : smani at sourcepole dot ch
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#ifndef QGSGEOMETRYLINEINTERSECTIONCHECK_H
17+
#define QGSGEOMETRYLINEINTERSECTIONCHECK_H
18+
19+
#include "qgsgeometrycheck.h"
20+
21+
class QgsGeometryLineIntersectionCheck : public QgsGeometryCheck
22+
{
23+
Q_OBJECT
24+
25+
public:
26+
QgsGeometryLineIntersectionCheck( QgsGeometryCheckerContext *context )
27+
: QgsGeometryCheck( FeatureNodeCheck, {QgsWkbTypes::LineGeometry}, context )
28+
{}
29+
void collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &messages, QAtomicInt *progressCounter = nullptr, const QMap<QString, QgsFeatureIds> &ids = QMap<QString, QgsFeatureIds>() ) const override;
30+
void fixError( QgsGeometryCheckError *error, int method, const QMap<QString, int> &mergeAttributeIndices, Changes &changes ) const override;
31+
QStringList getResolutionMethods() const override;
32+
QString errorDescription() const override { return tr( "Intersection" ); }
33+
QString errorName() const override { return QStringLiteral( "QgsGeometryLineIntersectionCheck" ); }
34+
private:
35+
enum ResolutionMethod { NoChange };
36+
};
37+
38+
#endif // QGSGEOMETRYLINEINTERSECTIONCHECK_H

src/plugins/geometry_checker/qgsgeometrycheckfactory.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "checks/qgsgeometryduplicatenodescheck.h"
2626
#include "checks/qgsgeometrygapcheck.h"
2727
#include "checks/qgsgeometryholecheck.h"
28+
#include "checks/qgsgeometrylineintersectioncheck.h"
2829
#include "checks/qgsgeometrymultipartcheck.h"
2930
#include "checks/qgsgeometryoverlapcheck.h"
3031
#include "checks/qgsgeometrypointcoveredbylinecheck.h"
@@ -299,6 +300,35 @@ REGISTER_QGS_GEOMETRY_CHECK_FACTORY( QgsGeometryCheckFactoryT<QgsGeometryHoleChe
299300

300301
///////////////////////////////////////////////////////////////////////////////
301302

303+
template<> void QgsGeometryCheckFactoryT<QgsGeometryLineIntersectionCheck>::restorePrevious( Ui::QgsGeometryCheckerSetupTab &ui ) const
304+
{
305+
ui.checkLineIntersection->setChecked( QgsSettings().value( sSettingsGroup + "checkLineIntersection" ).toBool() );
306+
}
307+
308+
template<> bool QgsGeometryCheckFactoryT<QgsGeometryLineIntersectionCheck>::checkApplicability( Ui::QgsGeometryCheckerSetupTab &ui, int /*nPoint*/, int nLineString, int /*nPolygon*/ ) const
309+
{
310+
ui.checkLineIntersection->setEnabled( nLineString > 0 );
311+
return ui.checkLineIntersection->isEnabled();
312+
}
313+
314+
template<> QgsGeometryCheck *QgsGeometryCheckFactoryT<QgsGeometryLineIntersectionCheck>::createInstance( QgsGeometryCheckerContext *context, const Ui::QgsGeometryCheckerSetupTab &ui ) const
315+
{
316+
QgsSettings().setValue( sSettingsGroup + "checkLineIntersection", ui.checkLineIntersection->isChecked() );
317+
if ( ui.checkLineIntersection->isEnabled() && ui.checkLineIntersection->isChecked() )
318+
{
319+
return new QgsGeometryLineIntersectionCheck( context );
320+
}
321+
else
322+
{
323+
return nullptr;
324+
}
325+
}
326+
327+
REGISTER_QGS_GEOMETRY_CHECK_FACTORY( QgsGeometryCheckFactoryT<QgsGeometryLineIntersectionCheck> )
328+
329+
///////////////////////////////////////////////////////////////////////////////
330+
331+
302332
template<> void QgsGeometryCheckFactoryT<QgsGeometryMultipartCheck>::restorePrevious( Ui::QgsGeometryCheckerSetupTab &ui ) const
303333
{
304334
ui.checkBoxMultipart->setChecked( QgsSettings().value( sSettingsGroup + "checkMultipart" ).toBool() );

src/plugins/geometry_checker/ui/qgsgeometrycheckersetuptab.ui

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
<x>0</x>
4444
<y>0</y>
4545
<width>626</width>
46-
<height>895</height>
46+
<height>918</height>
4747
</rect>
4848
</property>
4949
<layout class="QGridLayout" name="gridLayout_4">
@@ -511,6 +511,13 @@
511511
</property>
512512
</widget>
513513
</item>
514+
<item row="5" column="0">
515+
<widget class="QCheckBox" name="checkLineIntersection">
516+
<property name="text">
517+
<string>Lines must not intersect</string>
518+
</property>
519+
</widget>
520+
</item>
514521
<item row="0" column="0">
515522
<widget class="QCheckBox" name="checkBoxDuplicates">
516523
<property name="text">
@@ -535,7 +542,7 @@
535542
</property>
536543
</widget>
537544
</item>
538-
<item row="5" column="0" colspan="2">
545+
<item row="8" column="0" colspan="2">
539546
<widget class="QLabel" name="label">
540547
<property name="text">
541548
<string>&lt;i&gt;Note: Topology checks are performed in the current map CRS.&lt;/i&gt;</string>
@@ -552,7 +559,7 @@
552559
</property>
553560
</widget>
554561
</item>
555-
<item row="4" column="0" colspan="2">
562+
<item row="4" column="0">
556563
<widget class="QCheckBox" name="checkPointCoveredByLine">
557564
<property name="text">
558565
<string>Points must be covered by lines</string>

src/plugins/geometry_checker/utils/qgsgeometrycheckerutils.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,25 @@ namespace QgsGeometryCheckerUtils
222222
return false;
223223
}
224224

225+
bool linesIntersect( const QgsLineString *line1, const QgsLineString *line2, double tol, QgsPoint &inter )
226+
{
227+
for ( int i = 0, n = line1->vertexCount() - 1; i < n; ++i )
228+
{
229+
for ( int j = 0, m = line2->vertexCount() - 1; j < m; ++j )
230+
{
231+
QgsPoint p1 = line1->vertexAt( QgsVertexId( 0, 0, i ) );
232+
QgsPoint p2 = line1->vertexAt( QgsVertexId( 0, 0, i + 1 ) );
233+
QgsPoint q1 = line1->vertexAt( QgsVertexId( 0, 0, j ) );
234+
QgsPoint q2 = line1->vertexAt( QgsVertexId( 0, 0, j + 1 ) );
235+
if ( QgsGeometryUtils::segmentIntersection( p1, p2, q1, q2, inter, tol ) )
236+
{
237+
return true;
238+
}
239+
}
240+
}
241+
return false;
242+
}
243+
225244
double sharedEdgeLength( const QgsAbstractGeometry *geom1, const QgsAbstractGeometry *geom2, double tol )
226245
{
227246
double len = 0;

src/plugins/geometry_checker/utils/qgsgeometrycheckerutils.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ namespace QgsGeometryCheckerUtils
128128

129129
bool pointOnLine( const QgsPoint &p, const QgsLineString *line, double tol, bool excludeExtremities = false );
130130

131+
bool linesIntersect( const QgsLineString *line1, const QgsLineString *line2, double tol, QgsPoint &inter );
132+
131133
double sharedEdgeLength( const QgsAbstractGeometry *geom1, const QgsAbstractGeometry *geom2, double tol );
132134

133135
/**

0 commit comments

Comments
 (0)