diff --git a/python/core/qgsgeometry.sip b/python/core/qgsgeometry.sip index 4b90b2587b3..dd1f52d84b5 100644 --- a/python/core/qgsgeometry.sip +++ b/python/core/qgsgeometry.sip @@ -475,5 +475,27 @@ class QgsGeometry @returns the new computed QgsGeometry, or null */ static QgsGeometry *unaryUnion( const QList& geometryList ) /Factory/; + + /** Compares two polylines for equality within a specified tolerance. + * @param p1 first polyline + * @param p2 second polyline + * @param epsilon maximum difference for coordinates between the polylines + * @returns true if polylines have the same number of points and all + * points are equal within the specified tolerance + * @note added in QGIS 2.9 + */ + static bool compare( const QgsPolyline& p1, const QgsPolyline& p2, double epsilon = 4 * DBL_EPSILON ); + + /** Compares two polygons for equality within a specified tolerance. + * @param p1 first polygon + * @param p2 second polygon + * @param epsilon maximum difference for coordinates between the polygons + * @returns true if polygons have the same number of rings, and each ring has the same + * number of points and all points are equal within the specified tolerance + * @note added in QGIS 2.9 + */ + static bool compare( const QgsPolygon& p1, const QgsPolygon& p2, double epsilon = 4 * DBL_EPSILON ); + + }; // class QgsGeometry diff --git a/python/core/qgspoint.sip b/python/core/qgspoint.sip index 6bfe2decfed..8dea5598b9b 100644 --- a/python/core/qgspoint.sip +++ b/python/core/qgspoint.sip @@ -113,6 +113,14 @@ class QgsPoint /**Calculates azimuth between this point and other one (clockwise in degree, starting from north) */ double azimuth( const QgsPoint& other ); + /** Compares this point with another point with a fuzzy tolerance + * @param other point to compare with + * @param epsilon maximum difference for coordinates between the points + * @returns true if points are equal within specified tolerance + * @note added in QGIS 2.9 + */ + bool compare( const QgsPoint &other, double epsilon = 4 * DBL_EPSILON ) const; + //! equality operator bool operator==( const QgsPoint &other ); diff --git a/src/core/qgsgeometry.cpp b/src/core/qgsgeometry.cpp index ab7281a58b1..43a59d6efeb 100644 --- a/src/core/qgsgeometry.cpp +++ b/src/core/qgsgeometry.cpp @@ -6632,3 +6632,29 @@ QgsGeometry *QgsGeometry::unaryUnion( const QList &geometryList ) ret->fromGeos( geomUnion ); return ret; } + +bool QgsGeometry::compare( const QgsPolyline &p1, const QgsPolyline &p2, double epsilon ) +{ + if ( p1.count() != p2.count() ) + return false; + + for ( int i = 0; i < p1.count(); ++i ) + { + if ( !p1.at( i ).compare( p2.at( i ), epsilon ) ) + return false; + } + return true; +} + +bool QgsGeometry::compare( const QgsPolygon &p1, const QgsPolygon &p2, double epsilon ) +{ + if ( p1.count() != p2.count() ) + return false; + + for ( int i = 0; i < p1.count(); ++i ) + { + if ( !QgsGeometry::compare( p1.at( i ), p2.at( i ), epsilon ) ) + return false; + } + return true; +} diff --git a/src/core/qgsgeometry.h b/src/core/qgsgeometry.h index 36d23ace23d..4e2516acaa8 100644 --- a/src/core/qgsgeometry.h +++ b/src/core/qgsgeometry.h @@ -521,6 +521,26 @@ class CORE_EXPORT QgsGeometry */ static QgsGeometry *unaryUnion( const QList& geometryList ); + /** Compares two polylines for equality within a specified tolerance. + * @param p1 first polyline + * @param p2 second polyline + * @param epsilon maximum difference for coordinates between the polylines + * @returns true if polylines have the same number of points and all + * points are equal within the specified tolerance + * @note added in QGIS 2.9 + */ + static bool compare( const QgsPolyline& p1, const QgsPolyline& p2, double epsilon = 4 * DBL_EPSILON ); + + /** Compares two polygons for equality within a specified tolerance. + * @param p1 first polygon + * @param p2 second polygon + * @param epsilon maximum difference for coordinates between the polygons + * @returns true if polygons have the same number of rings, and each ring has the same + * number of points and all points are equal within the specified tolerance + * @note added in QGIS 2.9 + */ + static bool compare( const QgsPolygon& p1, const QgsPolygon& p2, double epsilon = 4 * DBL_EPSILON ); + private: // Private variables @@ -687,7 +707,7 @@ class CORE_EXPORT QgsWkbPtr inline const QgsWkbPtr &operator>>( char &v ) const { memcpy( &v, mP, sizeof( v ) ); mP += sizeof( v ); return *this; } inline const QgsWkbPtr &operator>>( QGis::WkbType &v ) const { memcpy( &v, mP, sizeof( v ) ); mP += sizeof( v ); return *this; } #ifdef QT_ARCH_ARM - inline const QgsWkbPtr &operator>>( qreal &v ) const { double d; memcpy( &d, mP, sizeof( d ) ); mP += sizeof( d ); v=d; return *this; } + inline const QgsWkbPtr &operator>>( qreal &v ) const { double d; memcpy( &d, mP, sizeof( d ) ); mP += sizeof( d ); v = d; return *this; } #endif inline QgsWkbPtr &operator<<( const double &v ) { memcpy( mP, &v, sizeof( v ) ); mP += sizeof( v ); return *this; } @@ -717,7 +737,7 @@ class CORE_EXPORT QgsConstWkbPtr inline const QgsConstWkbPtr &operator>>( char &v ) const { memcpy( &v, mP, sizeof( v ) ); mP += sizeof( v ); return *this; } inline const QgsConstWkbPtr &operator>>( QGis::WkbType &v ) const { memcpy( &v, mP, sizeof( v ) ); mP += sizeof( v ); return *this; } #ifdef QT_ARCH_ARM - inline const QgsConstWkbPtr &operator>>( qreal &v ) const { double d; memcpy( &d, mP, sizeof( d ) ); mP += sizeof( d ); v=d; return *this; } + inline const QgsConstWkbPtr &operator>>( qreal &v ) const { double d; memcpy( &d, mP, sizeof( d ) ); mP += sizeof( d ); v = d; return *this; } #endif inline void operator+=( int n ) { mP += n; } diff --git a/src/core/qgspoint.cpp b/src/core/qgspoint.cpp index 3a6ae698641..afde54e7e9a 100644 --- a/src/core/qgspoint.cpp +++ b/src/core/qgspoint.cpp @@ -347,6 +347,11 @@ double QgsPoint::azimuth( const QgsPoint& other ) return ( atan2( dx, dy ) * 180.0 / M_PI ); } +bool QgsPoint::compare( const QgsPoint &other, double epsilon ) const +{ + return ( qgsDoubleNear( m_x, other.x(), epsilon ) && qgsDoubleNear( m_y, other.y(), epsilon ) ); +} + // operators bool QgsPoint::operator==( const QgsPoint & other ) { diff --git a/src/core/qgspoint.h b/src/core/qgspoint.h index 0c866e04855..392f10f879d 100644 --- a/src/core/qgspoint.h +++ b/src/core/qgspoint.h @@ -189,6 +189,14 @@ class CORE_EXPORT QgsPoint /**Calculates azimuth between this point and other one (clockwise in degree, starting from north) */ double azimuth( const QgsPoint& other ); + /** Compares this point with another point with a fuzzy tolerance + * @param other point to compare with + * @param epsilon maximum difference for coordinates between the points + * @returns true if points are equal within specified tolerance + * @note added in QGIS 2.9 + */ + bool compare( const QgsPoint &other, double epsilon = 4 * DBL_EPSILON ) const; + //! equality operator bool operator==( const QgsPoint &other ); diff --git a/tests/src/core/testqgsgeometry.cpp b/tests/src/core/testqgsgeometry.cpp index 3dbcb94d9f9..fe18a395198 100644 --- a/tests/src/core/testqgsgeometry.cpp +++ b/tests/src/core/testqgsgeometry.cpp @@ -57,6 +57,9 @@ class TestQgsGeometry : public QObject void asQPointF(); void asQPolygonF(); + void comparePolylines(); + void comparePolygons(); + // MK, Disabled 14.11.2014 // Too unclear what exactly should be tested and which variations are allowed for the line #if 0 @@ -300,6 +303,48 @@ void TestQgsGeometry::asQPolygonF() QVERIFY( fromBad.isEmpty() ); } +void TestQgsGeometry::comparePolylines() +{ + QgsPolyline line1; + line1 << mPoint1 << mPoint2 << mPoint3; + QgsPolyline line2; + line2 << mPoint1 << mPoint2 << mPoint3; + QVERIFY( QgsGeometry::compare( line1, line2 ) ); + + //different number of nodes + QgsPolyline line3; + line3 << mPoint1 << mPoint2 << mPoint3 << mPoint4; + QVERIFY( !QgsGeometry::compare( line1, line3 ) ); + + //different nodes + QgsPolyline line4; + line3 << mPoint1 << mPointA << mPoint3 << mPoint4; + QVERIFY( !QgsGeometry::compare( line3, line4 ) ); +} + +void TestQgsGeometry::comparePolygons() +{ + QgsPolyline ring1; + ring1 << mPoint1 << mPoint2 << mPoint3 << mPoint1; + QgsPolyline ring2; + ring2 << mPoint4 << mPointA << mPointB << mPoint4; + QgsPolygon poly1; + poly1 << ring1 << ring2; + QgsPolygon poly2; + poly2 << ring1 << ring2; + QVERIFY( QgsGeometry::compare( poly1, poly2 ) ); + + //different number of rings + QgsPolygon poly3; + poly3 << ring1; + QVERIFY( !QgsGeometry::compare( poly1, poly3 ) ); + + //different rings + QgsPolygon poly4; + poly4 << ring2; + QVERIFY( !QgsGeometry::compare( poly3, poly4 ) ); +} + void TestQgsGeometry::initTestCase() { // diff --git a/tests/src/core/testqgspoint.cpp b/tests/src/core/testqgspoint.cpp index 0e572387a96..a8fd1769771 100644 --- a/tests/src/core/testqgspoint.cpp +++ b/tests/src/core/testqgspoint.cpp @@ -51,6 +51,8 @@ class TestQgsPoint: public QObject void sqrDist(); void multiply(); void onSegment(); + void compare(); + private: QgsPoint mPoint1; QgsPoint mPoint2; @@ -591,5 +593,16 @@ void TestQgsPoint::onSegment() } +void TestQgsPoint::compare() +{ + QgsPoint point1( 5.000000000001, 9.0 ); + QgsPoint point2( 5.0, 8.999999999999999 ); + QVERIFY( point1.compare( point2, 0.00000001 ) ); + QgsPoint point3( 5.0, 6.0 ); + QVERIFY( !( point3.compare( point1 ) ) ); + QgsPoint point4( 10 / 3.0, 12 / 7.0 ); + QVERIFY( point4.compare( QgsPoint( 10 / 3.0, 12 / 7.0 ) ) ); +} + QTEST_MAIN( TestQgsPoint ) #include "testqgspoint.moc"