Skip to content

Commit

Permalink
Allow using the longer arc with two point and center methods
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Apr 23, 2018
1 parent 732d6bb commit 9a6d966
Show file tree
Hide file tree
Showing 8 changed files with 41 additions and 9 deletions.
7 changes: 6 additions & 1 deletion python/core/geometry/qgscircularstring.sip.in
Expand Up @@ -41,11 +41,16 @@ arc passing through ``p1``, ``p2`` and ``p3``.

static QgsCircularString fromTwoPointsAndCenter( const QgsPoint &p1,
const QgsPoint &p2,
const QgsPoint &center );
const QgsPoint &center,
bool useShortestArc = true );
%Docstring
Creates a circular string with a single arc representing
the curve from ``p1`` to ``p2`` with the specified ``center``.

If ``useShortestArc`` is true, then the arc returned will be that corresponding
to the shorter arc from ``p1`` to ``p2``. If it is false, the longer arc from ``p1``
to ``p2`` will be used (i.e. winding the other way around the circle).

.. versionadded:: 3.2
%End

Expand Down
6 changes: 5 additions & 1 deletion python/core/geometry/qgsgeometryutils.sip.in
Expand Up @@ -277,11 +277,15 @@ first 3D point amongst ``p1`` and ``p2``.
.. seealso:: :py:func:`segmentMidPointFromCenter`
%End

static QgsPoint segmentMidPointFromCenter( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &center );
static QgsPoint segmentMidPointFromCenter( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &center, bool useShortestArc = true );
%Docstring
Calculates the midpoint on the circle passing through ``p1`` and ``p2``,
with the specified ``center`` coordinate.

If ``useShortestArc`` is true, then the midpoint returned will be that corresponding
to the shorter arc from ``p1`` to ``p2``. If it is false, the longer arc from ``p1``
to ``p2`` will be used (i.e. winding the other way around the circle).

.. versionadded:: 3.2

.. seealso:: :py:func:`segmentMidPoint`
Expand Down
4 changes: 2 additions & 2 deletions src/core/geometry/qgscircularstring.cpp
Expand Up @@ -66,9 +66,9 @@ QgsCircularString::QgsCircularString( const QgsPoint &p1, const QgsPoint &p2, co
}
}

QgsCircularString QgsCircularString::fromTwoPointsAndCenter( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &center )
QgsCircularString QgsCircularString::fromTwoPointsAndCenter( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &center, const bool useShortestArc )
{
const QgsPoint midPoint = QgsGeometryUtils::segmentMidPointFromCenter( p1, p2, center );
const QgsPoint midPoint = QgsGeometryUtils::segmentMidPointFromCenter( p1, p2, center, useShortestArc );
return QgsCircularString( p1, midPoint, p2 );
}

Expand Down
7 changes: 6 additions & 1 deletion src/core/geometry/qgscircularstring.h
Expand Up @@ -54,11 +54,16 @@ class CORE_EXPORT QgsCircularString: public QgsCurve
* Creates a circular string with a single arc representing
* the curve from \a p1 to \a p2 with the specified \a center.
*
* If \a useShortestArc is true, then the arc returned will be that corresponding
* to the shorter arc from \a p1 to \a p2. If it is false, the longer arc from \a p1
* to \a p2 will be used (i.e. winding the other way around the circle).
*
* \since QGIS 3.2
*/
static QgsCircularString fromTwoPointsAndCenter( const QgsPoint &p1,
const QgsPoint &p2,
const QgsPoint &center );
const QgsPoint &center,
bool useShortestArc = true );

bool equals( const QgsCurve &other ) const override;

Expand Down
8 changes: 5 additions & 3 deletions src/core/geometry/qgsgeometryutils.cpp
Expand Up @@ -740,10 +740,12 @@ bool QgsGeometryUtils::segmentMidPoint( const QgsPoint &p1, const QgsPoint &p2,
return true;
}

QgsPoint QgsGeometryUtils::segmentMidPointFromCenter( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &center )
QgsPoint QgsGeometryUtils::segmentMidPointFromCenter( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &center, const bool useShortestArc )
{
const double midPointAngle = averageAngle( lineAngle( center.x(), center.y(), p1.x(), p1.y() ),
lineAngle( center.x(), center.y(), p2.x(), p2.y() ) );
double midPointAngle = averageAngle( lineAngle( center.x(), center.y(), p1.x(), p1.y() ),
lineAngle( center.x(), center.y(), p2.x(), p2.y() ) );
if ( !useShortestArc )
midPointAngle += M_PI;
return center.project( center.distance( p1 ), midPointAngle * 180 / M_PI );
}

