Skip to content

Commit fa9f62f

Browse files
committed
Add class for comparing distance from two line segments to an origin
1 parent 6e6ddbb commit fa9f62f

File tree

3 files changed

+127
-0
lines changed

3 files changed

+127
-0
lines changed

src/core/geometry/qgsinternalgeometryengine.cpp

+58
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,64 @@ QgsGeometry QgsInternalGeometryEngine::densifyByDistance( double distance ) cons
711711
}
712712
}
713713

714+
//
715+
// QgsLineSegmentDistanceComparer
716+
//
717+
718+
// adapted for QGIS geometry classes from original work at https://github.com/trylock/visibility by trylock
719+
bool QgsLineSegmentDistanceComparer::operator()( QgsLineSegment2D ab, QgsLineSegment2D cd ) const
720+
{
721+
Q_ASSERT_X( ab.pointLeftOfLine( mOrigin ) != 0,
722+
"line_segment_dist_comparer",
723+
"AB must not be collinear with the origin." );
724+
Q_ASSERT_X( cd.pointLeftOfLine( mOrigin ) != 0,
725+
"line_segment_dist_comparer",
726+
"CD must not be collinear with the origin." );
727+
728+
// flip the segments so that if there are common endpoints,
729+
// they will be the segment's start points
730+
if ( ab.end() == cd.start() || ab.end() == cd.end() )
731+
ab.reverse();
732+
if ( ab.start() == cd.end() )
733+
cd.reverse();
734+
735+
// cases with common endpoints
736+
if ( ab.start() == cd.start() )
737+
{
738+
const int oad = QgsGeometryUtils::leftOfLine( cd.endX(), cd.endY(), mOrigin.x(), mOrigin.y(), ab.startX(), ab.startY() );
739+
const int oab = ab.pointLeftOfLine( mOrigin );
740+
if ( ab.end() == cd.end() || oad != oab )
741+
return false;
742+
else
743+
return ab.pointLeftOfLine( cd.end() ) != oab;
744+
}
745+
else
746+
{
747+
// cases without common endpoints
748+
const int cda = cd.pointLeftOfLine( ab.start() );
749+
const int cdb = cd.pointLeftOfLine( ab.end() );
750+
if ( cdb == 0 && cda == 0 )
751+
{
752+
return mOrigin.sqrDist( ab.start() ) < mOrigin.sqrDist( cd.start() );
753+
}
754+
else if ( cda == cdb || cda == 0 || cdb == 0 )
755+
{
756+
const int cdo = cd.pointLeftOfLine( mOrigin );
757+
return cdo == cda || cdo == cdb;
758+
}
759+
else
760+
{
761+
const int abo = ab.pointLeftOfLine( mOrigin );
762+
return abo != ab.pointLeftOfLine( cd.start() );
763+
}
764+
}
765+
}
766+
767+
768+
//
769+
// QgsRay2D
770+
//
771+
714772
bool QgsRay2D::intersects( const QgsLineSegment2D &segment, QgsPointXY &intersectPoint ) const
715773
{
716774
const QgsVector ao = origin - segment.start();

src/core/geometry/qgsinternalgeometryengine.h

+40
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ class QgsInternalGeometryEngine
110110
* A 2D ray which extends from an origin point to an infinite distance in a given direction.
111111
* \ingroup core
112112
* \since QGIS 3.2
113+
* \note not available in Python bindings
113114
*/
114115
class CORE_EXPORT QgsRay2D
115116
{
@@ -139,4 +140,43 @@ class CORE_EXPORT QgsRay2D
139140
QgsVector direction;
140141
};
141142

143+
///@cond PRIVATE
144+
145+
// adapted for QGIS geometry classes from original work at https://github.com/trylock/visibility by trylock
146+
147+
/**
148+
* Compares two line segments based on their distance from a given point
149+
* Assumes: (1) the line segments are intersected by some ray from the origin
150+
* (2) the line segments do not intersect except at their endpoints
151+
* (3) no line segment is collinear with the origin
152+
*/
153+
class CORE_EXPORT QgsLineSegmentDistanceComparer
154+
{
155+
public:
156+
157+
/**
158+
* Constructor for QgsLineSegmentDistanceComparer, comparing points
159+
* to the specified \a origin point.
160+
*/
161+
explicit QgsLineSegmentDistanceComparer( const QgsPointXY &origin )
162+
: mOrigin( origin )
163+
{}
164+
165+
/**
166+
* Checks whether the line segment \a ab is closer to the origin than the
167+
* line segment \a cd.
168+
* \param ab line segment: left hand side of the comparison operator
169+
* \param cd line segment: right hand side of the comparison operator
170+
* \returns true if ab < cd (ab is closer than cd) to origin
171+
*/
172+
bool operator()( QgsLineSegment2D ab, QgsLineSegment2D cd ) const;
173+
174+
private:
175+
176+
QgsPointXY mOrigin;
177+
178+
};
179+
180+
///@endcond PRIVATE
181+
142182
#endif // QGSINTERNALGEOMETRYENGINE_H

tests/src/core/testqgsinternalgeometryengine.cpp

+29
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class TestQgsInternalGeometryEngine : public QObject
3030
void init();// will be called before each testfunction is executed.
3131
void cleanup();// will be called after every testfunction.
3232
void ray();
33+
void lineSegmentDistanceComparer();
3334

3435
};
3536

