Skip to content
Permalink
Browse files

Add geometry util to calculate a point along a segment offset in a pe…

…rpendicular direction by a set offset amount
  • Loading branch information
nyalldawson committed Mar 19, 2021
1 parent 8b94ec5 commit ba6d96725b4e60db6596322a71c5a3c6aa597b31
@@ -269,6 +269,37 @@ Returns a point a specified ``distance`` toward a second point.
%End


static void perpendicularOffsetPointAlongSegment( double x1, double y1, double x2, double y2, double proportion, double offset, double *x /Out/, double *y /Out/ );
%Docstring
Calculates a point a certain ``proportion`` of the way along the segment from (``x1``, ``y1``) to (``x2``, ``y2``),
offset from the segment by the specified ``offset`` amount.

:param x1: x-coordinate of start of segment
:param y1: y-coordinate of start of segment
:param x2: x-coordinate of end of segment
:param y2: y-coordinate of end of segment
:param proportion: proportion of the segment's length at which to place the point (between 0.0 and 1.0)
:param offset: perpendicular offset from segment to apply to point. A negative ``offset`` shifts the point to the left of the segment, while a positive ``offset`` will shift it to the right of the segment.

Example
-------

.. code-block:: python

# Offset point at center of segment by 2 units to the right
x, y = QgsGeometryUtils.perpendicularOffsetPointAlongSegment( 1, 5, 11, 5, 0.5, 2 )
# (6.0, 3.0)

# Offset point at center of segment by 2 units to the left
x, y = QgsGeometryUtils.perpendicularOffsetPointAlongSegment( 1, 5, 11, 5, 0.5, -2 )
# (6.0, 7.0)

:return: - x: calculated point x-coordinate
- y: calculated point y-coordinate

.. versionadded:: 3.20
%End

static QgsPoint interpolatePointOnArc( const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double distance ) /HoldGIL/;
%Docstring
Interpolates a point on an arc defined by three points, ``pt1``, ``pt2`` and ``pt3``. The arc will be
@@ -631,6 +631,23 @@ void QgsGeometryUtils::pointOnLineWithDistance( double x1, double y1, double x2,
}
}

void QgsGeometryUtils::perpendicularOffsetPointAlongSegment( double x1, double y1, double x2, double y2, double proportion, double offset, double *x, double *y )
{
// calculate point along segment
const double mX = x1 + ( x2 - x1 ) * proportion;
const double mY = y1 + ( y2 - y1 ) * proportion;
const double pX = x1 - x2;
const double pY = y1 - y2;
double normalX = -pY;
double normalY = pX;
const double normalLength = sqrt( ( normalX * normalX ) + ( normalY * normalY ) );
normalX /= normalLength;
normalY /= normalLength;

*x = mX + offset * normalX;
*y = mY + offset * normalY;
}

QgsPoint QgsGeometryUtils::interpolatePointOnArc( const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double distance )
{
double centerX, centerY, radius;
@@ -301,6 +301,35 @@ class CORE_EXPORT QgsGeometryUtils
double *z1 = nullptr, double *z2 = nullptr, double *z = nullptr,
double *m1 = nullptr, double *m2 = nullptr, double *m = nullptr ) SIP_SKIP;

