Skip to content
Permalink
Browse files
File update to current file content
  • Loading branch information
tschmetzer authored and nyalldawson committed Jan 6, 2022
1 parent 9cbcae5 commit d94a996670cffd76f3b5364d123124144c893058
Showing with 117 additions and 79 deletions.
  1. +16 −37 src/core/geometry/qgsgeometryutils.cpp
  2. +33 −8 src/core/geometry/qgsgeometryutils.h
  3. +68 −34 tests/src/core/geometry/testqgsgeometryutils.cpp
@@ -1605,46 +1605,25 @@ QgsLineString QgsGeometryUtils::perpendicularSegment( const QgsPoint &p, const Q
return line;
}

QgsLineString QgsGeometryUtils::perpendicularCenterSegment( const QgsPoint &point, const QgsPoint &segmentPoint1, const QgsPoint &segmentPoint2 )
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)
{
QgsLineString segment;
QgsPoint p2;

/*
if ( ( p == s1 ) || ( p == s2 ) )
{
return line;
}
double a, b, c;
coefficients( s1, s2, a, b, c );
if ( qgsDoubleNear( a, 0 ) )
{
p2 = QgsPoint( p.x(), s1.y() );
}
else if ( qgsDoubleNear( b, 0 ) )
QgsVector segmentVector = QgsVector(segmentPoint2x-segmentPoint1x,segmentPoint2y-segmentPoint1y);
QgsVector perpendicularVector=segmentVector.perpVector();
if (desiredSegmentLength)
{
p2 = QgsPoint( s1.x(), p.y() );
if (*desiredSegmentLength==0)
{
perpendicularVector=perpendicularVector.normalized()/2;
}
else
{
perpendicularVector=perpendicularVector*(*desiredSegmentLength)/2;
}
}
else
{
double y = ( -c - a * p.x() ) / b;
double m = gradient( s1, s2 );
double d2 = 1 + m * m;
double H = p.y() - y;
double dx = m * H / d2;
double dy = m * dx;
p2 = QgsPoint( p.x() + dx, y + dy );
}*/


QgsVector segmentVector = QgsVector(segmentPoint2-segmentPoint1);
QgsVector perpendicularVector=segmentVector.perpVector();
segment.addVertex( point-perpendicularVector );
segment.addVertex( point+perpendicularVector );
return segment;

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 )
@@ -675,14 +675,39 @@ class CORE_EXPORT QgsGeometryUtils
static QgsLineString perpendicularSegment( const QgsPoint &p, const QgsPoint &s1, const QgsPoint &s2 ) SIP_HOLDGIL;

/**
* \brief Create a perpendicular line segment to a given segment [segmentPoint1, segmentPoint2] with its center at centerPoint
* May be used to split geometries
* \param centerPoint Point where the center of the perpendicular should be located
* \param segmentPoint1 The segment's start point
* \param segmentPoint2 The segment's end point
* \returns A line (segment) centered in point p and perpendicular to segment [segmentPoint1, segmentPoint2]
*/
static QgsLineString perpendicularCenterSegment( const QgsPoint &point, const QgsPoint &segmentPoint1, const QgsPoint &segmentPoint2 ) SIP_HOLDGIL;
* \brief Create a perpendicular line segment to a given segment [\a segmentPoint1,\a segmentPoint2] with its center at \a centerPoint.
*
* May be used to split geometries. The new centered perpendicular line segment will have double the length of the input segment
*
* \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.
*
*
* \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;

/**
* An algorithm to calculate the shortest distance between two skew lines.
@@ -22,6 +22,8 @@
#include "qgslinestring.h"
#include "qgspolygon.h"
#include "qgsmultipolygon.h"
#include <iostream>
using namespace std;

class TestQgsGeometryUtils: public QObject
{
@@ -730,42 +732,74 @@ void TestQgsGeometryUtils::testPerpendicularSegment()
QCOMPARE( line.pointN( 1 ), line_r.pointN( 1 ) );
}


void TestQgsGeometryUtils::testPerpendicularCenterSegment()
{
// default case 1: centerPoint and perpendicular line on given segment
QgsPoint centerPoint(2,1.5);
QgsPoint segmentPoint1(2,1);
QgsPoint segmentPoint2(2,2);
QgsLineString perpendicular_line = QgsGeometryUtils::perpendicularCenterSegment( centerPoint, segmentPoint1, segmentPoint2 );
QCOMPARE( perpendicular_line.pointN( 0 ),QgsPoint(1,1.5) );
QCOMPARE( perpendicular_line.pointN( 1 ),QgsPoint(3,1.5));

// default case 2: centerPoint not on given segment
perpendicular_line.clear();
centerPoint=QgsPoint( 3, 13 );
segmentPoint1=QgsPoint( 2, 3 );
segmentPoint2=QgsPoint( 7, 11 );
perpendicular_line = QgsGeometryUtils::perpendicularCenterSegment( centerPoint, segmentPoint1, segmentPoint2 );
QCOMPARE( perpendicular_line.pointN( 0 ),QgsPoint(-5,18) );
QCOMPARE( perpendicular_line.pointN( 1 ),QgsPoint(11,18) );

// horizontal
perpendicular_line.clear();
segmentPoint1 = QgsPoint( -3, 3 );
segmentPoint2 = QgsPoint( 2, 3 );
centerPoint = QgsPoint( 3, 13 );
perpendicular_line = QgsGeometryUtils::perpendicularCenterSegment( centerPoint, segmentPoint1, segmentPoint2 );
QCOMPARE( perpendicular_line.pointN( 0 ), QgsPoint(3,8) );
QCOMPARE( perpendicular_line.pointN( 1 ), QgsPoint(3,18) );

// vertical
perpendicular_line.clear();
segmentPoint1 = QgsPoint( 3, 13 );
segmentPoint2 = QgsPoint( 3, 3 );
centerPoint = QgsPoint( -7, 8 );
perpendicular_line = QgsGeometryUtils::perpendicularCenterSegment( centerPoint, segmentPoint1, segmentPoint2 );
QCOMPARE( perpendicular_line.pointN( 0 ), QgsPoint(3,8) );
QCOMPARE( perpendicular_line.pointN( 1 ), QgsPoint(-17,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) );
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) );
}

void TestQgsGeometryUtils::testClosestPoint()

0 comments on commit d94a996

Please sign in to comment.