@@ -95,5 +96,33 @@ void TestQgsInternalGeometryEngine::ray()
9596

9697
}
9798

99+
void TestQgsInternalGeometryEngine::lineSegmentDistanceComparer()
100+
{
101+
QgsLineSegmentDistanceComparer comp( QgsPointXY( 3, 5 ) );
102+
103+
QVERIFY( comp( QgsLineSegment2D( QgsPointXY( 1, 2 ), QgsPointXY( 3, 4 ) ),
104+
QgsLineSegment2D( QgsPointXY( 11, 2 ), QgsPointXY( 13, 4 ) ) ) );
105+
QVERIFY( comp( QgsLineSegment2D( QgsPointXY( 1, 2 ), QgsPointXY( 3, 4 ) ),
106+
QgsLineSegment2D( QgsPointXY( 13, 4 ), QgsPointXY( 11, 2 ) ) ) );
107+
QVERIFY( comp( QgsLineSegment2D( QgsPointXY( 1, 2 ), QgsPointXY( 3, 4 ) ),
108+
QgsLineSegment2D( QgsPointXY( -13, 4 ), QgsPointXY( -11, 2 ) ) ) );
109+
QVERIFY( comp( QgsLineSegment2D( QgsPointXY( 1, 2 ), QgsPointXY( 3, 4 ) ),
110+
QgsLineSegment2D( QgsPointXY( -13, -4 ), QgsPointXY( -11, 2 ) ) ) );
111+
QVERIFY( comp( QgsLineSegment2D( QgsPointXY( 1, 2 ), QgsPointXY( 3, 4 ) ),
112+
QgsLineSegment2D( QgsPointXY( 11, 2 ), QgsPointXY( 13, 4 ) ) ) );
113+
QVERIFY( !comp( QgsLineSegment2D( QgsPointXY( 11, 2 ), QgsPointXY( 13, 4 ) ),
114+
QgsLineSegment2D( QgsPointXY( 1, 2 ), QgsPointXY( 3, 4 ) ) ) );
115+
QVERIFY( !comp( QgsLineSegment2D( QgsPointXY( 1, 2 ), QgsPointXY( 3, 4 ) ),
116+
QgsLineSegment2D( QgsPointXY( 5, 6 ), QgsPointXY( 8, 9 ) ) ) );
117+
QVERIFY( comp( QgsLineSegment2D( QgsPointXY( 5, 6 ), QgsPointXY( 8, 9 ) ),
118+
QgsLineSegment2D( QgsPointXY( 1, 2 ), QgsPointXY( 3, 4 ) ) ) );
119+
QVERIFY( !comp( QgsLineSegment2D( QgsPointXY( 5, 6 ), QgsPointXY( 8, 9 ) ),
120+
QgsLineSegment2D( QgsPointXY( 8, 9 ), QgsPointXY( 13, 14 ) ) ) );
121+
QVERIFY( !comp( QgsLineSegment2D( QgsPointXY( 8, 9 ), QgsPointXY( 13, 14 ) ),
122+
QgsLineSegment2D( QgsPointXY( 5, 6 ), QgsPointXY( 8, 9 ) ) ) );
123+
QVERIFY( comp( QgsLineSegment2D( QgsPointXY( 1, 4 ), QgsPointXY( 8, 9 ) ),
124+
QgsLineSegment2D( QgsPointXY( 8, 9 ), QgsPointXY( 15, 16 ) ) ) );
125+
}
126+
98127
QGSTEST_MAIN( TestQgsInternalGeometryEngine )
99128
#include "testqgsinternalgeometryengine.moc"

0 commit comments

Comments
 (0)