Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Merge pull request #5986 from nyalldawson/geometry_equals
Refine geometry equals checks
- Loading branch information
|
@@ -1354,6 +1354,8 @@ maintains Z or M dimensions from the input points and is more efficient. |
|
|
- exportToWkt() was renamed to asWkt() |
|
|
- exportToGeoJSON() was renamed to asJson() |
|
|
- closestSegmentWithContext() now returns an extra value, indicating whether the point is to the left of the geometry |
|
|
- equals() now performs a fast, strict equality check, where geometries are considered equal only if they have the |
|
|
exact same type, vertices and order. The slower topological test can be performed by calling isGeosEqual instead. |
|
|
|
|
|
|
|
|
QgsGeometryAnalyzer {#qgis_api_break_3_0_QgsGeometryAnalyzer} |
|
|
|
@@ -72,6 +72,9 @@ Constructor for QgsAbstractGeometry. |
|
|
virtual ~QgsAbstractGeometry(); |
|
|
QgsAbstractGeometry( const QgsAbstractGeometry &geom ); |
|
|
|
|
|
virtual bool operator==( const QgsAbstractGeometry &other ) const = 0; |
|
|
virtual bool operator!=( const QgsAbstractGeometry &other ) const = 0; |
|
|
|
|
|
virtual QgsAbstractGeometry *clone() const = 0 /Factory/; |
|
|
%Docstring |
|
|
Clones the geometry by performing a deep copy |
|
|
|
@@ -25,9 +25,7 @@ class QgsCircularString: QgsCurve |
|
|
public: |
|
|
QgsCircularString(); |
|
|
|
|
|
virtual bool operator==( const QgsCurve &other ) const; |
|
|
|
|
|
virtual bool operator!=( const QgsCurve &other ) const; |
|
|
virtual bool equals( const QgsCurve &other ) const; |
|
|
|
|
|
|
|
|
virtual QString geometryType() const; |
|
|
|
@@ -25,9 +25,7 @@ class QgsCompoundCurve: QgsCurve |
|
|
QgsCompoundCurve( const QgsCompoundCurve &curve ); |
|
|
~QgsCompoundCurve(); |
|
|
|
|
|
virtual bool operator==( const QgsCurve &other ) const; |
|
|
|
|
|
virtual bool operator!=( const QgsCurve &other ) const; |
|
|
virtual bool equals( const QgsCurve &other ) const; |
|
|
|
|
|
|
|
|
virtual QString geometryType() const; |
|
|
|
@@ -28,8 +28,17 @@ class QgsCurve: QgsAbstractGeometry |
|
|
Constructor for QgsCurve. |
|
|
%End |
|
|
|
|
|
virtual bool operator==( const QgsCurve &other ) const = 0; |
|
|
virtual bool operator!=( const QgsCurve &other ) const = 0; |
|
|
virtual bool equals( const QgsCurve &other ) const = 0; |
|
|
%Docstring |
|
|
Checks whether this curve exactly equals another curve. |
|
|
|
|
|
.. versionadded:: 3.0 |
|
|
%End |
|
|
|
|
|
virtual bool operator==( const QgsAbstractGeometry &other ) const; |
|
|
|
|
|
virtual bool operator!=( const QgsAbstractGeometry &other ) const; |
|
|
|
|
|
|
|
|
virtual QgsCurve *clone() const = 0 /Factory/; |
|
|
|
|
|
|
@@ -25,8 +25,10 @@ class QgsCurvePolygon: QgsSurface |
|
|
QgsCurvePolygon(); |
|
|
QgsCurvePolygon( const QgsCurvePolygon &p ); |
|
|
|
|
|
bool operator==( const QgsCurvePolygon &other ) const; |
|
|
bool operator!=( const QgsCurvePolygon &other ) const; |
|
|
virtual bool operator==( const QgsAbstractGeometry &other ) const; |
|
|
|
|
|
virtual bool operator!=( const QgsAbstractGeometry &other ) const; |
|
|
|
|
|
|
|
|
~QgsCurvePolygon(); |
|
|
|
|
|
|
@@ -247,13 +247,46 @@ return true for isEmpty(). |
|
|
bool isMultipart() const; |
|
|
%Docstring |
|
|
Returns true if WKB of the geometry is of WKBMulti* type |
|
|
%End |
|
|
|
|
|
bool equals( const QgsGeometry &geometry ) const; |
|
|
%Docstring |
|
|
Test if this geometry is exactly equal to another ``geometry``. |
|
|
|
|
|
This is a strict equality check, where the underlying geometries must |
|
|
have exactly the same type, component vertices and vertex order. |
|
|
|
|
|
Calling this method is dramatically faster than the topological |
|
|
equality test performed by isGeosEqual(). |
|
|
|
|
|
.. note:: |
|
|
|
|
|
Comparing two null geometries will return false. |
|
|
|
|
|
.. versionadded:: 1.5 |
|
|
|
|
|
.. seealso:: :py:func:`isGeosEqual()` |
|
|
%End |
|
|
|
|
|
bool isGeosEqual( const QgsGeometry & ) const; |
|
|
%Docstring |
|
|
Compares the geometry with another geometry using GEOS |
|
|
Compares the geometry with another geometry using GEOS. |
|
|
|
|
|
This method performs a slow, topological check, where geometries |
|
|
are considered equal if all of the their component edges overlap. E.g. |
|
|
lines with the same vertex locations but opposite direction will be |
|
|
considered equal by this method. |
|
|
|
|
|
Consider using the much faster, stricter equality test performed |
|
|
by equals() instead. |
|
|
|
|
|
.. note:: |
|
|
|
|
|
Comparing two null geometries will return false. |
|
|
|
|
|
.. versionadded:: 1.5 |
|
|
|
|
|
.. seealso:: :py:func:`equals()` |
|
|
%End |
|
|
|
|
|
bool isGeosValid() const; |
|
@@ -749,13 +782,6 @@ Tests for if geometry is contained in another (uses GEOS) |
|
|
%Docstring |
|
|
Tests for if geometry is disjoint of another (uses GEOS) |
|
|
|
|
|
.. versionadded:: 1.5 |
|
|
%End |
|
|
|
|
|
bool equals( const QgsGeometry &geometry ) const; |
|
|
%Docstring |
|
|
Test for if geometry equals another (uses GEOS) |
|
|
|
|
|
.. versionadded:: 1.5 |
|
|
%End |
|
|
|
|
|
|
@@ -27,6 +27,11 @@ class QgsGeometryCollection: QgsAbstractGeometry |
|
|
QgsGeometryCollection( const QgsGeometryCollection &c ); |
|
|
~QgsGeometryCollection(); |
|
|
|
|
|
virtual bool operator==( const QgsAbstractGeometry &other ) const; |
|
|
|
|
|
virtual bool operator!=( const QgsAbstractGeometry &other ) const; |
|
|
|
|
|
|
|
|
virtual QgsGeometryCollection *clone() const /Factory/; |
|
|
|
|
|
|
|
|
|
@@ -57,9 +57,7 @@ or repeatedly calling addVertex() |
|
|
.. versionadded:: 3.0 |
|
|
%End |
|
|
|
|
|
virtual bool operator==( const QgsCurve &other ) const; |
|
|
|
|
|
virtual bool operator!=( const QgsCurve &other ) const; |
|
|
virtual bool equals( const QgsCurve &other ) const; |
|
|
|
|
|
|
|
|
QgsPoint pointN( int i ) const; |
|
|
|
@@ -85,8 +85,10 @@ Construct a QgsPoint from a QPointF |
|
|
%End |
|
|
|
|
|
|
|
|
bool operator==( const QgsPoint &pt ) const; |
|
|
bool operator!=( const QgsPoint &pt ) const; |
|
|
virtual bool operator==( const QgsAbstractGeometry &other ) const; |
|
|
|
|
|
virtual bool operator!=( const QgsAbstractGeometry &other ) const; |
|
|
|
|
|
|
|
|
double x() const; |
|
|
%Docstring |
|
|
|
@@ -202,7 +202,7 @@ QVariantMap QgsSplitWithLinesAlgorithm::processAlgorithm( const QVariantMap &par |
|
|
// between geometry and splitLine, only the first one is considered. |
|
|
if ( result == QgsGeometry::Success ) // split occurred |
|
|
{ |
|
|
if ( inGeom.equals( before ) ) |
|
|
if ( inGeom.isGeosEqual( before ) ) |
|
|
{ |
|
|
// bug in splitGeometry: sometimes it returns 0 but |
|
|
// the geometry is unchanged |
|
|
|
@@ -110,6 +110,9 @@ class CORE_EXPORT QgsAbstractGeometry |
|
|
QgsAbstractGeometry( const QgsAbstractGeometry &geom ); |
|
|
QgsAbstractGeometry &operator=( const QgsAbstractGeometry &geom ); |
|
|
|
|
|
virtual bool operator==( const QgsAbstractGeometry &other ) const = 0; |
|
|
virtual bool operator!=( const QgsAbstractGeometry &other ) const = 0; |
|
|
|
|
|
/** |
|
|
* Clones the geometry by performing a deep copy |
|
|
*/ |
|
|
|
@@ -33,7 +33,7 @@ QgsCircularString::QgsCircularString() |
|
|
mWkbType = QgsWkbTypes::CircularString; |
|
|
} |
|
|
|
|
|
bool QgsCircularString::operator==( const QgsCurve &other ) const |
|
|
bool QgsCircularString::equals( const QgsCurve &other ) const |
|
|
{ |
|
|
const QgsCircularString *otherLine = dynamic_cast< const QgsCircularString * >( &other ); |
|
|
if ( !otherLine ) |
|
@@ -61,11 +61,6 @@ bool QgsCircularString::operator==( const QgsCurve &other ) const |
|
|
return true; |
|
|
} |
|
|
|
|
|
bool QgsCircularString::operator!=( const QgsCurve &other ) const |
|
|
{ |
|
|
return !operator==( other ); |
|
|
} |
|
|
|
|
|
QgsCircularString *QgsCircularString::createEmptyWithSameType() const |
|
|
{ |
|
|
auto result = qgis::make_unique< QgsCircularString >(); |
|
|
|
@@ -36,8 +36,7 @@ class CORE_EXPORT QgsCircularString: public QgsCurve |
|
|
public: |
|
|
QgsCircularString(); |
|
|
|
|
|
bool operator==( const QgsCurve &other ) const override; |
|
|
bool operator!=( const QgsCurve &other ) const override; |
|
|
bool equals( const QgsCurve &other ) const override; |
|
|
|
|
|
QString geometryType() const override; |
|
|
int dimension() const override; |
|
|
|
@@ -35,7 +35,7 @@ QgsCompoundCurve::~QgsCompoundCurve() |
|
|
clear(); |
|
|
} |
|
|
|
|
|
bool QgsCompoundCurve::operator==( const QgsCurve &other ) const |
|
|
bool QgsCompoundCurve::equals( const QgsCurve &other ) const |
|
|
{ |
|
|
const QgsCompoundCurve *otherCurve = qgsgeometry_cast< const QgsCompoundCurve * >( &other ); |
|
|
if ( !otherCurve ) |
|
@@ -56,11 +56,6 @@ bool QgsCompoundCurve::operator==( const QgsCurve &other ) const |
|
|
return true; |
|
|
} |
|
|
|
|
|
bool QgsCompoundCurve::operator!=( const QgsCurve &other ) const |
|
|
{ |
|
|
return !operator==( other ); |
|
|
} |
|
|
|
|
|
QgsCompoundCurve *QgsCompoundCurve::createEmptyWithSameType() const |
|
|
{ |
|
|
auto result = qgis::make_unique< QgsCompoundCurve >(); |
|
|
|
@@ -36,8 +36,7 @@ class CORE_EXPORT QgsCompoundCurve: public QgsCurve |
|
|
QgsCompoundCurve &operator=( const QgsCompoundCurve &curve ); |
|
|
~QgsCompoundCurve() override; |
|
|
|
|
|
bool operator==( const QgsCurve &other ) const override; |
|
|
bool operator!=( const QgsCurve &other ) const override; |
|
|
bool equals( const QgsCurve &other ) const override; |
|
|
|
|
|
QString geometryType() const override; |
|
|
int dimension() const override; |
|
|
|
@@ -22,6 +22,20 @@ |
|
|
#include "qgspoint.h" |
|
|
#include "qgsmultipoint.h" |
|
|
|
|
|
bool QgsCurve::operator==( const QgsAbstractGeometry &other ) const |
|
|
{ |
|
|
const QgsCurve *otherCurve = qgsgeometry_cast< const QgsCurve * >( &other ); |
|
|
if ( !otherCurve ) |
|
|
return false; |
|
|
|
|
|
return equals( *otherCurve ); |
|
|
} |
|
|
|
|
|
bool QgsCurve::operator!=( const QgsAbstractGeometry &other ) const |
|
|
{ |
|
|
return !operator==( other ); |
|
|
} |
|
|
|
|
|
bool QgsCurve::isClosed() const |
|
|
{ |
|
|
if ( numPoints() == 0 ) |
|
|
|
@@ -41,8 +41,14 @@ class CORE_EXPORT QgsCurve: public QgsAbstractGeometry |
|
|
*/ |
|
|
QgsCurve() = default; |
|
|
|
|
|
virtual bool operator==( const QgsCurve &other ) const = 0; |
|
|
virtual bool operator!=( const QgsCurve &other ) const = 0; |
|
|
/** |
|
|
* Checks whether this curve exactly equals another curve. |
|
|
* \since QGIS 3.0 |
|
|
*/ |
|
|
virtual bool equals( const QgsCurve &other ) const = 0; |
|
|
|
|
|
bool operator==( const QgsAbstractGeometry &other ) const override; |
|
|
bool operator!=( const QgsAbstractGeometry &other ) const override; |
|
|
|
|
|
QgsCurve *clone() const override = 0 SIP_FACTORY; |
|
|
|
|
|
|
@@ -90,40 +90,44 @@ QgsCurvePolygon &QgsCurvePolygon::operator=( const QgsCurvePolygon &p ) |
|
|
return *this; |
|
|
} |
|
|
|
|
|
bool QgsCurvePolygon::operator==( const QgsCurvePolygon &other ) const |
|
|
bool QgsCurvePolygon::operator==( const QgsAbstractGeometry &other ) const |
|
|
{ |
|
|
const QgsCurvePolygon *otherPolygon = qgsgeometry_cast< const QgsCurvePolygon * >( &other ); |
|
|
if ( !otherPolygon ) |
|
|
return false; |
|
|
|
|
|
//run cheap checks first |
|
|
if ( mWkbType != other.mWkbType ) |
|
|
if ( mWkbType != otherPolygon->mWkbType ) |
|
|
return false; |
|
|
|
|
|
if ( ( !mExteriorRing && other.mExteriorRing ) || ( mExteriorRing && !other.mExteriorRing ) ) |
|
|
if ( ( !mExteriorRing && otherPolygon->mExteriorRing ) || ( mExteriorRing && !otherPolygon->mExteriorRing ) ) |
|
|
return false; |
|
|
|
|
|
if ( mInteriorRings.count() != other.mInteriorRings.count() ) |
|
|
if ( mInteriorRings.count() != otherPolygon->mInteriorRings.count() ) |
|
|
return false; |
|
|
|
|
|
// compare rings |
|
|
if ( mExteriorRing && other.mExteriorRing ) |
|
|
if ( mExteriorRing && otherPolygon->mExteriorRing ) |
|
|
{ |
|
|
if ( *mExteriorRing != *other.mExteriorRing ) |
|
|
if ( *mExteriorRing != *otherPolygon->mExteriorRing ) |
|
|
return false; |
|
|
} |
|
|
|
|
|
for ( int i = 0; i < mInteriorRings.count(); ++i ) |
|
|
{ |
|
|
if ( ( !mInteriorRings.at( i ) && other.mInteriorRings.at( i ) ) || |
|
|
( mInteriorRings.at( i ) && !other.mInteriorRings.at( i ) ) ) |
|
|
if ( ( !mInteriorRings.at( i ) && otherPolygon->mInteriorRings.at( i ) ) || |
|
|
( mInteriorRings.at( i ) && !otherPolygon->mInteriorRings.at( i ) ) ) |
|
|
return false; |
|
|
|
|
|
if ( mInteriorRings.at( i ) && other.mInteriorRings.at( i ) && |
|
|
*mInteriorRings.at( i ) != *other.mInteriorRings.at( i ) ) |
|
|
if ( mInteriorRings.at( i ) && otherPolygon->mInteriorRings.at( i ) && |
|
|
*mInteriorRings.at( i ) != *otherPolygon->mInteriorRings.at( i ) ) |
|
|
return false; |
|
|
} |
|
|
|
|
|
return true; |
|
|
} |
|
|
|
|
|
bool QgsCurvePolygon::operator!=( const QgsCurvePolygon &other ) const |
|
|
bool QgsCurvePolygon::operator!=( const QgsAbstractGeometry &other ) const |
|
|
{ |
|
|
return !operator==( other ); |
|
|
} |
|
|
|
@@ -38,8 +38,8 @@ class CORE_EXPORT QgsCurvePolygon: public QgsSurface |
|
|
QgsCurvePolygon( const QgsCurvePolygon &p ); |
|
|
QgsCurvePolygon &operator=( const QgsCurvePolygon &p ); |
|
|
|
|
|
bool operator==( const QgsCurvePolygon &other ) const; |
|
|
bool operator!=( const QgsCurvePolygon &other ) const; |
|
|
bool operator==( const QgsAbstractGeometry &other ) const override; |
|
|
bool operator!=( const QgsAbstractGeometry &other ) const override; |
|
|
|
|
|
~QgsCurvePolygon() override; |
|
|
|
|
|
|
@@ -1147,9 +1147,12 @@ bool QgsGeometry::equals( const QgsGeometry &geometry ) const |
|
|
return false; |
|
|
} |
|
|
|
|
|
QgsGeos geos( d->geometry.get() ); |
|
|
mLastError.clear(); |
|
|
return geos.isEqual( geometry.d->geometry.get(), &mLastError ); |
|
|
// fast check - are they shared copies of the same underlying geometry? |
|
|
if ( d == geometry.d ) |
|
|
return true; |
|
|
|
|
|
// slower check - actually test the geometries |
|
|
return *d->geometry.get() == *geometry.d->geometry.get(); |
|
|
} |
|
|
|
|
|
bool QgsGeometry::touches( const QgsGeometry &geometry ) const |
|
|
Oops, something went wrong.