Skip to content

Commit

Permalink
Add azimuth function
Browse files Browse the repository at this point in the history
  • Loading branch information
m-kuhn committed Jan 13, 2016
1 parent f8de083 commit b7170b8
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 0 deletions.
13 changes: 13 additions & 0 deletions resources/function_help/json/azimuth
@@ -0,0 +1,13 @@
{
"name": "azimuth",
"type": "function",
"description": "Returns the north-based azimuth as the angle in radians measured clockwise from the vertical on pointA to pointB.",
"arguments": [
{"arg":"pointA","description":"point geometry"},
{"arg":"pointB","description":"point geometry"}
],
"examples": [
{ "expression":"degrees( azimuth( make_point(25, 45), make_point(75, 100) ) )", "returns":"42.273689"},
{ "expression":"degrees( azimuth( make_point(75, 100), make_point(25,45) ) )", "returns":"222.273689"}
]
}
72 changes: 72 additions & 0 deletions src/core/qgsexpression.cpp
Expand Up @@ -2082,6 +2082,77 @@ static QVariant fcnGeomToWKT( const QVariantList& values, const QgsExpressionCon
return QVariant( wkt );
}

static QVariant fcnAzimuth( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
{
if ( values.length() != 2 )
{
parent->setEvalErrorString( QObject::tr( "Function `azimuth` requires exactly two parameters. %1 given." ).arg( values.length() ) );
return QVariant();
}

QgsGeometry fGeom1 = getGeometry( values.at( 0 ), parent );
QgsGeometry fGeom2 = getGeometry( values.at( 1 ), parent );

const QgsPointV2* pt1 = dynamic_cast<const QgsPointV2*>( fGeom1.geometry() );
const QgsPointV2* pt2 = dynamic_cast<const QgsPointV2*>( fGeom2.geometry() );

if ( !pt1 || !pt2 )
{
parent->setEvalErrorString( QObject::tr( "Function `azimuth` requires two points as arguments." ) );
return QVariant();
}

// Code from postgis
if ( pt1->x() == pt2->x() )
{
if ( pt1->y() < pt2->y() )
return 0.0;
else if ( pt1->y() > pt2->y() )
return M_PI;
else return 0;
return 1;
}

if ( pt1->y() == pt2->y() )
{
if ( pt1->x() < pt2->x() )
return M_PI / 2;
else if ( pt1->x() > pt2->x() )
return M_PI + ( M_PI / 2 );
else return 0;
return 1;
}

if ( pt1->x() < pt2->x() )
{
if ( pt1->y() < pt2->y() )
{
return atan( fabs( pt1->x() - pt2->x() ) / fabs( pt1->y() - pt2->y() ) );
}
else /* ( pt1->y() > pt2->y() ) - equality case handled above */
{
return atan( fabs( pt1->y() - pt2->y() ) / fabs( pt1->x() - pt2->x() ) )
+ ( M_PI / 2 );
}
}

else /* ( pt1->x() > pt2->x() ) - equality case handled above */
{
if ( pt1->y() > pt2->y() )
{
return atan( fabs( pt1->x() - pt2->x() ) / fabs( pt1->y() - pt2->y() ) )
+ M_PI;
}
else /* ( pt1->y() < pt2->y() ) - equality case handled above */
{
return atan( fabs( pt1->y() - pt2->y() ) / fabs( pt1->x() - pt2->x() ) )
+ ( M_PI + ( M_PI / 2 ) );
}
}

return QVariant();
}

static QVariant fcnRound( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
{
if ( values.length() == 2 )
Expand Down Expand Up @@ -2700,6 +2771,7 @@ const QList<QgsExpression::Function*>& QgsExpression::Functions()
<< new StaticFunction( "sqrt", 1, fcnSqrt, "Math" )
<< new StaticFunction( "radians", 1, fcnRadians, "Math" )
<< new StaticFunction( "degrees", 1, fcnDegrees, "Math" )
<< new StaticFunction( "azimuth", 2, fcnAzimuth, "Math" )
<< new StaticFunction( "abs", 1, fcnAbs, "Math" )
<< new StaticFunction( "cos", 1, fcnCos, "Math" )
<< new StaticFunction( "sin", 1, fcnSin, "Math" )
Expand Down
2 changes: 2 additions & 0 deletions tests/src/core/testqgsexpression.cpp
Expand Up @@ -581,6 +581,8 @@ class TestQgsExpression: public QObject
QTest::newRow( "relate bad 2" ) << "relate(geom_from_wkt('POINT(110 120)'),geom_from_wkt(''))" << false << QVariant();
QTest::newRow( "relate pattern true" ) << "relate( geom_from_wkt( 'LINESTRING(40 40,120 120)' ), geom_from_wkt( 'LINESTRING(40 40,60 120)' ), '**1F001**' )" << false << QVariant( true );
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( make_point(25, 45), 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 );

// string functions
QTest::newRow( "lower" ) << "lower('HeLLo')" << false << QVariant( "hello" );
Expand Down

0 comments on commit b7170b8

Please sign in to comment.