Skip to content

Commit

Permalink
Adapt function to comply with default behavior at segmentLength value…
Browse files Browse the repository at this point in the history
… 0, adapt and improve test cases, include .sip.in files, corrected segmentLength calculation
  • Loading branch information
tschmetzer authored and nyalldawson committed Jan 6, 2022
1 parent 7cdde55 commit 7640026
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 103 deletions.
25 changes: 11 additions & 14 deletions python/core/auto_generated/geometry/qgsgeometryutils.sip.in
Expand Up @@ -644,34 +644,31 @@ Create a perpendicular line segment from p to segment [s1, s2]
%End


static void perpendicularCenterSegment( double centerPointx, double centerPointy,
double segmentPoint1x, double segmentPoint1y,
double segmentPoint2x, double segmentPoint2y,
double &perpendicularSegmentPoint1x /Out/, double &perpendicularSegmentPoint1y /Out/,
double &perpendicularSegmentPoint2x /Out/, double &perpendicularSegmentPoint2y /Out/,
double *segmentLength=0
) /HoldGIL/;
static void perpendicularCenterSegment( double centerPointx, double centerPointy,
double segmentPoint1x, double segmentPoint1y,
double segmentPoint2x, double segmentPoint2y,
double &perpendicularSegmentPoint1x /Out/, double &perpendicularSegmentPoint1y /Out/,
double &perpendicularSegmentPoint2x /Out/, double &perpendicularSegmentPoint2y /Out/,
double *segmentLength = 0
) /HoldGIL/;
%Docstring
Create a perpendicular line segment to a given segment [``segmentPoint1``,``segmentPoint2``] with its center at ``centerPoint``.

May be used to split geometries. The new centered perpendicular line segment will have double the length of the input segment
May be used to split geometries. Unless ``segmentLength`` is specified the new centered perpendicular line segment will have double the length of the input segment.

The result is a line (segment) centered in point p and perpendicular to segment [segmentPoint1, segmentPoint2].

:param centerPointx: x-coordinate of the point where the center of the perpendicular should be located
:param centerPointy: y-coordinate of the point where the center of the perpendicular should be located

:param segmentPoint1x: : x-coordinate of segmentPoint1, the segment's start point
:param segmentPoint1y: : y-coordinate of segmentPoint1, the segment's start point
:param segmentPoint2x: : x-coordinate of segmentPoint2, the segment's end point
:param y2: : y-coordinate of segmentPoint2, the segment's end point

Result is a line (segment) centered in point p and perpendicular to segment [segmentPoint1, segmentPoint2]

:param perpendicularSegmentPoint1x: : x-coordinate of the perpendicularCenterSegment's start point
:param perpendicularSegmentPoint1y: : y-coordinate of the perpendicularCenterSegment's start point
:param perpendicularSegmentPoint2x: : x-coordinate of the perpendicularCenterSegment's end point
:param perpendicularSegmentPoint2y: : y-coordinate of the perpendicularCenterSegment's end point

\param (optional parameter) segmentLength trims to given length. Default length is double the length of the input segment. Set to 0 for normalized length which is equal to 1.
:param segmentLength: (optional) Trims to given length. A segmentLength value of 0 refers to the default length which is double the length of the input segment. Set to 1 for a normalized length.

.. versionadded:: 3.17
%End
Expand Down
32 changes: 16 additions & 16 deletions src/core/geometry/qgsgeometryutils.cpp
Expand Up @@ -1605,25 +1605,25 @@ QgsLineString QgsGeometryUtils::perpendicularSegment( const QgsPoint &p, const Q
return line;
}

