Skip to content

Commit 33d6b51

Browse files
authored
Merge pull request #4232 from manisandro/geomchecker
Geometry checker: Add self-contact check
2 parents 9754590 + db138ff commit 33d6b51

6 files changed

+178
-13
lines changed

src/plugins/geometry_checker/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ SET (geometrychecker_SRCS
1818
checks/qgsgeometrycontainedcheck.cpp
1919
checks/qgsgeometryoverlapcheck.cpp
2020
checks/qgsgeometrysegmentlengthcheck.cpp
21+
checks/qgsgeometryselfcontactcheck.cpp
2122
checks/qgsgeometryselfintersectioncheck.cpp
2223
checks/qgsgeometrytypecheck.cpp
2324
ui/qgsgeometrycheckerdialog.cpp
@@ -52,6 +53,7 @@ SET (geometrychecker_MOC_HDRS
5253
checks/qgsgeometrycontainedcheck.h
5354
checks/qgsgeometryoverlapcheck.h
5455
checks/qgsgeometrysegmentlengthcheck.h
56+
checks/qgsgeometryselfcontactcheck.h
5557
checks/qgsgeometryselfintersectioncheck.h
5658
checks/qgsgeometrysliverpolygoncheck.h
5759
checks/qgsgeometrytypecheck.h
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/***************************************************************************
2+
* qgsgeometryselfcontactcheck.cpp *
3+
* ------------------- *
4+
* copyright : (C) 2017 by Sandro Mani / Sourcepole AG *
5+
* email : smani@sourcepole.ch *
6+
***************************************************************************/
7+
8+
#include "qgsgeometryselfcontactcheck.h"
9+
#include "qgsgeometryutils.h"
10+
#include "../utils/qgsfeaturepool.h"
11+
12+
void QgsGeometrySelfContactCheck::collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &/*messages*/, QAtomicInt *progressCounter, const QgsFeatureIds &ids ) const
13+
{
14+
const QgsFeatureIds &featureIds = ids.isEmpty() ? mFeaturePool->getFeatureIds() : ids;
15+
double tolerance = QgsGeometryCheckPrecision::tolerance();
16+
foreach ( const QgsFeatureId &featureid, featureIds )
17+
{
18+
if ( progressCounter ) progressCounter->fetchAndAddRelaxed( 1 );
19+
QgsFeature feature;
20+
if ( !mFeaturePool->get( featureid, feature ) )
21+
{
22+
continue;
23+
}
24+
QgsAbstractGeometry *geom = feature.geometry().geometry();
25+
26+
for ( int iPart = 0, nParts = geom->partCount(); iPart < nParts; ++iPart )
27+
{
28+
for ( int iRing = 0, nRings = geom->ringCount( iPart ); iRing < nRings; ++iRing )
29+
{
30+
// Test for self-contacts
31+
int n = geom->vertexCount( iPart, iRing );
32+
bool isClosed = geom->vertexAt( QgsVertexId( iPart, iRing, 0 ) ) == geom->vertexAt( QgsVertexId( iPart, iRing, n - 1 ) );
33+
34+
// Geometry ring without duplicate nodes
35+
QVector<int> vtxMap;
36+
QVector<QgsPointV2> ring;
37+
vtxMap.append( 0 );
38+
ring.append( geom->vertexAt( QgsVertexId( iPart, iRing, 0 ) ) );
39+
for ( int i = 1; i < n; ++i )
40+
{
41+
QgsPointV2 p = geom->vertexAt( QgsVertexId( iPart, iRing, i ) );
42+
if ( QgsGeometryUtils::sqrDistance2D( p, ring.last() ) > tolerance * tolerance )
43+
{
44+
vtxMap.append( i );
45+
ring.append( p );
46+
}
47+
}
48+
while ( QgsGeometryUtils::sqrDistance2D( ring.front(), ring.back() ) < tolerance * tolerance )
49+
{
50+
vtxMap.pop_back();
51+
ring.pop_back();
52+
}
53+
if ( isClosed )
54+
{
55+
vtxMap.append( n - 1 );
56+
ring.append( ring.front() );
57+
}
58+
n = ring.size();
59+
60+
// For each vertex, check whether it lies on a segment
61+
for ( int iVert = 0, nVerts = n - isClosed; iVert < nVerts; ++iVert )
62+
{
63+
const QgsPointV2 &p = ring[iVert];
64+
for ( int i = 0, j = 1; j < n; i = j++ )
65+
{
66+
if ( iVert == i || iVert == j || ( isClosed && iVert == 0 && j == n - 1 ) )
67+
{
68+
continue;
69+
}
70+
const QgsPointV2 &si = ring[i];
71+
const QgsPointV2 &sj = ring[j];
72+
QgsPointV2 q = QgsGeometryUtils::projPointOnSegment( p, si, sj );
73+
if ( QgsGeometryUtils::sqrDistance2D( p, q ) < tolerance * tolerance )
74+
{
75+
errors.append( new QgsGeometryCheckError( this, featureid, p, QgsVertexId( iPart, iRing, vtxMap[iVert] ) ) );
76+
break; // No need to report same contact on different segments multiple times
77+
}
78+
}
79+
}
80+
}
81+
}
82+
}
83+
}
84+
85+
void QgsGeometrySelfContactCheck::fixError( QgsGeometryCheckError *error, int method, int /*mergeAttributeIndex*/, Changes & /*changes*/ ) const
86+
{
87+
if ( method == NoChange )
88+
{
89+
error->setFixed( method );
90+
}
91+
else
92+
{
93+
error->setFixFailed( tr( "Unknown method" ) );
94+
}
95+
}
96+
97+
QStringList QgsGeometrySelfContactCheck::getResolutionMethods() const
98+
{
99+
static QStringList methods = QStringList() << tr( "No action" );
100+
return methods;
101+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/***************************************************************************
2+
* qgsgeometryselfcontactcheck.h *
3+
* ------------------- *
4+
* copyright : (C) 2017 by Sandro Mani / Sourcepole AG *
5+
* email : smani@sourcepole.ch *
6+
***************************************************************************/
7+
8+
#ifndef QGS_GEOMETRY_SELFCONTACT_CHECK_H
9+
#define QGS_GEOMETRY_SELFCONTACT_CHECK_H
10+
11+
#include "qgsgeometrycheck.h"
12+
13+
class QgsGeometrySelfContactCheck : public QgsGeometryCheck
14+
{
15+
Q_OBJECT
16+
17+
public:
18+
QgsGeometrySelfContactCheck( QgsFeaturePool *featurePool )
19+
: QgsGeometryCheck( FeatureNodeCheck, featurePool ) {}
20+
void collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &messages, QAtomicInt *progressCounter = 0, const QgsFeatureIds &ids = QgsFeatureIds() ) const;
21+
void fixError( QgsGeometryCheckError *error, int method, int, Changes & ) const;
22+
QStringList getResolutionMethods() const;
23+
QString errorDescription() const { return tr( "Self contact" ); }
24+
QString errorName() const { return "QgsGeometrySelfContactCheck"; }
25+
private:
26+
enum ResolutionMethod { NoChange };
27+
};
28+
29+
#endif // QGS_GEOMETRY_SELFCONTACT_CHECK_H

src/plugins/geometry_checker/checks/qgsgeometryselfintersectioncheck.cpp

-2
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@
2525
bool QgsGeometrySelfIntersectionCheckError::isEqual( QgsGeometryCheckError *other ) const
2626
{
2727
return QgsGeometryCheckError::isEqual( other ) &&
28-
other->featureId() == featureId() &&
29-
other->vidx() == vidx() &&
3028
static_cast<QgsGeometrySelfIntersectionCheckError *>( other )->intersection().segment1 == intersection().segment1 &&
3129
static_cast<QgsGeometrySelfIntersectionCheckError *>( other )->intersection().segment2 == intersection().segment2;
3230
}

src/plugins/geometry_checker/qgsgeometrycheckfactory.cpp

+29
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "checks/qgsgeometrymultipartcheck.h"
2828
#include "checks/qgsgeometryoverlapcheck.h"
2929
#include "checks/qgsgeometrysegmentlengthcheck.h"
30+
#include "checks/qgsgeometryselfcontactcheck.h"
3031
#include "checks/qgsgeometryselfintersectioncheck.h"
3132
#include "checks/qgsgeometrysliverpolygoncheck.h"
3233
#include "checks/qgsgeometrytypecheck.h"
@@ -357,6 +358,34 @@ REGISTER_QGS_GEOMETRY_CHECK_FACTORY( QgsGeometryCheckFactoryT<QgsGeometrySegment
357358

358359
///////////////////////////////////////////////////////////////////////////////
359360

361+
template<> void QgsGeometryCheckFactoryT<QgsGeometrySelfContactCheck>::restorePrevious( Ui::QgsGeometryCheckerSetupTab &ui ) const
362+
{
363+
ui.checkBoxSelfContacts->setChecked( QgsSettings().value( sSettingsGroup + "checkSelfContacts" ).toBool() );
364+
}
365+
366+
template<> bool QgsGeometryCheckFactoryT<QgsGeometrySelfContactCheck>::checkApplicability( Ui::QgsGeometryCheckerSetupTab &ui, QgsWkbTypes::GeometryType geomType ) const
367+
{
368+
ui.checkBoxSelfContacts->setEnabled( geomType == QgsWkbTypes::PolygonGeometry || geomType == QgsWkbTypes::LineGeometry );
369+
return ui.checkBoxSelfContacts->isEnabled();
370+
}
371+
372+
template<> QgsGeometryCheck *QgsGeometryCheckFactoryT<QgsGeometrySelfContactCheck>::createInstance( QgsFeaturePool *featurePool, const Ui::QgsGeometryCheckerSetupTab &ui, double /*mapToLayerUnits*/ ) const
373+
{
374+
QgsSettings().setValue( sSettingsGroup + "checkSelfContacts", ui.checkBoxSelfContacts->isChecked() );
375+
if ( ui.checkBoxSelfContacts->isEnabled() && ui.checkBoxSelfContacts->isChecked() )
376+
{
377+
return new QgsGeometrySelfContactCheck( featurePool );
378+
}
379+
else
380+
{
381+
return 0;
382+
}
383+
}
384+
385+
REGISTER_QGS_GEOMETRY_CHECK_FACTORY( QgsGeometryCheckFactoryT<QgsGeometrySelfContactCheck> )
386+
387+
///////////////////////////////////////////////////////////////////////////////
388+
360389
template<> void QgsGeometryCheckFactoryT<QgsGeometrySelfIntersectionCheck>::restorePrevious( Ui::QgsGeometryCheckerSetupTab &ui ) const
361390
{
362391
ui.checkBoxSelfIntersections->setChecked( QgsSettings().value( sSettingsGroup + "checkSelfIntersections" ).toBool() );

src/plugins/geometry_checker/ui/qgsgeometrycheckersetuptab.ui

+17-11
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@
4141
<property name="geometry">
4242
<rect>
4343
<x>0</x>
44-
<y>-301</y>
45-
<width>670</width>
46-
<height>776</height>
44+
<y>0</y>
45+
<width>626</width>
46+
<height>726</height>
4747
</rect>
4848
</property>
4949
<layout class="QGridLayout" name="gridLayout_4">
@@ -117,10 +117,7 @@
117117
<property name="flat">
118118
<bool>true</bool>
119119
</property>
120-
<layout class="QVBoxLayout" name="verticalLayout_4">
121-
<property name="spacing">
122-
<number>2</number>
123-
</property>
120+
<layout class="QGridLayout" name="gridLayout_8">
124121
<property name="leftMargin">
125122
<number>2</number>
126123
</property>
@@ -133,7 +130,7 @@
133130
<property name="bottomMargin">
134131
<number>2</number>
135132
</property>
136-
<item>
133+
<item row="0" column="0">
137134
<widget class="QCheckBox" name="checkBoxSelfIntersections">
138135
<property name="text">
139136
<string>Self intersections</string>
@@ -143,7 +140,7 @@
143140
</property>
144141
</widget>
145142
</item>
146-
<item>
143+
<item row="1" column="0">
147144
<widget class="QCheckBox" name="checkBoxDuplicateNodes">
148145
<property name="text">
149146
<string>Duplicate nodes</string>
@@ -153,7 +150,7 @@
153150
</property>
154151
</widget>
155152
</item>
156-
<item>
153+
<item row="1" column="1">
157154
<widget class="QCheckBox" name="checkBoxDegeneratePolygon">
158155
<property name="text">
159156
<string>Polygon with less than 3 nodes</string>
@@ -163,6 +160,16 @@
163160
</property>
164161
</widget>
165162
</item>
163+
<item row="0" column="1">
164+
<widget class="QCheckBox" name="checkBoxSelfContacts">
165+
<property name="text">
166+
<string>Self contacts</string>
167+
</property>
168+
<property name="checked">
169+
<bool>true</bool>
170+
</property>
171+
</widget>
172+
</item>
166173
</layout>
167174
</widget>
168175
</item>
@@ -728,7 +735,6 @@
728735
<tabstop>checkBoxInputSelectedOnly</tabstop>
729736
<tabstop>checkBoxSelfIntersections</tabstop>
730737
<tabstop>checkBoxDuplicateNodes</tabstop>
731-
<tabstop>checkBoxDegeneratePolygon</tabstop>
732738
<tabstop>checkBoxPoint</tabstop>
733739
<tabstop>checkBoxMultipoint</tabstop>
734740
<tabstop>checkBoxLine</tabstop>

0 commit comments

Comments
 (0)