Skip to content

Commit 1b79b9a

Browse files
committedNov 9, 2018
[FEATURE] force_rhr expression function
Forces polygons to follow the right hand rule, in which the area that is bounded by a polygon is to the right of the boundary. In particular, the exterior ring is oriented in a clockwise direction and the interior rings in a counter-clockwise direction.
1 parent 27e1ef5 commit 1b79b9a

File tree

4 files changed

+58
-0
lines changed

4 files changed

+58
-0
lines changed
 
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"name": "force_rhr",
3+
"type": "function",
4+
"description": "Forces a geometry to respect the Right-Hand-Rule, in which the area that is bounded by a polygon is to the right of the boundary. In particular, the exterior ring is oriented in a clockwise direction and the interior rings in a counter-clockwise direction.",
5+
"arguments": [ {"arg":"geom","description":"a geometry. Any non-polygon geometries are returned unchanged."}],
6+
"examples": [ { "expression":"geom_to_wkt(force_rhr(geometry:=geom_from_wkt('POLYGON((-1 -1, 4 0, 4 2, 0 2, -1 -1))')))", "returns":"Polygon ((-1 -1, 0 2, 4 2, 4 0, -1 -1))"}]
7+
}
8+

‎src/core/expression/qgsexpressionfunction.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2692,6 +2692,46 @@ static QVariant fcnBuffer( const QVariantList &values, const QgsExpressionContex
26922692
return result;
26932693
}
26942694

2695+
static QVariant fcnForceRHR( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2696+
{
2697+
QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2698+
if ( fGeom.isMultipart() )
2699+
{
2700+
const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( fGeom.constGet() );
2701+
std::unique_ptr< QgsGeometryCollection > newCollection( collection->createEmptyWithSameType() );
2702+
for ( int i = 0; i < collection->numGeometries(); ++i )
2703+
{
2704+
const QgsAbstractGeometry *g = collection->geometryN( i );
2705+
if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( g ) )
2706+
{
2707+
std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
2708+
corrected->forceRHR();
2709+
newCollection->addGeometry( corrected.release() );
2710+
}
2711+
else
2712+
{
2713+
newCollection->addGeometry( g->clone() );
2714+
}
2715+
}
2716+
QgsGeometry geom( std::move( newCollection ) );
2717+
return !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
2718+
}
2719+
else
2720+
{
2721+
if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( fGeom.constGet() ) )
2722+
{
2723+
std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
2724+
corrected->forceRHR();
2725+
QgsGeometry geom( std::move( corrected ) );
2726+
return !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
2727+
}
2728+
else
2729+
{
2730+
return fGeom;
2731+
}
2732+
}
2733+
}
2734+
26952735
static QVariant fcnWedgeBuffer( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
26962736
{
26972737
QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
@@ -4687,6 +4727,8 @@ const QList<QgsExpressionFunction *> &QgsExpression::Functions()
46874727
<< new QgsStaticExpressionFunction( QStringLiteral( "within" ), 2, fcnWithin, QStringLiteral( "GeometryGroup" ) )
46884728
<< new QgsStaticExpressionFunction( QStringLiteral( "translate" ), 3, fcnTranslate, QStringLiteral( "GeometryGroup" ) )
46894729
<< new QgsStaticExpressionFunction( QStringLiteral( "buffer" ), -1, fcnBuffer, QStringLiteral( "GeometryGroup" ) )
4730+
<< new QgsStaticExpressionFunction( QStringLiteral( "force_rhr" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
4731+
fcnForceRHR, QStringLiteral( "GeometryGroup" ) )
46904732
<< new QgsStaticExpressionFunction( QStringLiteral( "wedge_buffer" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "center" ) )
46914733
<< QgsExpressionFunction::Parameter( QStringLiteral( "azimuth" ) )
46924734
<< QgsExpressionFunction::Parameter( QStringLiteral( "width" ) )

‎tests/src/core/testqgsexpression.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -816,6 +816,12 @@ class TestQgsExpression: public QObject
816816
QTest::newRow( "geometry_n collection" ) << "geom_to_wkt(geometry_n(geom_from_wkt('GEOMETRYCOLLECTION(POINT(0 1), POINT(0 0), POINT(1 0), POINT(1 1))'),3))" << false << QVariant( QStringLiteral( "Point (1 0)" ) );
817817
QTest::newRow( "geometry_n collection bad index 1" ) << "geometry_n(geom_from_wkt('GEOMETRYCOLLECTION(POINT(0 1), POINT(0 0), POINT(1 0), POINT(1 1))'),0)" << false << QVariant();
818818
QTest::newRow( "geometry_n collection bad index 2" ) << "geometry_n(geom_from_wkt('GEOMETRYCOLLECTION(POINT(0 1), POINT(0 0), POINT(1 0), POINT(1 1))'),5)" << false << QVariant();
819+
QTest::newRow( "force_rhr not geom" ) << "force_rhr('g')" << true << QVariant();
820+
QTest::newRow( "force_rhr null" ) << "force_rhr(NULL)" << false << QVariant();
821+
QTest::newRow( "force_rhr point" ) << "geom_to_wkt(force_rhr(geom_from_wkt('POINT(1 2)')))" << false << QVariant( "Point (1 2)" );
822+
QTest::newRow( "force_rhr polygon" ) << "geom_to_wkt(force_rhr(geometry:=geom_from_wkt('POLYGON((-1 -1, 4 0, 4 2, 0 2, -1 -1))')))" << false << QVariant( "Polygon ((-1 -1, 0 2, 4 2, 4 0, -1 -1))" );
823+
QTest::newRow( "force_rhr multipolygon" ) << "geom_to_wkt(force_rhr(geometry:=geom_from_wkt('MULTIPOLYGON(Polygon((-1 -1, 4 0, 4 2, 0 2, -1 -1)),Polygon((100 100, 200 100, 200 200, 100 200, 100 100)))')))" << false << QVariant( "MultiPolygon (((-1 -1, 0 2, 4 2, 4 0, -1 -1)),((100 100, 100 200, 200 200, 200 100, 100 100)))" );
824+
QTest::newRow( "force_rhr line" ) << "geom_to_wkt(force_rhr(geom_from_wkt('LINESTRING(0 0, 1 1, 2 2)')))" << false << QVariant( "LineString (0 0, 1 1, 2 2)" );
819825
QTest::newRow( "boundary not geom" ) << "boundary('g')" << true << QVariant();
820826
QTest::newRow( "boundary null" ) << "boundary(NULL)" << false << QVariant();
821827
QTest::newRow( "boundary point" ) << "boundary(geom_from_wkt('POINT(1 2)'))" << false << QVariant();
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
compressed_size=12008
2+
uncompressed_size=40684

0 commit comments

Comments
 (0)
Please sign in to comment.