Expand Down
6 changes: 5 additions & 1 deletion src/core/geometry/qgsgeometryutils.h
Expand Up @@ -288,10 +288,14 @@ class CORE_EXPORT QgsGeometryUtils
* Calculates the midpoint on the circle passing through \a p1 and \a p2,
* with the specified \a center coordinate.
*
* If \a useShortestArc is true, then the midpoint returned will be that corresponding
* to the shorter arc from \a p1 to \a p2. If it is false, the longer arc from \a p1
* to \a p2 will be used (i.e. winding the other way around the circle).
*
* \since QGIS 3.2
* \see segmentMidPoint()
*/
static QgsPoint segmentMidPointFromCenter( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &center );
static QgsPoint segmentMidPointFromCenter( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &center, bool useShortestArc = true );

//! Calculates the direction angle of a circle tangent (clockwise from north in radians)
static double circleTangentDirection( const QgsPoint &tangentPoint, const QgsPoint &cp1, const QgsPoint &cp2, const QgsPoint &cp3 );
Expand Down
9 changes: 9 additions & 0 deletions tests/src/core/testqgsgeometry.cpp
Expand Up @@ -1221,6 +1221,15 @@ void TestQgsGeometry::circularString()
QCOMPARE( from3Pts.yAt( 1 ), 22.0 );
QCOMPARE( from3Pts.xAt( 2 ), 31.0 );
QCOMPARE( from3Pts.yAt( 2 ), 2.0 );
from3Pts = QgsCircularString::fromTwoPointsAndCenter( QgsPoint( 1, 2 ), QgsPoint( 31, 2 ), QgsPoint( 21, 2 ), false );
QCOMPARE( from3Pts.wkbType(), QgsWkbTypes::CircularString );
QCOMPARE( from3Pts.numPoints(), 3 );
QCOMPARE( from3Pts.xAt( 0 ), 1.0 );
QCOMPARE( from3Pts.yAt( 0 ), 2.0 );
QCOMPARE( from3Pts.xAt( 1 ), 21.0 );
QCOMPARE( from3Pts.yAt( 1 ), -18.0 );
QCOMPARE( from3Pts.xAt( 2 ), 31.0 );
QCOMPARE( from3Pts.yAt( 2 ), 2.0 );
from3Pts = QgsCircularString::fromTwoPointsAndCenter( QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ), QgsPoint( QgsWkbTypes::PointZ, 32, 2, 33 ),
QgsPoint( QgsWkbTypes::PointZ, 21, 2, 23 ) );
QCOMPARE( from3Pts.wkbType(), QgsWkbTypes::CircularStringZ );
Expand Down
3 changes: 3 additions & 0 deletions tests/src/core/testqgsgeometryutils.cpp
Expand Up @@ -220,6 +220,9 @@ void TestQgsGeometryUtils::testSegmentMidPointCenter()
QgsPoint mid = QgsGeometryUtils::segmentMidPointFromCenter( QgsPoint( 10, 21 ), QgsPoint( 11, 20 ), QgsPoint( 10, 20 ) );
QGSCOMPARENEAR( mid.x(), 10.7071, 0.0001 );
QGSCOMPARENEAR( mid.y(), 20.7071, 0.0001 );
QgsGeometryUtils::segmentMidPointFromCenter( QgsPoint( 10, 21 ), QgsPoint( 11, 20 ), QgsPoint( 10, 20 ), false );
QGSCOMPARENEAR( mid.x(), 10.7071, 0.0001 );
QGSCOMPARENEAR( mid.y(), 20.7071, 0.0001 );
mid = QgsGeometryUtils::segmentMidPointFromCenter( QgsPoint( 10, 21 ), QgsPoint( 9, 20 ), QgsPoint( 10, 20 ) );
QGSCOMPARENEAR( mid.x(), 9.292893, 0.0001 );
QGSCOMPARENEAR( mid.y(), 20.7071, 0.0001 );
Expand Down

0 comments on commit 9a6d966

Please sign in to comment.