void QgsGeometryUtils::perpendicularCenterSegment( double pointx, double pointy, double segmentPoint1x, double segmentPoint1y, double segmentPoint2x, double segmentPoint2y, double &perpendicularSegmentPoint1x, double &perpendicularSegmentPoint1y, double &perpendicularSegmentPoint2x, double &perpendicularSegmentPoint2y, double *desiredSegmentLength)
void QgsGeometryUtils::perpendicularCenterSegment( double pointx, double pointy, double segmentPoint1x, double segmentPoint1y, double segmentPoint2x, double segmentPoint2y, double &perpendicularSegmentPoint1x, double &perpendicularSegmentPoint1y, double &perpendicularSegmentPoint2x, double &perpendicularSegmentPoint2y, double *desiredSegmentLength )
{
QgsVector segmentVector = QgsVector(segmentPoint2x-segmentPoint1x,segmentPoint2y-segmentPoint1y);
QgsVector perpendicularVector=segmentVector.perpVector();
if (desiredSegmentLength)
QgsVector segmentVector = QgsVector( segmentPoint2x - segmentPoint1x, segmentPoint2y - segmentPoint1y );
QgsVector perpendicularVector = segmentVector.perpVector();
if ( desiredSegmentLength )
{
if (*desiredSegmentLength==0)
{
perpendicularVector=perpendicularVector.normalized()/2;
}
else
{
perpendicularVector=perpendicularVector*(*desiredSegmentLength)/2;
}
if ( *desiredSegmentLength == 0 )
{
perpendicularVector = perpendicularVector * 1;
}
else
{
perpendicularVector = perpendicularVector.normalized() * ( *desiredSegmentLength ) / 2;
}
}
perpendicularSegmentPoint1x=pointx-perpendicularVector.x();
perpendicularSegmentPoint1y=pointy-perpendicularVector.y();
perpendicularSegmentPoint2x=pointx+perpendicularVector.x();
perpendicularSegmentPoint2y=pointy+perpendicularVector.y();
perpendicularSegmentPoint1x = pointx - perpendicularVector.x();
perpendicularSegmentPoint1y = pointy - perpendicularVector.y();
perpendicularSegmentPoint2x = pointx + perpendicularVector.x();
perpendicularSegmentPoint2y = pointy + perpendicularVector.y();
}

double QgsGeometryUtils::lineAngle( double x1, double y1, double x2, double y2 )
Expand Down
16 changes: 8 additions & 8 deletions src/core/geometry/qgsgeometryutils.h
Expand Up @@ -691,20 +691,20 @@ class CORE_EXPORT QgsGeometryUtils
* \param perpendicularSegmentPoint1y: y-coordinate of the perpendicularCenterSegment's start point
* \param perpendicularSegmentPoint2x: x-coordinate of the perpendicularCenterSegment's end point
* \param perpendicularSegmentPoint2y: y-coordinate of the perpendicularCenterSegment's end point
* \param segmentLength trims to given length. Default length is double the length of the input segment. Set to 0 for normalized length which is equal to 1.
* \param segmentLength (optional) Trims to given length. A segmentLength value of 0 refers to the default length which is double the length of the input segment. Set to 1 for a normalized length.
*
*
* \since QGIS 3.17?
*
*/

static void perpendicularCenterSegment( double centerPointx, double centerPointy,
double segmentPoint1x, double segmentPoint1y,
double segmentPoint2x, double segmentPoint2y,
double &perpendicularSegmentPoint1x SIP_OUT, double &perpendicularSegmentPoint1y SIP_OUT,
double &perpendicularSegmentPoint2x SIP_OUT, double &perpendicularSegmentPoint2y SIP_OUT,
double *segmentLength=nullptr
) SIP_HOLDGIL;
static void perpendicularCenterSegment( double centerPointx, double centerPointy,
double segmentPoint1x, double segmentPoint1y,
double segmentPoint2x, double segmentPoint2y,
double &perpendicularSegmentPoint1x SIP_OUT, double &perpendicularSegmentPoint1y SIP_OUT,
double &perpendicularSegmentPoint2x SIP_OUT, double &perpendicularSegmentPoint2y SIP_OUT,
double *segmentLength = nullptr
) SIP_HOLDGIL;

