Skip to content

Commit 4c704be

Browse files
committed
Add geometry methods for calculating the distance to a specified
vertex from the start of the geometry
1 parent d464f86 commit 4c704be

File tree

7 files changed

+116
-0
lines changed

7 files changed

+116
-0
lines changed

python/core/geometry/qgsgeometry.sip

+8
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,14 @@ class QgsGeometry
184184
//TODO QGIS 3.0 - rename beforeVertex to previousVertex, afterVertex to nextVertex
185185
QgsPoint closestVertex( const QgsPoint& point, int& atVertex /Out/, int& beforeVertex /Out/, int& afterVertex /Out/, double& sqrDist /Out/ ) const;
186186

187+
/**
188+
* Returns the distance along this geometry from its first vertex to the specified vertex.
189+
* @param vertex vertex index to calculate distance to
190+
* @returns distance to vertex (following geometry), or -1 for invalid vertex numbers
191+
* @note added in QGIS 2.16
192+
*/
193+
double distanceToVertex( int vertex ) const;
194+
187195
/**
188196
* Returns the indexes of the vertices before and after the given vertex index.
189197
*

src/core/geometry/qgsgeometry.cpp

+16
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,22 @@ QgsPoint QgsGeometry::closestVertex( const QgsPoint& point, int& atVertex, int&
361361
return QgsPoint( vp.x(), vp.y() );
362362
}
363363

364+
double QgsGeometry::distanceToVertex( int vertex ) const
365+
{
366+
if ( !d->geometry )
367+
{
368+
return -1;
369+
}
370+
371+
QgsVertexId id;
372+
if ( !vertexIdFromVertexNr( vertex, id ) )
373+
{
374+
return -1;
375+
}
376+
377+
return QgsGeometryUtils::distanceToVertex( *( d->geometry ), id );
378+
}
379+
364380
void QgsGeometry::adjacentVertices( int atVertex, int& beforeVertex, int& afterVertex ) const
365381
{
366382
if ( !d->geometry )

src/core/geometry/qgsgeometry.h

+8
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,14 @@ class CORE_EXPORT QgsGeometry
226226
//TODO QGIS 3.0 - rename beforeVertex to previousVertex, afterVertex to nextVertex
227227
QgsPoint closestVertex( const QgsPoint& point, int& atVertex, int& beforeVertex, int& afterVertex, double& sqrDist ) const;
228228

229+
/**
230+
* Returns the distance along this geometry from its first vertex to the specified vertex.
231+
* @param vertex vertex index to calculate distance to
232+
* @returns distance to vertex (following geometry), or -1 for invalid vertex numbers
233+
* @note added in QGIS 2.16
234+
*/
235+
double distanceToVertex( int vertex ) const;
236+
229237
/**
230238
* Returns the indexes of the vertices before and after the given vertex index.
231239
*

src/core/geometry/qgsgeometryutils.cpp

+29
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,35 @@ QgsPointV2 QgsGeometryUtils::closestVertex( const QgsAbstractGeometryV2& geom, c
8989
return minDistPoint;
9090
}
9191

92+
double QgsGeometryUtils::distanceToVertex( const QgsAbstractGeometryV2 &geom, const QgsVertexId &id )
93+
{
94+
double currentDist = 0;
95+
QgsVertexId vertexId;
96+
QgsPointV2 vertex;
97+
QgsPointV2 previousVertex;
98+
99+
bool first = true;
100+
while ( geom.nextVertex( vertexId, vertex ) )
101+
{
102+
if ( !first )
103+
{
104+
currentDist += sqrt( QgsGeometryUtils::sqrDistance2D( previousVertex, vertex ) );
105+
}
106+
107+
previousVertex = vertex;
108+
first = false;
109+
110+
if ( vertexId == id )
111+
{
112+
//found target vertex
113+
return currentDist;
114+
}
115+
}
116+
117+
//could not find target vertex
118+
return -1;
119+
}
120+
92121
void QgsGeometryUtils::adjacentVertices( const QgsAbstractGeometryV2& geom, QgsVertexId atVertex, QgsVertexId& beforeVertex, QgsVertexId& afterVertex )
93122
{
94123
bool polygonType = ( geom.dimension() == 2 );

src/core/geometry/qgsgeometryutils.h

+8
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ class CORE_EXPORT QgsGeometryUtils
4141
*/
4242
static QgsPointV2 closestVertex( const QgsAbstractGeometryV2& geom, const QgsPointV2& pt, QgsVertexId& id );
4343

44+
/** Returns the distance along a geometry from its first vertex to the specified vertex.
45+
* @param geom geometry
46+
* @param id vertex id to find distance to
47+
* @returns distance to vertex (following geometry)
48+
* @note added in QGIS 2.16
49+
*/
50+
static double distanceToVertex( const QgsAbstractGeometryV2& geom, const QgsVertexId& id );
51+
4452
/** Returns vertices adjacent to a specified vertex within a geometry.
4553
*/
4654
static void adjacentVertices( const QgsAbstractGeometryV2& geom, QgsVertexId atVertex, QgsVertexId& beforeVertex, QgsVertexId& afterVertex );

tests/src/core/testqgsgeometryutils.cpp

