Skip to content

Commit e001d5c

Browse files
committedMay 18, 2017
Add QgsGeometry::isSimple() - useful for self-intersection checks
1 parent 09975ce commit e001d5c

File tree

8 files changed

+87
-0
lines changed

8 files changed

+87
-0
lines changed
 

‎python/core/geometry/qgsgeometry.sip

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,19 @@ Returns true if WKB of the geometry is of WKBMulti* type
188188
:rtype: bool
189189
%End
190190

191+
bool isSimple() const;
192+
%Docstring
193+
Determines whether the geometry is simple (according to OGC definition),
194+
i.e. it has no anomalous geometric points, such as self-intersection or self-tangency.
195+
Uses GEOS library for the test.
196+
.. note::
197+
198+
This is useful mainly for linestrings and linear rings. Polygons are simple by definition,
199+
for checking anomalies in polygon geometries one can use isGeosValid().
200+
.. versionadded:: 3.0
201+
:rtype: bool
202+
%End
203+
191204
double area() const;
192205
%Docstring
193206
Returns the area of the geometry using GEOS

‎python/core/geometry/qgsgeometryengine.sip

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,13 @@ class QgsGeometryEngine
155155
:rtype: bool
156156
%End
157157

158+
virtual bool isSimple( QString *errorMsg = 0 ) const = 0;
159+
%Docstring
160+
Determines whether the geometry is simple (according to OGC definition).
161+
.. versionadded:: 3.0
162+
:rtype: bool
163+
%End
164+
158165
virtual int splitGeometry( const QgsLineString &splitLine,
159166
QList<QgsAbstractGeometry *> &newGeometries,
160167
bool topological,

‎src/core/geometry/qgsgeometry.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1980,6 +1980,15 @@ bool QgsGeometry::isGeosValid() const
19801980
return geos.isValid();
19811981
}
19821982

