Skip to content

Commit

Permalink
Add some utils functions for QgsPointV2 (distance3D, midpoint)
Browse files Browse the repository at this point in the history
  • Loading branch information
lbartoletti authored and nyalldawson committed Feb 14, 2017
1 parent eaa97f3 commit e851b68
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 3 deletions.
56 changes: 56 additions & 0 deletions python/core/geometry/qgspointv2.sip
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
51 changes: 48 additions & 3 deletions src/core/geometry/qgspointv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -438,24 +438,44 @@ 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
{
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;
Expand Down Expand Up @@ -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 );
}
56 changes: 56 additions & 0 deletions src/core/geometry/qgspointv2.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
27 changes: 27 additions & 0 deletions tests/src/core/testqgsgeometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 );

This comment has been minimized.

Copy link
@m-kuhn

m-kuhn Jun 10, 2017

Member

Is this a safe thing to test?
I.e. is the assumption that the altitude is 0 for a 2D coordinate safe?

What do you think about changing this to

QCOMPARE( true, qIsNaN( QgsPointV2( 0, 0 ).distanceSquared3D(  1, 1, 0 ) ) );

see #4677 : https://travis-ci.org/qgis/QGIS/jobs/241494759#L949

CC @wonder-sk @nyalldawson @haubourg

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 );
Expand Down Expand Up @@ -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()
Expand Down

0 comments on commit e851b68

Please sign in to comment.