/**
* An algorithm to calculate the shortest distance between two skew lines.
Expand Down
153 changes: 88 additions & 65 deletions tests/src/core/geometry/testqgsgeometryutils.cpp
Expand Up @@ -733,71 +733,94 @@ void TestQgsGeometryUtils::testPerpendicularSegment()

void TestQgsGeometryUtils::testPerpendicularCenterSegment()
{
double perpendicularSegmentPoint1x=0, perpendicularSegmentPoint1y=0, perpendicularSegmentPoint2x=0, perpendicularSegmentPoint2y=0, segmentLength=0;

// default case 1: centerPoint and perpendicular line on given segment without segmentLength
QgsPoint centerPoint(2,1.5);
QgsPoint segmentPoint1(2,1);
QgsPoint segmentPoint2(2,2);

QgsGeometryUtils::perpendicularCenterSegment( centerPoint.x(),centerPoint.y(), segmentPoint1.x(), segmentPoint1.y(), segmentPoint2.x(), segmentPoint2.y(),
perpendicularSegmentPoint1x, perpendicularSegmentPoint1y, perpendicularSegmentPoint2x, perpendicularSegmentPoint2y);
QCOMPARE( perpendicularSegmentPoint1x, 3.0 );
QCOMPARE( perpendicularSegmentPoint1y, (1.5) );
QCOMPARE( perpendicularSegmentPoint2x, (1) );
QCOMPARE( perpendicularSegmentPoint2y, (1.5) );

// default case 1 with segmentLength
segmentLength=3;
QgsGeometryUtils::perpendicularCenterSegment( centerPoint.x(),centerPoint.y(), segmentPoint1.x(), segmentPoint1.y(), segmentPoint2.x(), segmentPoint2.y(),
perpendicularSegmentPoint1x, perpendicularSegmentPoint1y, perpendicularSegmentPoint2x, perpendicularSegmentPoint2y,&segmentLength);
QCOMPARE( perpendicularSegmentPoint1x, (3.5) );
QCOMPARE( perpendicularSegmentPoint1y, (1.5) );
QCOMPARE( perpendicularSegmentPoint2x, (.5) );
QCOMPARE( perpendicularSegmentPoint2y, (1.5) );


// default case 2: centerPoint not on given segment without segmentLength
centerPoint=QgsPoint( 3, 13 );
segmentPoint1=QgsPoint( 2, 3 );
segmentPoint2=QgsPoint( 7, 11 );
QgsGeometryUtils::perpendicularCenterSegment( centerPoint.x(),centerPoint.y(), segmentPoint1.x(), segmentPoint1.y(), segmentPoint2.x(), segmentPoint2.y(),
perpendicularSegmentPoint1x, perpendicularSegmentPoint1y, perpendicularSegmentPoint2x, perpendicularSegmentPoint2y );
QCOMPARE( perpendicularSegmentPoint1x, (11) );
QCOMPARE( perpendicularSegmentPoint1y, (8) );
QCOMPARE( perpendicularSegmentPoint2x, (-5) );
QCOMPARE( perpendicularSegmentPoint2y, (18) );

// horizontal without segmentLength
segmentPoint1 = QgsPoint( -3, 3 );
segmentPoint2 = QgsPoint( 2, 3 );
centerPoint = QgsPoint( 3, 13 );
QgsGeometryUtils::perpendicularCenterSegment( centerPoint.x(),centerPoint.y(), segmentPoint1.x(), segmentPoint1.y(), segmentPoint2.x(), segmentPoint2.y(),
perpendicularSegmentPoint1x, perpendicularSegmentPoint1y, perpendicularSegmentPoint2x, perpendicularSegmentPoint2y );
QCOMPARE( perpendicularSegmentPoint1x, (3) );
QCOMPARE( perpendicularSegmentPoint1y, (8) );
QCOMPARE( perpendicularSegmentPoint2x, (3) );
QCOMPARE( perpendicularSegmentPoint2y, (18) );

// vertical without segmentLength
segmentPoint1 = QgsPoint( 3, 13 );
segmentPoint2 = QgsPoint( 3, 3 );
centerPoint = QgsPoint( -7, 8 );
QgsGeometryUtils::perpendicularCenterSegment( centerPoint.x(),centerPoint.y(), segmentPoint1.x(), segmentPoint1.y(), segmentPoint2.x(), segmentPoint2.y(),
perpendicularSegmentPoint1x, perpendicularSegmentPoint1y, perpendicularSegmentPoint2x, perpendicularSegmentPoint2y );
QCOMPARE( perpendicularSegmentPoint1x, (-17) );
QCOMPARE( perpendicularSegmentPoint1y, (8) );
QCOMPARE( perpendicularSegmentPoint2x, (3) );
QCOMPARE( perpendicularSegmentPoint2y, (8) );

// vertical with normalization of segmentLength
segmentLength=0;
QgsGeometryUtils::perpendicularCenterSegment( centerPoint.x(),centerPoint.y(), segmentPoint1.x(), segmentPoint1.y(), segmentPoint2.x(), segmentPoint2.y(),
perpendicularSegmentPoint1x, perpendicularSegmentPoint1y, perpendicularSegmentPoint2x, perpendicularSegmentPoint2y,&segmentLength);
QCOMPARE( perpendicularSegmentPoint1x, (-7.5) );
QCOMPARE( perpendicularSegmentPoint1y, (8) );
QCOMPARE( perpendicularSegmentPoint2x, (-6.5) );
QCOMPARE( perpendicularSegmentPoint2y, (8) );
double perpendicularSegmentPoint1x = 0, perpendicularSegmentPoint1y = 0, perpendicularSegmentPoint2x = 0, perpendicularSegmentPoint2y = 0, segmentLength = 0;

// default case 1: centerPoint and perpendicular line on given segment without segmentLength
QgsPoint centerPoint( 2, 1.5 );
QgsPoint segmentPoint1( 2, 1 );
QgsPoint segmentPoint2( 2, 2 );

QgsGeometryUtils::perpendicularCenterSegment( centerPoint.x(), centerPoint.y(), segmentPoint1.x(), segmentPoint1.y(), segmentPoint2.x(), segmentPoint2.y(),
perpendicularSegmentPoint1x, perpendicularSegmentPoint1y, perpendicularSegmentPoint2x, perpendicularSegmentPoint2y );
QCOMPARE( perpendicularSegmentPoint1x, 3.0 );
QCOMPARE( perpendicularSegmentPoint1y, ( 1.5 ) );
QCOMPARE( perpendicularSegmentPoint2x, ( 1.0 ) );
QCOMPARE( perpendicularSegmentPoint2y, ( 1.5 ) );

// case 1 with segmentLength
segmentLength = 3;
QgsGeometryUtils::perpendicularCenterSegment( centerPoint.x(), centerPoint.y(), segmentPoint1.x(), segmentPoint1.y(), segmentPoint2.x(), segmentPoint2.y(),
perpendicularSegmentPoint1x, perpendicularSegmentPoint1y, perpendicularSegmentPoint2x, perpendicularSegmentPoint2y, &segmentLength );
QCOMPARE( perpendicularSegmentPoint1x, ( 3.5 ) );
QCOMPARE( perpendicularSegmentPoint1y, ( 1.5 ) );
QCOMPARE( perpendicularSegmentPoint2x, ( 0.5 ) );
QCOMPARE( perpendicularSegmentPoint2y, ( 1.5 ) );

// default case 1 with default segmentLength=0 (meaning no effect)
segmentLength = 0;
QgsGeometryUtils::perpendicularCenterSegment( centerPoint.x(), centerPoint.y(), segmentPoint1.x(), segmentPoint1.y(), segmentPoint2.x(), segmentPoint2.y(),
perpendicularSegmentPoint1x, perpendicularSegmentPoint1y, perpendicularSegmentPoint2x, perpendicularSegmentPoint2y, &segmentLength );
QCOMPARE( perpendicularSegmentPoint1x, 3.0 );
QCOMPARE( perpendicularSegmentPoint1y, ( 1.5 ) );
QCOMPARE( perpendicularSegmentPoint2x, ( 1.0 ) );
QCOMPARE( perpendicularSegmentPoint2y, ( 1.5 ) );


// default case 2: centerPoint not on given segment without segmentLength
centerPoint = QgsPoint( 3, 13 );
segmentPoint1 = QgsPoint( 2, 3 );
segmentPoint2 = QgsPoint( 7, 11 );
QgsGeometryUtils::perpendicularCenterSegment( centerPoint.x(), centerPoint.y(), segmentPoint1.x(), segmentPoint1.y(), segmentPoint2.x(), segmentPoint2.y(),
perpendicularSegmentPoint1x, perpendicularSegmentPoint1y, perpendicularSegmentPoint2x, perpendicularSegmentPoint2y );
QCOMPARE( perpendicularSegmentPoint1x, ( 11.0 ) );
QCOMPARE( perpendicularSegmentPoint1y, ( 8.0 ) );
QCOMPARE( perpendicularSegmentPoint2x, ( -5.0 ) );
QCOMPARE( perpendicularSegmentPoint2y, ( 18.0 ) );

// case 3: centerPoint segment with segmentLength
centerPoint = QgsPoint( 1, 3 );
segmentPoint1 = QgsPoint( 4, 3 );
segmentPoint2 = QgsPoint( -5, -9 );

segmentLength = 5;
QgsGeometryUtils::perpendicularCenterSegment( centerPoint.x(), centerPoint.y(), segmentPoint1.x(), segmentPoint1.y(), segmentPoint2.x(), segmentPoint2.y(),
perpendicularSegmentPoint1x, perpendicularSegmentPoint1y, perpendicularSegmentPoint2x, perpendicularSegmentPoint2y, &segmentLength );

QCOMPARE( perpendicularSegmentPoint1x, ( -1.0 ) );
QCOMPARE( perpendicularSegmentPoint1y, ( 4.5 ) );
QCOMPARE( perpendicularSegmentPoint2x, ( 3.0 ) );
QCOMPARE( perpendicularSegmentPoint2y, ( 1.5 ) );

// horizontal without segmentLength
segmentPoint1 = QgsPoint( -3, 3 );
segmentPoint2 = QgsPoint( 2, 3 );
centerPoint = QgsPoint( 3, 13 );
QgsGeometryUtils::perpendicularCenterSegment( centerPoint.x(), centerPoint.y(), segmentPoint1.x(), segmentPoint1.y(), segmentPoint2.x(), segmentPoint2.y(),
perpendicularSegmentPoint1x, perpendicularSegmentPoint1y, perpendicularSegmentPoint2x, perpendicularSegmentPoint2y );
QCOMPARE( perpendicularSegmentPoint1x, ( 3.0 ) );
QCOMPARE( perpendicularSegmentPoint1y, ( 8.0 ) );
QCOMPARE( perpendicularSegmentPoint2x, ( 3.0 ) );
QCOMPARE( perpendicularSegmentPoint2y, ( 18.0 ) );

// vertical without segmentLength
segmentPoint1 = QgsPoint( 3, 13 );
segmentPoint2 = QgsPoint( 3, 3 );
centerPoint = QgsPoint( -7, 8 );
QgsGeometryUtils::perpendicularCenterSegment( centerPoint.x(), centerPoint.y(), segmentPoint1.x(), segmentPoint1.y(), segmentPoint2.x(), segmentPoint2.y(),
perpendicularSegmentPoint1x, perpendicularSegmentPoint1y, perpendicularSegmentPoint2x, perpendicularSegmentPoint2y );
QCOMPARE( perpendicularSegmentPoint1x, ( -17.0 ) );
QCOMPARE( perpendicularSegmentPoint1y, ( 8.0 ) );
QCOMPARE( perpendicularSegmentPoint2x, ( 3. ) );
QCOMPARE( perpendicularSegmentPoint2y, ( 8.0 ) );

// vertical with normalization of segmentLength
segmentLength = 1;
QgsGeometryUtils::perpendicularCenterSegment( centerPoint.x(), centerPoint.y(), segmentPoint1.x(), segmentPoint1.y(), segmentPoint2.x(), segmentPoint2.y(),
perpendicularSegmentPoint1x, perpendicularSegmentPoint1y, perpendicularSegmentPoint2x, perpendicularSegmentPoint2y, &segmentLength );
QCOMPARE( perpendicularSegmentPoint1x, ( -7.5 ) );
QCOMPARE( perpendicularSegmentPoint1y, ( 8.0 ) );
QCOMPARE( perpendicularSegmentPoint2x, ( -6.5 ) );
QCOMPARE( perpendicularSegmentPoint2y, ( 8.0 ) );
}

void TestQgsGeometryUtils::testClosestPoint()
Expand Down

0 comments on commit 7640026

Please sign in to comment.