Skip to content

Commit

Permalink
[FEATURE] New project(point, distance, bearing) expression function
Browse files Browse the repository at this point in the history
Projects a point geometry by the specified distance and bearing
  • Loading branch information
nyalldawson committed Apr 6, 2016
1 parent 2e44c11 commit fd7a4bd
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 1 deletion.
13 changes: 13 additions & 0 deletions resources/function_help/json/project
@@ -0,0 +1,13 @@
{
"name": "project",
"type": "function",
"description": "Returns a point projected from a start point using a distance and bearing (azimuth) in radians.",
"arguments": [
{"arg":"point","description":"start point"},
{"arg":"distance","description":"distance to project"},
{"arg":"bearing","description":"bearing in radians clockwise, where 0 corresponds to north"}
],
"examples": [
{ "expression":"project(make_point(1, 2), 3, radians(270))", "returns":"Point(-2, 2)"}
]
}
22 changes: 21 additions & 1 deletion src/core/qgsexpression.cpp
Expand Up @@ -2143,6 +2143,25 @@ static QVariant fcnAzimuth( const QVariantList& values, const QgsExpressionConte
}
}

static QVariant fcnProject( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
{
QgsGeometry geom = getGeometry( values.at( 0 ), parent );

if ( geom.type() != QGis::Point )
{
parent->setEvalErrorString( "'project' requires a point geometry" );
return QVariant();
}

double distance = getDoubleValue( values.at( 1 ), parent );
double bearing = getDoubleValue( values.at( 2 ), parent );

QgsPoint p = geom.asPoint();
QgsPoint newPoint = p.project( distance, ( 180 * bearing ) / M_PI );

return QVariant::fromValue( QgsGeometry( new QgsPointV2( newPoint.x(), newPoint.y() ) ) );
}

static QVariant fcnExtrude( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
{
if ( values.length() != 3 )
Expand Down Expand Up @@ -2841,7 +2860,7 @@ const QStringList& QgsExpression::BuiltinFunctions()
<< "overlaps" << "within" << "buffer" << "centroid" << "bounds" << "reverse" << "exterior_ring"
<< "bounds_width" << "bounds_height" << "is_closed" << "convex_hull" << "difference"
<< "distance" << "intersection" << "sym_difference" << "combine"
<< "extrude" << "azimuth" << "closest_point" << "shortest_line"
<< "extrude" << "azimuth" << "project" << "closest_point" << "shortest_line"
<< "union" << "geom_to_wkt" << "geomToWKT" << "geometry"
<< "transform" << "get_feature" << "getFeature"
<< "levenshtein" << "longest_common_substring" << "hamming_distance"
Expand All @@ -2864,6 +2883,7 @@ const QList<QgsExpression::Function*>& QgsExpression::Functions()
<< new StaticFunction( "radians", ParameterList() << Parameter( "degrees" ), fcnRadians, "Math" )
<< new StaticFunction( "degrees", ParameterList() << Parameter( "radians" ), fcnDegrees, "Math" )
<< new StaticFunction( "azimuth", ParameterList() << Parameter( "point_a" ) << Parameter( "point_b" ), fcnAzimuth, "Math" )
<< new StaticFunction( "project", ParameterList() << Parameter( "point" ) << Parameter( "distance" ) << Parameter( "bearing" ), fcnProject, "GeometryGroup" )
<< new StaticFunction( "abs", ParameterList() << Parameter( "value" ), fcnAbs, "Math" )
<< new StaticFunction( "cos", ParameterList() << Parameter( "angle" ), fcnCos, "Math" )
<< new StaticFunction( "sin", ParameterList() << Parameter( "angle" ), fcnSin, "Math" )
Expand Down
4 changes: 4 additions & 0 deletions tests/src/core/testqgsexpression.cpp
Expand Up @@ -645,6 +645,10 @@ class TestQgsExpression: public QObject
QTest::newRow( "relate pattern false" ) << "relate( geom_from_wkt( 'LINESTRING(40 40,120 120)' ), geom_from_wkt( 'LINESTRING(40 40,60 120)' ), '**1F002**' )" << false << QVariant( false );
QTest::newRow( "azimuth" ) << "toint(degrees(azimuth( point_a := make_point(25, 45), point_b := make_point(75, 100)))*1000000)" << false << QVariant( 42273689 );
QTest::newRow( "azimuth" ) << "toint(degrees( azimuth( make_point(75, 100), make_point(25,45) ) )*1000000)" << false << QVariant( 222273689 );
QTest::newRow( "project not geom" ) << "project( 'asd', 1, 2 )" << true << QVariant();
QTest::newRow( "project not point" ) << "project( geom_from_wkt('LINESTRING(2 0,2 2, 3 2, 3 0)'), 1, 2 )" << true << QVariant();
QTest::newRow( "project x" ) << "toint(x(project( make_point( 1, 2 ), 3, radians(270)))*1000000)" << false << QVariant( -2 * 1000000 );
QTest::newRow( "project y" ) << "toint(y(project( point:=make_point( 1, 2 ), distance:=3, bearing:=radians(270)))*1000000)" << false << QVariant( 2 * 1000000 );
QTest::newRow( "extrude geom" ) << "geom_to_wkt(extrude( geom_from_wkt('LineString( 1 2, 3 2, 4 3)'),1,2))" << false << QVariant( "Polygon ((1 2, 3 2, 4 3, 5 5, 4 4, 2 4, 1 2))" );
QTest::newRow( "extrude not geom" ) << "extrude('g',5,6)" << true << QVariant();
QTest::newRow( "extrude null" ) << "extrude(NULL,5,6)" << false << QVariant();
Expand Down

0 comments on commit fd7a4bd

Please sign in to comment.