Skip to content

Commit

Permalink
[FEATURE] pole_of_inaccessibility expression function
Browse files Browse the repository at this point in the history
Exposes calculation of pole of inaccessiblity to expression
engine
  • Loading branch information
nyalldawson committed Nov 14, 2016
1 parent 880647e commit 1f81a7c
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 0 deletions.
8 changes: 8 additions & 0 deletions resources/function_help/json/pole_of_inaccessibility
@@ -0,0 +1,8 @@
{
"name": "pole_of_inaccessibility",
"type": "function",
"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.",
"arguments": [ {"arg":"geometry","description":"a geometry"},
{"arg":"tolerance","description":"maximum distance between the returned point and the true pole location"}],
"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)"}]
}
12 changes: 12 additions & 0 deletions src/core/qgsexpression.cpp
Expand Up @@ -2582,6 +2582,16 @@ static QVariant fcnPointOnSurface( const QVariantList& values, const QgsExpressi
QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
return result;
}

static QVariant fcnPoleOfInaccessibility( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
{
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
double tolerance = getDoubleValue( values.at( 1 ), parent );
QgsGeometry geom = fGeom.poleOfInaccessibility( tolerance );
QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
return result;
}

static QVariant fcnConvexHull( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
{
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
Expand Down Expand Up @@ -3919,6 +3929,8 @@ const QList<QgsExpression::Function*>& QgsExpression::Functions()
fcnExtend, QStringLiteral( "GeometryGroup" ) )
<< new StaticFunction( QStringLiteral( "centroid" ), 1, fcnCentroid, QStringLiteral( "GeometryGroup" ) )
<< new StaticFunction( QStringLiteral( "point_on_surface" ), 1, fcnPointOnSurface, QStringLiteral( "GeometryGroup" ) )
<< new StaticFunction( QStringLiteral( "pole_of_inaccessibility" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) )
<< Parameter( QStringLiteral( "tolerance" ) ), fcnPoleOfInaccessibility, QStringLiteral( "GeometryGroup" ) )
<< new StaticFunction( QStringLiteral( "reverse" ), 1, fcnReverse, QStringLiteral( "GeometryGroup" ) )
<< new StaticFunction( QStringLiteral( "exterior_ring" ), 1, fcnExteriorRing, QStringLiteral( "GeometryGroup" ) )
<< new StaticFunction( QStringLiteral( "interior_ring_n" ), 2, fcnInteriorRingN, QStringLiteral( "GeometryGroup" ) )
Expand Down
5 changes: 5 additions & 0 deletions tests/src/core/testqgsexpression.cpp
Expand Up @@ -733,6 +733,11 @@ class TestQgsExpression: public QObject
QTest::newRow( "point on surface line" ) << "geom_to_wkt(point_on_surface( geomFromWKT('LINESTRING (-1 2, 9 12)') ))" << false << QVariant( "Point (-1 2)" );
QTest::newRow( "point on surface not geom" ) << "point_on_surface('g')" << true << QVariant();
QTest::newRow( "point on surface null" ) << "point_on_surface(NULL)" << false << QVariant();
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 );
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 );
QTest::newRow( "pole_of_inaccessibility not poly" ) << "geom_to_wkt(pole_of_inaccessibility( geomFromWKT('POINT (1.5 0.5)'), 0.1 ))" << false << QVariant();
QTest::newRow( "pole_of_inaccessibility not geom" ) << "pole_of_inaccessibility('g',0.1)" << true << QVariant();
QTest::newRow( "pole_of_inaccessibility null" ) << "pole_of_inaccessibility(NULL,0.1)" << false << QVariant();
QTest::newRow( "is_closed not geom" ) << "is_closed('g')" << true << QVariant();
QTest::newRow( "is_closed null" ) << "is_closed(NULL)" << false << QVariant();
QTest::newRow( "is_closed point" ) << "is_closed(geom_from_wkt('POINT(1 2)'))" << false << QVariant();
Expand Down

1 comment on commit 1f81a7c

@nirvn
Copy link
Contributor

@nirvn nirvn commented on 1f81a7c Nov 15, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Please sign in to comment.