+31
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class TestQgsGeometryUtils: public QObject
4343
void testLinePerpendicularAngle();
4444
void testAverageAngle_data();
4545
void testAverageAngle();
46+
void testDistanceToVertex();
4647
};
4748

4849

@@ -330,6 +331,36 @@ void TestQgsGeometryUtils::testAverageAngle()
330331
QVERIFY( qgsDoubleNear( averageAngle, expected, 0.0000000001 ) );
331332
}
332333

334+
void TestQgsGeometryUtils::testDistanceToVertex()
335+
{
336+
//test with linestring
337+
QgsLineStringV2* outerRing1 = new QgsLineStringV2();
338+
outerRing1->setPoints( QList<QgsPointV2>() << QgsPointV2( 1, 1 ) << QgsPointV2( 1, 2 ) << QgsPointV2( 2, 2 ) << QgsPointV2( 2, 1 ) << QgsPointV2( 1, 1 ) );
339+
QCOMPARE( QgsGeometryUtils::distanceToVertex( *outerRing1, QgsVertexId( 0, 0, 0 ) ), 0.0 );
340+
QCOMPARE( QgsGeometryUtils::distanceToVertex( *outerRing1, QgsVertexId( 0, 0, 1 ) ), 1.0 );
341+
QCOMPARE( QgsGeometryUtils::distanceToVertex( *outerRing1, QgsVertexId( 0, 0, 2 ) ), 2.0 );
342+
QCOMPARE( QgsGeometryUtils::distanceToVertex( *outerRing1, QgsVertexId( 0, 0, 3 ) ), 3.0 );
343+
QCOMPARE( QgsGeometryUtils::distanceToVertex( *outerRing1, QgsVertexId( 0, 0, 4 ) ), 4.0 );
344+
QCOMPARE( QgsGeometryUtils::distanceToVertex( *outerRing1, QgsVertexId( 0, 0, 5 ) ), -1.0 );
345+
QCOMPARE( QgsGeometryUtils::distanceToVertex( *outerRing1, QgsVertexId( 0, 1, 1 ) ), -1.0 );
346+
347+
//test with polygon
348+
QgsPolygonV2 polygon1;
349+
polygon1.setExteriorRing( outerRing1 );
350+
QCOMPARE( QgsGeometryUtils::distanceToVertex( polygon1, QgsVertexId( 0, 0, 0 ) ), 0.0 );
351+
QCOMPARE( QgsGeometryUtils::distanceToVertex( polygon1, QgsVertexId( 0, 0, 1 ) ), 1.0 );
352+
QCOMPARE( QgsGeometryUtils::distanceToVertex( polygon1, QgsVertexId( 0, 0, 2 ) ), 2.0 );
353+
QCOMPARE( QgsGeometryUtils::distanceToVertex( polygon1, QgsVertexId( 0, 0, 3 ) ), 3.0 );
354+
QCOMPARE( QgsGeometryUtils::distanceToVertex( polygon1, QgsVertexId( 0, 0, 4 ) ), 4.0 );
355+
QCOMPARE( QgsGeometryUtils::distanceToVertex( polygon1, QgsVertexId( 0, 0, 5 ) ), -1.0 );
356+
QCOMPARE( QgsGeometryUtils::distanceToVertex( polygon1, QgsVertexId( 0, 1, 1 ) ), -1.0 );
357+
358+
//test with point
359+
QgsPointV2 point( 1, 2 );
360+
QCOMPARE( QgsGeometryUtils::distanceToVertex( point, QgsVertexId( 0, 0, 0 ) ), 0.0 );
361+
QCOMPARE( QgsGeometryUtils::distanceToVertex( point, QgsVertexId( 0, 0, 1 ) ), -1.0 );
362+
}
363+
333364

334365
QTEST_MAIN( TestQgsGeometryUtils )
335366
#include "testqgsgeometryutils.moc"

tests/src/python/test_qgsgeometry.py

+16
Original file line numberDiff line numberDiff line change
@@ -1837,6 +1837,22 @@ def testAddMValue(self):
18371837
wkt = geom.exportToWkt()
18381838
assert compareWkt(expWkt, wkt), "addMValue to Point failed: mismatch Expected:\n%s\nGot:\n%s\n" % (expWkt, wkt)
18391839

1840+
def testDistanceToVertex(self):
1841+
""" Test distanceToVertex calculation """
1842+
g = QgsGeometry()
1843+
self.assertEqual(g.distanceToVertex(0), -1)
1844+
1845+
g = QgsGeometry.fromWkt('LineString ()')
1846+
self.assertEqual(g.distanceToVertex(0), -1)
1847+
1848+
g = QgsGeometry.fromWkt('Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))')
1849+
self.assertEqual(g.distanceToVertex(0), 0)
1850+
self.assertEqual(g.distanceToVertex(1), 1)
1851+
self.assertEqual(g.distanceToVertex(2), 2)
1852+
self.assertEqual(g.distanceToVertex(3), 3)
1853+
self.assertEqual(g.distanceToVertex(4), 4)
1854+
self.assertEqual(g.distanceToVertex(5), -1)
1855+
18401856
def testRelates(self):
18411857
""" Test relationships between geometries. Note the bulk of these tests were taken from the PostGIS relate testdata """
18421858
with open(os.path.join(TEST_DATA_DIR, 'relates_data.csv'), 'r') as d:

0 commit comments

Comments
 (0)