diff --git a/python/core/geometry/qgspointv2.sip b/python/core/geometry/qgspointv2.sip index 62abfe203c3..d797b08ff77 100644 --- a/python/core/geometry/qgspointv2.sip +++ b/python/core/geometry/qgspointv2.sip @@ -173,6 +173,41 @@ class QgsPointV2: public QgsAbstractGeometry */ double distanceSquared( const QgsPointV2& other ) const; + /** + * Returns the 3D distance between this point and a specified x, y, z coordinate. In certain + * cases it may be more appropriate to call the faster distanceSquared() method, e.g., + * when comparing distances. + * @note added in QGIS 3.0 + * @see distanceSquared() + */ + double distance3D( double x, double y, double z ) const; + + /** + * Returns the 3D distance between this point and another point. In certain + * cases it may be more appropriate to call the faster distanceSquared() method, e.g., + * when comparing distances. + * @note added in QGIS 3.0 + */ + double distance3D( const QgsPointV2& other ) const; + + /** + * Returns the 3D squared distance between this point a specified x, y, z coordinate. Calling + * this is faster than calling distance(), and may be useful in use cases such as comparing + * distances where the extra expense of calling distance() is not required. + * @see distance() + * @note added in QGIS 3.0 + */ + double distanceSquared3D( double x, double y, double z ) const; + + /** + * Returns the 3D squared distance between this point another point. Calling + * this is faster than calling distance(), and may be useful in use cases such as comparing + * distances where the extra expense of calling distance() is not required. + * @see distance() + * @note added in QGIS 3.0 + */ + double distanceSquared3D( const QgsPointV2& other ) const; + /** * Calculates azimuth between this point and other one (clockwise in degree, starting from north) * @note added in QGIS 3.0 @@ -208,6 +243,27 @@ class QgsPointV2: public QgsAbstractGeometry */ QgsPointV2 project( double distance, double azimuth, double inclination = 90.0 ) const; + /** Returns a middle point between this point and other one. + * Z value is computed if one of this point have Z. + * M value is computed if one of this point have M. + * @param other other point. + * @return New point at middle between this and other one. + * Example: + * \code{.py} + * p = QgsPointV2( 4, 6 ) # 2D point + * pr = p.midpoint ( QgsPointV2( 2, 2 ) ) + * # pr is a 2D point: 'Point (3 4)' + * pr = p.midpoint ( QgsPointV2( QgsWkbTypes.PointZ, 2, 2, 2 ) ) + * # pr is a 3D point: 'PointZ (3 4 1)' + * pr = p.midpoint ( QgsPointV2( QgsWkbTypes.PointM, 2, 2, 0, 2 ) ) + * # pr is a 3D point: 'PointM (3 4 1)' + * pr = p.midpoint ( QgsPointV2( QgsWkbTypes.PointZM, 2, 2, 2, 2 ) ) + * # pr is a 4D point: 'PointZM (3 4 1 1)' + * \endcode + * @note added in QGIS 3.0 + */ + QgsPointV2 midpoint (const QgsPointV2& other) const; + /** * Calculates the vector obtained by subtracting a point from this point. * @note added in QGIS 3.0 diff --git a/src/core/geometry/qgspointv2.cpp b/src/core/geometry/qgspointv2.cpp index c582651a16a..e44fb609b03 100644 --- a/src/core/geometry/qgspointv2.cpp +++ b/src/core/geometry/qgspointv2.cpp @@ -438,12 +438,12 @@ QPointF QgsPointV2::toQPointF() const double QgsPointV2::distance( double x, double y ) const { - return sqrt(( mX - x ) * ( mX - x ) + ( mY - y ) * ( mY - y ) ); + return sqrt( ( mX - x ) * ( mX - x ) + ( mY - y ) * ( mY - y ) ); } double QgsPointV2::distance( const QgsPointV2& other ) const { - return sqrt(( mX - other.x() ) * ( mX - other.x() ) + ( mY - other.y() ) * ( mY - other.y() ) ); + return sqrt( ( mX - other.x() ) * ( mX - other.x() ) + ( mY - other.y() ) * ( mY - other.y() ) ); } double QgsPointV2::distanceSquared( double x, double y ) const @@ -451,11 +451,31 @@ double QgsPointV2::distanceSquared( double x, double y ) const return ( mX - x ) * ( mX - x ) + ( mY - y ) * ( mY - y ); } -double QgsPointV2::distanceSquared( const QgsPointV2& other ) const +double QgsPointV2::distanceSquared( const QgsPointV2& other) const { return ( mX - other.x() ) * ( mX - other.x() ) + ( mY - other.y() ) * ( mY - other.y() ) ; } +double QgsPointV2::distance3D( double x, double y, double z ) const +{ + return sqrt( ( mX - x ) * ( mX - x ) + ( mY - y ) * ( mY - y ) + ( mZ - z ) * ( mZ - z ) ); +} + +double QgsPointV2::distance3D( const QgsPointV2& other ) const +{ + return sqrt( ( mX - other.x() ) * ( mX - other.x() ) + ( mY - other.y() ) * ( mY - other.y() ) + ( mZ - other.z() ) * ( mZ - other.z() ) ); +} + +double QgsPointV2::distanceSquared3D( double x, double y, double z ) const +{ + return ( mX - x ) * ( mX - x ) + ( mY - y ) * ( mY - y ) + ( mZ - z ) * ( mZ - z ); +} + +double QgsPointV2::distanceSquared3D( const QgsPointV2& other) const +{ + return ( mX - other.x() ) * ( mX - other.x() ) + ( mY - other.y() ) * ( mY - other.y() ) + ( mZ - other.z() ) * ( mZ - other.z() ); +} + double QgsPointV2::azimuth( const QgsPointV2& other ) const { double dx = other.x() - mX; @@ -494,3 +514,28 @@ QgsPointV2 QgsPointV2::project( double distance, double azimuth, double inclinat return QgsPointV2( pType, mX + dx, mY + dy, mZ + dz, mM ); } + +QgsPointV2 QgsPointV2::midpoint (const QgsPointV2& other) const +{ + QgsWkbTypes::Type pType( QgsWkbTypes::Point ); + + + double x = ( mX + other.x() ) / 2.0; + double y = ( mY + other.y() ) / 2.0; + double z = 0.0; + double m = 0.0; + + if ( is3D() || other.is3D() ) + { + pType = QgsWkbTypes::addZ( pType ); + z = ( mZ + other.z()) / 2.0; + } + + if ( isMeasure() || other.isMeasure() ) + { + pType = QgsWkbTypes::addM( pType ); + m = ( mM + other.m()) / 2.0; + } + + return QgsPointV2( pType, x, y, z, m ); +} diff --git a/src/core/geometry/qgspointv2.h b/src/core/geometry/qgspointv2.h index 6f42cd74e3a..683be1048e1 100644 --- a/src/core/geometry/qgspointv2.h +++ b/src/core/geometry/qgspointv2.h @@ -187,6 +187,41 @@ class CORE_EXPORT QgsPointV2: public QgsAbstractGeometry */ double distanceSquared( const QgsPointV2& other ) const; + /** + * Returns the 3D distance between this point and a specified x, y, z coordinate. In certain + * cases it may be more appropriate to call the faster distanceSquared() method, e.g., + * when comparing distances. + * @note added in QGIS 3.0 + * @see distanceSquared() + */ + double distance3D( double x, double y, double z ) const; + + /** + * Returns the 3D distance between this point and another point. In certain + * cases it may be more appropriate to call the faster distanceSquared() method, e.g., + * when comparing distances. + * @note added in QGIS 3.0 + */ + double distance3D( const QgsPointV2& other ) const; + + /** + * Returns the 3D squared distance between this point a specified x, y, z coordinate. Calling + * this is faster than calling distance(), and may be useful in use cases such as comparing + * distances where the extra expense of calling distance() is not required. + * @see distance() + * @note added in QGIS 3.0 + */ + double distanceSquared3D( double x, double y, double z ) const; + + /** + * Returns the 3D squared distance between this point another point. Calling + * this is faster than calling distance(), and may be useful in use cases such as comparing + * distances where the extra expense of calling distance() is not required. + * @see distance() + * @note added in QGIS 3.0 + */ + double distanceSquared3D( const QgsPointV2& other ) const; + /** * Calculates azimuth between this point and other one (clockwise in degree, starting from north) * @note added in QGIS 3.0 @@ -222,6 +257,27 @@ class CORE_EXPORT QgsPointV2: public QgsAbstractGeometry */ QgsPointV2 project( double distance, double azimuth, double inclination = 90.0 ) const; + /** Returns a middle point between this point and other one. + * Z value is computed if one of this point have Z. + * M value is computed if one of this point have M. + * @param other other point. + * @return New point at middle between this and other one. + * Example: + * \code{.py} + * p = QgsPointV2( 4, 6 ) # 2D point + * pr = p.midpoint ( QgsPointV2( 2, 2 ) ) + * # pr is a 2D point: 'Point (3 4)' + * pr = p.midpoint ( QgsPointV2( QgsWkbTypes.PointZ, 2, 2, 2 ) ) + * # pr is a 3D point: 'PointZ (3 4 1)' + * pr = p.midpoint ( QgsPointV2( QgsWkbTypes.PointM, 2, 2, 0, 2 ) ) + * # pr is a 3D point: 'PointM (3 4 1)' + * pr = p.midpoint ( QgsPointV2( QgsWkbTypes.PointZM, 2, 2, 2, 2 ) ) + * # pr is a 4D point: 'PointZM (3 4 1 1)' + * \endcode + * @note added in QGIS 3.0 + */ + QgsPointV2 midpoint (const QgsPointV2& other) const; + /** * Calculates the vector obtained by subtracting a point from this point. * @note added in QGIS 3.0 diff --git a/tests/src/core/testqgsgeometry.cpp b/tests/src/core/testqgsgeometry.cpp index 28932a2fd42..8dfc36a31a2 100644 --- a/tests/src/core/testqgsgeometry.cpp +++ b/tests/src/core/testqgsgeometry.cpp @@ -818,6 +818,26 @@ void TestQgsGeometry::point() QCOMPARE( QgsPointV2( 1, -2 ).distanceSquared( QgsPointV2( 1, -4 ) ), 4.0 ); QCOMPARE( QgsPointV2( 1, -2 ).distanceSquared( 1, -4 ), 4.0 ); + // distance 3D + QCOMPARE( QgsPointV2( 0, 0 ).distanceSquared3D( QgsPointV2( 1, 1 )), 2.0 ); + QCOMPARE( QgsPointV2( 0, 0 ).distanceSquared3D( 1, 1, 0 ), 2.0 ); + QCOMPARE( QgsPointV2( 0, 0 ).distanceSquared3D( QgsPointV2 ( QgsWkbTypes::PointZ, 2, 2, 2, 0 )), 12.0 ); + QCOMPARE( QgsPointV2( 0, 0 ).distanceSquared3D( 2, 2, 2 ), 12.0 ); + QCOMPARE( QgsPointV2( QgsWkbTypes::PointZ, 2, 2, 2, 0 ).distanceSquared3D( QgsPointV2( 1, 1 )), 6.0 ); + QCOMPARE( QgsPointV2( QgsWkbTypes::PointZ, 2, 2, 2, 0 ).distanceSquared3D( 1, 1, 0 ), 6.0 ); + QCOMPARE( QgsPointV2( QgsWkbTypes::PointZ, -2, -2, -2, 0 ).distanceSquared3D( QgsPointV2( 0, 0 )), 12.0 ); + QCOMPARE( QgsPointV2( QgsWkbTypes::PointZ, -2, -2, -2, 0 ).distanceSquared3D( 0, 0, 0 ), 12.0 ); + QCOMPARE( QgsPointV2( QgsWkbTypes::PointZ, -2, -2, -2, 0 ).distanceSquared3D( QgsPointV2( QgsWkbTypes::PointZ, 2, 2, 2, 0 )), 48.0 ); + QCOMPARE( QgsPointV2( QgsWkbTypes::PointZ, -2, -2, -2, 0 ).distanceSquared3D( 2, 2, 2 ), 48.0 ); + + + QCOMPARE( QgsPointV2( QgsWkbTypes::PointZ, 1, 1, 2, 0 ).distance3D( QgsPointV2( QgsWkbTypes::PointZ, 1, 3, 2, 0 )), 2.0 ); + QCOMPARE( QgsPointV2( QgsWkbTypes::PointZ, 1, 1, 2, 0 ).distance3D( 1, 3, 2 ), 2.0 ); + QCOMPARE( QgsPointV2( QgsWkbTypes::PointZ, 1, 1, 2, 0 ).distance3D( QgsPointV2( QgsWkbTypes::PointZ, 1, 1, 4, 0 )), 2.0 ); + QCOMPARE( QgsPointV2( QgsWkbTypes::PointZ, 1, 1, 2, 0 ).distance3D( 1, 1, 4 ), 2.0 ); + QCOMPARE( QgsPointV2( QgsWkbTypes::PointZ, 1, 1, -2, 0 ).distance3D( QgsPointV2( QgsWkbTypes::PointZ, 1, 1, -4, 0 )), 2.0 ); + QCOMPARE( QgsPointV2( QgsWkbTypes::PointZ, 1, 1, -2, 0 ).distance3D( 1, 1, -4 ), 2.0 ); + // azimuth QCOMPARE( QgsPointV2( 1, 2 ).azimuth( QgsPointV2( 1, 2 ) ), 0.0 ); QCOMPARE( QgsPointV2( 1, 2 ).azimuth( QgsPointV2( 1, 3 ) ), 0.0 ); @@ -890,6 +910,13 @@ void TestQgsGeometry::point() QCOMPARE( p34.project( 5, 450 ), QgsPointV2( QgsWkbTypes::PointZM, 6, 2, 2, 5 ) ); QCOMPARE( p34.project( 5, 450, 450 ), QgsPointV2( QgsWkbTypes::PointZM, 6, 2, 2, 5 ) ); + // midpoint + QgsPointV2 p35 = QgsPointV2( 4, 6 ); + QCOMPARE( p35.midpoint( QgsPointV2( 2, 2 ) ), QgsPointV2( 3, 4 ) ); + QCOMPARE( p35.midpoint( QgsPointV2( QgsWkbTypes::PointZ, 2, 2, 2 ) ), QgsPointV2( QgsWkbTypes::PointZ, 3, 4, 1 ) ); + QCOMPARE( p35.midpoint( QgsPointV2( QgsWkbTypes::PointM, 2, 2, 0, 2 ) ), QgsPointV2( QgsWkbTypes::PointM, 3, 4, 0, 1 ) ); + QCOMPARE( p35.midpoint( QgsPointV2( QgsWkbTypes::PointZM, 2, 2, 2, 2 ) ), QgsPointV2( QgsWkbTypes::PointZM, 3, 4, 1, 1 ) ); + } void TestQgsGeometry::lineString()