Skip to content

Commit a2d4bbe

Browse files
committed
Add geometry methods for interpolating angle along geometry
Sponsored by Andreas Neumann (cherry-picked from 93c7f5f)
1 parent 193e9e7 commit a2d4bbe

11 files changed

+10156
-0
lines changed

python/core/geometry/qgsgeometry.sip

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,15 @@ class QgsGeometry
488488
*/
489489
double lineLocatePoint( const QgsGeometry& point ) const;
490490

491+
/** Returns the angle parallel to the linestring or polygon boundary at the specified distance
492+
* along the geometry. Angles are in radians, clockwise from north.
493+
* If the distance coincides precisely at a node then the average angle from the segment either side
494+
* of the node is returned.
495+
* @param distance distance along geometry
496+
* @note added in QGIS 3.0
497+
*/
498+
double interpolateAngle( double distance ) const;
499+
491500
/** Returns a geometry representing the points shared by this geometry and other. */
492501
QgsGeometry* intersection( const QgsGeometry* geometry ) const /Factory/;
493502

src/core/geometry/qgsgeometry.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1409,6 +1409,61 @@ double QgsGeometry::lineLocatePoint( const QgsGeometry& point ) const
14091409
return geos.lineLocatePoint( *( static_cast< QgsPointV2* >( point.d->geometry ) ) );
14101410
}
14111411

1412+
double QgsGeometry::interpolateAngle( double distance ) const
1413+
{
1414+
if ( !d->geometry )
1415+
return 0.0;
1416+
1417+
// always operate on segmentized geometries
1418+
QgsGeometry segmentized = *this;
1419+
if ( QgsWKBTypes::isCurvedType( d->geometry->wkbType() ) )
1420+
{
1421+
segmentized = QgsGeometry( static_cast< QgsCurveV2* >( d->geometry )->segmentize() );
1422+
}
1423+
1424+
QgsVertexId previous;
1425+
QgsVertexId next;
1426+
if ( !QgsGeometryUtils::verticesAtDistance( *segmentized.geometry(), distance, previous, next ) )
1427+
return 0.0;
1428+
1429+
if ( previous == next )
1430+
{
1431+
// distance coincided exactly with a vertex
1432+
QgsVertexId v2 = previous;
1433+
QgsVertexId v1;
1434+
QgsVertexId v3;
1435+
QgsGeometryUtils::adjacentVertices( *segmentized.geometry(), v2, v1, v3 );
1436+
if ( v1.isValid() && v3.isValid() )
1437+
{
1438+
QgsPointV2 p1 = segmentized.geometry()->vertexAt( v1 );
1439+
QgsPointV2 p2 = segmentized.geometry()->vertexAt( v2 );
1440+
QgsPointV2 p3 = segmentized.geometry()->vertexAt( v3 );
1441+
double angle1 = QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
1442+
double angle2 = QgsGeometryUtils::lineAngle( p2.x(), p2.y(), p3.x(), p3.y() );
1443+
return QgsGeometryUtils::averageAngle( angle1, angle2 );
1444+
}
1445+
else if ( v3.isValid() )
1446+
{
1447+
QgsPointV2 p1 = segmentized.geometry()->vertexAt( v2 );
1448+
QgsPointV2 p2 = segmentized.geometry()->vertexAt( v3 );
1449+
return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
1450+
}
1451+
else
1452+
{
1453+
QgsPointV2 p1 = segmentized.geometry()->vertexAt( v1 );
1454+
QgsPointV2 p2 = segmentized.geometry()->vertexAt( v2 );
1455+
return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
1456+
}
1457+
}
1458+
else
1459+
{
1460+
QgsPointV2 p1 = segmentized.geometry()->vertexAt( previous );
1461+
QgsPointV2 p2 = segmentized.geometry()->vertexAt( next );
1462+
return QgsGeometryUtils::lineAngle( p1.x(), p1.y(), p2.x(), p2.y() );
1463+
}
1464+
}
1465+
1466+
14121467
QgsGeometry* QgsGeometry::intersection( const QgsGeometry* geometry ) const
14131468
{
14141469
if ( !d->geometry || !geometry->d->geometry )

src/core/geometry/qgsgeometry.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,15 @@ class CORE_EXPORT QgsGeometry
531531
*/
532532
double lineLocatePoint( const QgsGeometry& point ) const;
533533

534+
/** Returns the angle parallel to the linestring or polygon boundary at the specified distance
535+
* along the geometry. Angles are in radians, clockwise from north.
536+
* If the distance coincides precisely at a node then the average angle from the segment either side
537+
* of the node is returned.
538+
* @param distance distance along geometry
539+
* @note added in QGIS 3.0
540+
*/
541+
double interpolateAngle( double distance ) const;
542+
534543
/** Returns a geometry representing the points shared by this geometry and other. */
535544
QgsGeometry* intersection( const QgsGeometry* geometry ) const;
536545

0 commit comments

Comments
 (0)