1983+
bool QgsGeometry::isSimple() const
1984+
{
1985+
if ( !d->geometry )
1986+
return false;
1987+
1988+
QgsGeos geos( d->geometry );
1989+
return geos.isSimple();
1990+
}
1991+
19831992
bool QgsGeometry::isGeosEqual( const QgsGeometry &g ) const
19841993
{
19851994
if ( !d->geometry || !g.d->geometry )

‎src/core/geometry/qgsgeometry.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,15 @@ class CORE_EXPORT QgsGeometry
213213
*/
214214
bool isGeosValid() const;
215215

216+
/** Determines whether the geometry is simple (according to OGC definition),
217+
* i.e. it has no anomalous geometric points, such as self-intersection or self-tangency.
218+
* Uses GEOS library for the test.
219+
* \note This is useful mainly for linestrings and linear rings. Polygons are simple by definition,
220+
* for checking anomalies in polygon geometries one can use isGeosValid().
221+
* \since QGIS 3.0
222+
*/
223+
bool isSimple() const;
224+
216225
/** Returns the area of the geometry using GEOS
217226
\since QGIS 1.5
218227
*/

‎src/core/geometry/qgsgeometryengine.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@ class CORE_EXPORT QgsGeometryEngine
8383
virtual bool isEqual( const QgsAbstractGeometry &geom, QString *errorMsg = nullptr ) const = 0;
8484
virtual bool isEmpty( QString *errorMsg ) const = 0;
8585

86+
/** Determines whether the geometry is simple (according to OGC definition).
87+
* \since QGIS 3.0
88+
*/
89+
virtual bool isSimple( QString *errorMsg = nullptr ) const = 0;
90+
8691
virtual int splitGeometry( const QgsLineString &splitLine,
8792
QList<QgsAbstractGeometry *> &newGeometries,
8893
bool topological,

‎src/core/geometry/qgsgeos.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1494,6 +1494,20 @@ bool QgsGeos::isEmpty( QString *errorMsg ) const
14941494
CATCH_GEOS_WITH_ERRMSG( false );
14951495
}
14961496

1497+
bool QgsGeos::isSimple( QString *errorMsg ) const
1498+
{
1499+
if ( !mGeos )
1500+
{
1501+
return false;
1502+
}
1503+
1504+
try
1505+
{
1506+
return GEOSisSimple_r( geosinit.ctxt, mGeos );
1507+
}
1508+
CATCH_GEOS_WITH_ERRMSG( false );
1509+
}
1510+
14971511
GEOSCoordSequence *QgsGeos::createCoordinateSequence( const QgsCurve *curve, double precision, bool forceClose )
14981512
{
14991513
bool segmentize = false;

‎src/core/geometry/qgsgeos.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ class CORE_EXPORT QgsGeos: public QgsGeometryEngine
7171
bool isValid( QString *errorMsg = nullptr ) const override;
7272
bool isEqual( const QgsAbstractGeometry &geom, QString *errorMsg = nullptr ) const override;
7373
bool isEmpty( QString *errorMsg = nullptr ) const override;
74+
bool isSimple( QString *errorMsg = nullptr ) const override;
7475

7576
/** Splits this geometry according to a given line.
7677
\param splitLine the line that splits the geometry

‎tests/src/core/testqgsgeometry.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ class TestQgsGeometry : public QObject
124124

125125
void makeValid();
126126

127+
void isSimple();
128+
127129
private:
128130
//! A helper method to do a render check to see if the geometry op is as expected
129131
bool renderCheck( const QString &testName, const QString &comment = QLatin1String( QLatin1String( "" ) ), int mismatchCount = 0 );
@@ -5423,5 +5425,32 @@ void TestQgsGeometry::makeValid()
54235425
}
54245426
}
54255427

5428+
void TestQgsGeometry::isSimple()
5429+
{
5430+
typedef QPair<QString, bool> InputWktAndExpectedResult;
5431+
QList<InputWktAndExpectedResult> geoms;
5432+
geoms << qMakePair( QString( "LINESTRING(0 0, 1 0, 1 1)" ), true );
5433+
geoms << qMakePair( QString( "LINESTRING(0 0, 1 0, 1 1, 0 0)" ), true ); // may be closed (linear ring)
5434+
geoms << qMakePair( QString( "LINESTRING(0 0, 1 0, 1 1, 0 -1)" ), false ); // self-intersection
5435+
geoms << qMakePair( QString( "LINESTRING(0 0, 1 0, 1 1, 0.5 0, 0 1)" ), false ); // self-tangency
5436+
geoms << qMakePair( QString( "POINT(1 1)" ), true ); // points are simple
5437+
geoms << qMakePair( QString( "POLYGON((0 0, 1 1, 1 1, 0 0))" ), true ); // polygons are always simple, even if they are invalid
5438+
geoms << qMakePair( QString( "MULTIPOINT((1 1), (2 2))" ), true );
5439+
geoms << qMakePair( QString( "MULTIPOINT((1 1), (1 1))" ), false ); // must not contain the same point twice
5440+
geoms << qMakePair( QString( "MULTILINESTRING((0 0, 1 0), (0 1, 1 1))" ), true );
5441+
geoms << qMakePair( QString( "MULTILINESTRING((0 0, 1 0), (0 0, 1 0))" ), true ); // may be touching at endpoints
5442+
geoms << qMakePair( QString( "MULTILINESTRING((0 0, 1 1), (0 1, 1 0))" ), false ); // must not intersect each other
5443+
geoms << qMakePair( QString( "MULTIPOLYGON(((0 0, 1 1, 1 1, 0 0)),((0 0, 1 1, 1 1, 0 0)))" ), true ); // multi-polygons are always simple
5444+
5445+
Q_FOREACH ( const InputWktAndExpectedResult &pair, geoms )
5446+
{
5447+
QgsGeometry gInput = QgsGeometry::fromWkt( pair.first );
5448+
QVERIFY( !gInput.isNull() );
5449+
5450+
bool res = gInput.isSimple();
5451+
QCOMPARE( res, pair.second );
5452+
}
5453+
}
5454+
54265455
QGSTEST_MAIN( TestQgsGeometry )
54275456
#include "testqgsgeometry.moc"

0 commit comments

Comments
 (0)
Please sign in to comment.