Skip to content

Commit

Permalink
[FEATURE] rotate() expression function
Browse files Browse the repository at this point in the history
Allows rotation of geometries around a point
  • Loading branch information
raymondnijssen authored and nyalldawson committed Jan 2, 2020
1 parent 5792966 commit 933f1ca
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 0 deletions.
10 changes: 10 additions & 0 deletions resources/function_help/json/rotate
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "rotate",
"type": "function",
"description": "Returns a rotated version of a geometry. Calculations are in the Spatial Reference System of this geometry.",
"arguments": [ {"arg":"geom","description":"a geometry"},
{"arg":"rotation","description":"clockwise rotation in degrees"},
{"arg":"point","description":"rotation center"}
],
"examples": [ { "expression":"rotate($geometry, 45, centroid($geometry))", "returns":"a rotated geometry of the same type as the original one"}]
}
36 changes: 36 additions & 0 deletions src/core/expression/qgsexpressionfunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3400,6 +3400,38 @@ static QVariant fcnTranslate( const QVariantList &values, const QgsExpressionCon
fGeom.translate( dx, dy );
return QVariant::fromValue( fGeom );
}

static QVariant fcnRotate( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
{
QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
double rotation = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
QgsGeometry center = QgsExpressionUtils::getGeometry( values.at( 2 ), parent );

if ( center.isNull() || center.type() != QgsWkbTypes::PointGeometry )
{
parent->setEvalErrorString( QObject::tr( "Function 'rotate' requires a point value for the center" ) );
return QVariant();
}

QgsPointXY pt = center.asPoint();
if ( center.isMultipart() )
{
QgsMultiPointXY multiPoint = center.asMultiPoint();
if ( multiPoint.count() == 1 )
{
pt = multiPoint[0];
}
else
{
parent->setEvalErrorString( QObject::tr( "Function 'rotate' requires a point value for the center" ) );
return QVariant();
}
}

fGeom.rotate( rotation, pt );
return QVariant::fromValue( fGeom );
}

static QVariant fcnCentroid( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
{
QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
Expand Down Expand Up @@ -5664,6 +5696,10 @@ const QList<QgsExpressionFunction *> &QgsExpression::Functions()
<< QgsExpressionFunction::Parameter( QStringLiteral( "dx" ) )
<< QgsExpressionFunction::Parameter( QStringLiteral( "dy" ) ),
fcnTranslate, QStringLiteral( "GeometryGroup" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "rotate" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) )
<< QgsExpressionFunction::Parameter( QStringLiteral( "rotation" ) )
<< QgsExpressionFunction::Parameter( QStringLiteral( "center" ) ),
fcnRotate, QStringLiteral( "GeometryGroup" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "buffer" ), -1, fcnBuffer, QStringLiteral( "GeometryGroup" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "force_rhr" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
fcnForceRHR, QStringLiteral( "GeometryGroup" ) )
Expand Down
9 changes: 9 additions & 0 deletions tests/src/core/testqgsexpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2947,6 +2947,15 @@ class TestQgsExpression: public QObject
QTest::newRow( "translate" ) << "translate( $geometry, -1, 2)" << geom << false << true << QgsGeometry::fromWkt( QStringLiteral( "LINESTRING (-1 2, 9 12)" ) );
geom = QgsGeometry::fromPointXY( point );
QTest::newRow( "translate" ) << "translate( $geometry, 1, -2)" << geom << false << true << QgsGeometry::fromWkt( QStringLiteral( "POINT(1 -2)" ) );

geom = QgsGeometry::fromPolygonXY( polygon );
QTest::newRow( "rotate" ) << "rotate( $geometry, 90, geomFromWKT( 'POINT(10 10)' ) )" << geom << false << true << QgsGeometry::fromWkt( QStringLiteral( "Polygon ((0 20, 10 10, 0 10, 0 20))" ) );
geom = QgsGeometry::fromPolylineXY( line );
QTest::newRow( "rotate" ) << "rotate( $geometry, -90, geomFromWKT( 'POINT(5 5)' ) )" << geom << false << true << QgsGeometry::fromWkt( QStringLiteral( "LineString (10 0, 0 10)'" ) );
geom = QgsGeometry::fromPointXY( point );
QTest::newRow( "rotate" ) << "rotate( $geometry, 180, geomFromWKT( 'POINT(-5 -3)' ) )" << geom << false << true << QgsGeometry::fromWkt( QStringLiteral( "Point (-10 -6)" ) );
QTest::newRow( "rotate" ) << "rotate( $geometry, 180, geomFromWKT( 'MULTIPOINT((-5 -3))' ) )" << geom << false << true << QgsGeometry::fromWkt( QStringLiteral( "Point (-10 -6)" ) );
QTest::newRow( "rotate" ) << "rotate( $geometry, 180, geomFromWKT( 'MULTIPOINT((-5 -3, 7 7, 4 4))' ) )" << geom << true << true << QgsVariant();
}

void eval_geometry_method()
Expand Down

0 comments on commit 933f1ca

Please sign in to comment.