Skip to content

Commit 1f81a7c

Browse files
committedNov 14, 2016
[FEATURE] pole_of_inaccessibility expression function
Exposes calculation of pole of inaccessiblity to expression engine
1 parent 880647e commit 1f81a7c

File tree

3 files changed

+25
-0
lines changed

3 files changed

+25
-0
lines changed
 
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"name": "pole_of_inaccessibility",
3+
"type": "function",
4+
"description": "Calculates the approximate pole of inaccessibility for a surface, which is the most distant internal point from the boundary of the surface. This function uses the 'polylabel' algorithm (Vladimir Agafonkin, 2016), which is an iterative approach guaranteed to find the true pole of inaccessibility within a specified tolerance. More precise tolerances require more iterations and will take longer to calculate.",
5+
"arguments": [ {"arg":"geometry","description":"a geometry"},
6+
{"arg":"tolerance","description":"maximum distance between the returned point and the true pole location"}],
7+
"examples": [ { "expression":"geom_to_wkt(pole_of_inaccessibility( geom_from_wkt('POLYGON((0 1,0 9,3 10,3 3, 10 3, 10 1, 0 1))'), 0.1))", "returns":"Point(1.55, 1.55)"}]
8+
}

‎src/core/qgsexpression.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2582,6 +2582,16 @@ static QVariant fcnPointOnSurface( const QVariantList& values, const QgsExpressi
25822582
QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
25832583
return result;
25842584
}
2585+
2586+
static QVariant fcnPoleOfInaccessibility( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2587+
{
2588+
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2589+
double tolerance = getDoubleValue( values.at( 1 ), parent );
2590+
QgsGeometry geom = fGeom.poleOfInaccessibility( tolerance );
2591+
QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
2592+
return result;
2593+
}
2594+
25852595
static QVariant fcnConvexHull( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
25862596
{
25872597
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
@@ -3919,6 +3929,8 @@ const QList<QgsExpression::Function*>& QgsExpression::Functions()
39193929
fcnExtend, QStringLiteral( "GeometryGroup" ) )
39203930
<< new StaticFunction( QStringLiteral( "centroid" ), 1, fcnCentroid, QStringLiteral( "GeometryGroup" ) )
39213931
<< new StaticFunction( QStringLiteral( "point_on_surface" ), 1, fcnPointOnSurface, QStringLiteral( "GeometryGroup" ) )
3932+
<< new StaticFunction( QStringLiteral( "pole_of_inaccessibility" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) )
3933+
<< Parameter( QStringLiteral( "tolerance" ) ), fcnPoleOfInaccessibility, QStringLiteral( "GeometryGroup" ) )
39223934
<< new StaticFunction( QStringLiteral( "reverse" ), 1, fcnReverse, QStringLiteral( "GeometryGroup" ) )
39233935
<< new StaticFunction( QStringLiteral( "exterior_ring" ), 1, fcnExteriorRing, QStringLiteral( "GeometryGroup" ) )
39243936
<< new StaticFunction( QStringLiteral( "interior_ring_n" ), 2, fcnInteriorRingN, QStringLiteral( "GeometryGroup" ) )

‎tests/src/core/testqgsexpression.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,11 @@ class TestQgsExpression: public QObject
733733
QTest::newRow( "point on surface line" ) << "geom_to_wkt(point_on_surface( geomFromWKT('LINESTRING (-1 2, 9 12)') ))" << false << QVariant( "Point (-1 2)" );
734734
QTest::newRow( "point on surface not geom" ) << "point_on_surface('g')" << true << QVariant();
735735
QTest::newRow( "point on surface null" ) << "point_on_surface(NULL)" << false << QVariant();
736+
QTest::newRow( "pole_of_inaccessibility polygon" ) << "round(x(pole_of_inaccessibility( geomFromWKT('POLYGON((0 1,0 9,3 10,3 3, 10 3, 10 1, 0 1))'), 0.1))*100)" << false << QVariant( 155 );
737+
QTest::newRow( "pole_of_inaccessibility polygon" ) << "round(y(pole_of_inaccessibility( geomFromWKT('POLYGON((0 1,0 9,3 10,3 3, 10 3, 10 1, 0 1))'), 0.1))*100)" << false << QVariant( 255 );
738+
QTest::newRow( "pole_of_inaccessibility not poly" ) << "geom_to_wkt(pole_of_inaccessibility( geomFromWKT('POINT (1.5 0.5)'), 0.1 ))" << false << QVariant();
739+
QTest::newRow( "pole_of_inaccessibility not geom" ) << "pole_of_inaccessibility('g',0.1)" << true << QVariant();
740+
QTest::newRow( "pole_of_inaccessibility null" ) << "pole_of_inaccessibility(NULL,0.1)" << false << QVariant();
736741
QTest::newRow( "is_closed not geom" ) << "is_closed('g')" << true << QVariant();
737742
QTest::newRow( "is_closed null" ) << "is_closed(NULL)" << false << QVariant();
738743
QTest::newRow( "is_closed point" ) << "is_closed(geom_from_wkt('POINT(1 2)'))" << false << QVariant();

1 commit comments

Comments
 (1)

nirvn commented on Nov 15, 2016

@nirvn
Contributor

@nyalldawson great feature, once again. While testing it I spotted an error: it fails on multipart polygons.

Please sign in to comment.