/**
* Calculates a point a certain \a proportion of the way along the segment from (\a x1, \a y1) to (\a x2, \a y2),
* offset from the segment by the specified \a offset amount.
*
* \param x1 x-coordinate of start of segment
* \param y1 y-coordinate of start of segment
* \param x2 x-coordinate of end of segment
* \param y2 y-coordinate of end of segment
* \param proportion proportion of the segment's length at which to place the point (between 0.0 and 1.0)
* \param offset perpendicular offset from segment to apply to point. A negative \a offset shifts the point to the left of the segment, while a positive \a offset will shift it to the right of the segment.
* \param x calculated point x-coordinate
* \param y calculated point y-coordinate
*
* ### Example
*
* \code{.py}
* # Offset point at center of segment by 2 units to the right
* x, y = QgsGeometryUtils.perpendicularOffsetPointAlongSegment( 1, 5, 11, 5, 0.5, 2 )
* # (6.0, 3.0)
*
* # Offset point at center of segment by 2 units to the left
* x, y = QgsGeometryUtils.perpendicularOffsetPointAlongSegment( 1, 5, 11, 5, 0.5, -2 )
* # (6.0, 7.0)
* \endcode
*
* \since QGIS 3.20
*/
static void perpendicularOffsetPointAlongSegment( double x1, double y1, double x2, double y2, double proportion, double offset, double *x SIP_OUT, double *y SIP_OUT );

/**
* Interpolates a point on an arc defined by three points, \a pt1, \a pt2 and \a pt3. The arc will be
* interpolated by the specified \a distance from \a pt1.
@@ -83,6 +83,7 @@ class TestQgsGeometryUtils: public QObject
void testPointContinuesArc();
void testBisector();
void testAngleBisector();
void testPerpendicularOffsetPoint();
};


@@ -1537,5 +1538,34 @@ void TestQgsGeometryUtils::testAngleBisector()
QVERIFY( !QgsGeometryUtils::angleBisector( 0, 0, 5, 0, 6, 0, 10, 0, x, y, angle ) );
}

void TestQgsGeometryUtils::testPerpendicularOffsetPoint()
{
double x, y;
QgsGeometryUtils::perpendicularOffsetPointAlongSegment( 1, 5, 11, 5, 0.5, 2, &x, &y );
QGSCOMPARENEAR( x, 6.0, 10e-3 );
QGSCOMPARENEAR( y, 3.0, 10e-3 );
QgsGeometryUtils::perpendicularOffsetPointAlongSegment( 1, 5, 11, 5, 0.5, -2, &x, &y );
QGSCOMPARENEAR( x, 6.0, 10e-3 );
QGSCOMPARENEAR( y, 7.0, 10e-3 );
QgsGeometryUtils::perpendicularOffsetPointAlongSegment( 1, 5, 11, 5, 0.1, 2, &x, &y );
QGSCOMPARENEAR( x, 2.0, 10e-3 );
QGSCOMPARENEAR( y, 3.0, 10e-3 );
QgsGeometryUtils::perpendicularOffsetPointAlongSegment( 1, 5, 11, 5, 0.9, 2, &x, &y );
QGSCOMPARENEAR( x, 10.0, 10e-3 );
QGSCOMPARENEAR( y, 3.0, 10e-3 );
QgsGeometryUtils::perpendicularOffsetPointAlongSegment( 1, 5, 11, 5, 0.0, 2, &x, &y );
QGSCOMPARENEAR( x, 1.0, 10e-3 );
QGSCOMPARENEAR( y, 3.0, 10e-3 );
QgsGeometryUtils::perpendicularOffsetPointAlongSegment( 1, 5, 11, 5, 1.0, 2, &x, &y );
QGSCOMPARENEAR( x, 11.0, 10e-3 );
QGSCOMPARENEAR( y, 3.0, 10e-3 );
QgsGeometryUtils::perpendicularOffsetPointAlongSegment( 5, 1, 5, 11, 0.5, 2, &x, &y );
QGSCOMPARENEAR( x, 7.0, 10e-3 );
QGSCOMPARENEAR( y, 6.0, 10e-3 );
QgsGeometryUtils::perpendicularOffsetPointAlongSegment( 5, 1, 5, 11, 0.5, -2, &x, &y );
QGSCOMPARENEAR( x, 3.0, 10e-3 );
QGSCOMPARENEAR( y, 6.0, 10e-3 );
}

QGSTEST_MAIN( TestQgsGeometryUtils )
#include "testqgsgeometryutils.moc"

0 comments on commit ba6d967

Please sign in to comment.