Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[expressions] Allow make_point to accept z/m values, add new
make_point_m for creation of PointM geometries. Also add
m(point) and z(point) functions for retrieving z/m value of
a point or node.
  • Loading branch information
nyalldawson committed Nov 6, 2015
1 parent 7439643 commit 12e34f2
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 16 deletions.
8 changes: 8 additions & 0 deletions resources/function_help/json/m
@@ -0,0 +1,8 @@
{
"name": "m",
"type": "function",
"description": "Returns the m value of a point geometry.",
"arguments": [ {"arg":"geom","description":"a point geometry"}],
"examples": [ { "expression":"m( geom_from_wkt( 'POINTM(2 5 4)' ) )", "returns":"4"}
]
}
11 changes: 8 additions & 3 deletions resources/function_help/json/make_point
@@ -1,9 +1,14 @@
{
"name": "make_point",
"type": "function",
"description": "Creates a point geometry from an x and y value.",
"description": "Creates a point geometry from an x and y (and optional z and m) value.",
"arguments": [
{"arg":"x","description":"x coordinate of point"},
{"arg":"y","description":"y coordinate of point"} ],
"examples": [ { "expression":"geom_to_wkt(make_point(2,4))", "returns":"'Point (2 4)'"}]
{"arg":"y","description":"y coordinate of point"},
{"arg":"z","description":"optional z coordinate of point"},
{"arg":"m","description":"optional m value of point"} ],
"examples": [ { "expression":"geom_to_wkt(make_point(2,4))", "returns":"'Point (2 4)'"},
{ "expression":"geom_to_wkt(make_point(2,4,6))", "returns":"'PointZ (2 4 6)'"},
{ "expression":"geom_to_wkt(make_point(2,4,6,8))", "returns":"'PointZM (2 4 6 8)'"}
]
}
10 changes: 10 additions & 0 deletions resources/function_help/json/make_point_m
@@ -0,0 +1,10 @@
{
"name": "make_point_m",
"type": "function",
"description": "Creates a point geometry from an x, y coordinate and m value.",
"arguments": [
{"arg":"x","description":"x coordinate of point"},
{"arg":"y","description":"y coordinate of point"},
{"arg":"m","description":"m value of point"} ],
"examples": [ { "expression":"geom_to_wkt(make_point_m(2,4,6))", "returns":"'PointM (2 4 6)'"} ]
}
8 changes: 8 additions & 0 deletions resources/function_help/json/z
@@ -0,0 +1,8 @@
{
"name": "z",
"type": "function",
"description": "Returns the z coordinate of a point geometry.",
"arguments": [ {"arg":"geom","description":"a point geometry"}],
"examples": [ { "expression":"z( geom_from_wkt( 'POINTZ(2 5 7)' ) )", "returns":"7"}
]
}
72 changes: 67 additions & 5 deletions src/core/qgsexpression.cpp
Expand Up @@ -1258,6 +1258,40 @@ static QVariant fcnGeomY( const QVariantList& values, const QgsExpressionContext
return result;
}

static QVariant fcnGeomZ( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
{
QgsGeometry geom = getGeometry( values.at( 0 ), parent );
if ( geom.isEmpty() )
return QVariant(); //or 0?

//if single point, return the point's z coordinate
if ( geom.type() == QGis::Point && !geom.isMultipart() )
{
QgsPointV2* point = dynamic_cast< QgsPointV2* >( geom.geometry() );
if ( point )
return point->z();
}

return QVariant();
}

static QVariant fcnGeomM( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
{
QgsGeometry geom = getGeometry( values.at( 0 ), parent );
if ( geom.isEmpty() )
return QVariant(); //or 0?

//if single point, return the point's m value
if ( geom.type() == QGis::Point && !geom.isMultipart() )
{
QgsPointV2* point = dynamic_cast< QgsPointV2* >( geom.geometry() );
if ( point )
return point->m();
}

return QVariant();
}

static QVariant fcnPointN( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
{
QgsGeometry geom = getGeometry( values.at( 0 ), parent );
Expand Down Expand Up @@ -1314,10 +1348,35 @@ static QVariant fcnEndPoint( const QVariantList& values, const QgsExpressionCont
}

static QVariant fcnMakePoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
{
if ( values.count() < 2 || values.count() > 4 )
{
parent->setEvalErrorString( QObject::tr( "Function make_point requires 2-4 arguments" ) );
return QVariant();
}

double x = getDoubleValue( values.at( 0 ), parent );
double y = getDoubleValue( values.at( 1 ), parent );
double z = values.count() >= 3 ? getDoubleValue( values.at( 2 ), parent ) : 0.0;
double m = values.count() >= 4 ? getDoubleValue( values.at( 3 ), parent ) : 0.0;
switch ( values.count() )
{
case 2:
return QVariant::fromValue( QgsGeometry( new QgsPointV2( x, y ) ) );
case 3:
return QVariant::fromValue( QgsGeometry( new QgsPointV2( QgsWKBTypes::PointZ, x, y, z ) ) );
case 4:
return QVariant::fromValue( QgsGeometry( new QgsPointV2( QgsWKBTypes::PointZM, x, y, z, m ) ) );
}
return QVariant(); //avoid warning
}

static QVariant fcnMakePointM( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
{
double x = getDoubleValue( values.at( 0 ), parent );
double y = getDoubleValue( values.at( 1 ), parent );
return QVariant::fromValue( QgsGeometry( new QgsPointV2( x, y ) ) );
double m = getDoubleValue( values.at( 2 ), parent );
return QVariant::fromValue( QgsGeometry( new QgsPointV2( QgsWKBTypes::PointM, x, y, 0.0, m ) ) );
}

static QVariant pointAt( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent ) // helper function
Expand Down Expand Up @@ -2034,7 +2093,7 @@ static QVariant fcnGetFeature( const QVariantList& values, const QgsExpressionCo
const QVariant& attVal = values.at( 2 );
QgsFeatureRequest req;
req.setFilterExpression( QString( "%1=%2" ).arg( QgsExpression::quotedColumnRef( attribute ),
QgsExpression::quotedString( attVal.toString() ) ) );
QgsExpression::quotedString( attVal.toString() ) ) );
if ( !parent->needsGeometry() )
{
req.setFlags( QgsFeatureRequest::NoGeometry );
Expand Down Expand Up @@ -2192,8 +2251,8 @@ const QStringList& QgsExpression::BuiltinFunctions()
<< "color_hsl" << "color_hsla" << "color_hsv" << "color_hsva"
<< "color_cmyk" << "color_cmyka" << "color_part" << "set_color_part"
<< "xat" << "yat" << "$area" << "area" << "perimeter"
<< "$length" << "$perimeter" << "x" << "y" << "$x" << "$y" << "num_points"
<< "point_n" << "start_point" << "end_point" << "make_point"
<< "$length" << "$perimeter" << "x" << "y" << "$x" << "$y" << "z" << "m" << "num_points"
<< "point_n" << "start_point" << "end_point" << "make_point" << "make_point_m"
<< "$x_at" << "x_at" << "xat" << "$y_at" << "y_at" << "yat" << "x_min" << "xmin" << "x_max" << "xmax"
<< "y_min" << "ymin" << "y_max" << "ymax" << "geom_from_wkt" << "geomFromWKT"
<< "geom_from_gml" << "geomFromGML" << "intersects_bbox" << "bbox"
Expand Down Expand Up @@ -2308,10 +2367,13 @@ const QList<QgsExpression::Function*>& QgsExpression::Functions()
<< new StaticFunction( "$y", 0, fcnY, "GeometryGroup", QString(), true )
<< new StaticFunction( "x", 1, fcnGeomX, "GeometryGroup" )
<< new StaticFunction( "y", 1, fcnGeomY, "GeometryGroup" )
<< new StaticFunction( "z", 1, fcnGeomZ, "GeometryGroup" )
<< new StaticFunction( "m", 1, fcnGeomM, "GeometryGroup" )
<< new StaticFunction( "point_n", 2, fcnPointN, "GeometryGroup" )
<< new StaticFunction( "start_point", 1, fcnStartPoint, "GeometryGroup" )
<< new StaticFunction( "end_point", 1, fcnEndPoint, "GeometryGroup" )
<< new StaticFunction( "make_point", 2, fcnMakePoint, "GeometryGroup" )
<< new StaticFunction( "make_point", -1, fcnMakePoint, "GeometryGroup" )
<< new StaticFunction( "make_point_m", 3, fcnMakePointM, "GeometryGroup" )
<< new StaticFunction( "$x_at", 1, fcnXat, "GeometryGroup", QString(), true, QStringList(), false, QStringList() << "xat" << "x_at" )
<< new StaticFunction( "$y_at", 1, fcnYat, "GeometryGroup", QString(), true, QStringList(), false, QStringList() << "yat" << "y_at" )
<< new StaticFunction( "x_min", 1, fcnXMin, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "xmin" )
Expand Down
25 changes: 17 additions & 8 deletions tests/src/core/testqgsexpression.cpp
Expand Up @@ -122,7 +122,7 @@ class TestQgsExpression: public QObject
QTest::newRow( "invalid binary operator" ) << "1+" << false;
QTest::newRow( "invalid function no params" ) << "cos" << false;
QTest::newRow( "invalid function not known" ) << "coz(1)" << false;
QTest::newRow( "invalid operator IN" ) << "n in m" << false;
QTest::newRow( "invalid operator IN" ) << "n in p" << false;
QTest::newRow( "empty node list" ) << "1 in ()" << false;
QTest::newRow( "invalid sqrt params" ) << "sqrt(2,4)" << false;
QTest::newRow( "special column as function" ) << "$id()" << false;
Expand All @@ -145,16 +145,16 @@ class TestQgsExpression: public QObject
QTest::newRow( "arithmetics" ) << "1+2*3" << true;
QTest::newRow( "logic" ) << "be or not be" << true;

QTest::newRow( "conditions +1" ) << "case when n then m end" << true;
QTest::newRow( "conditions +2" ) << "case when n then m else o end" << true;
QTest::newRow( "conditions +3" ) << "case when n then m when a then b end" << true;
QTest::newRow( "conditions +4" ) << "case when n then ym when a then b else z end" << true;
QTest::newRow( "conditions +1" ) << "case when n then p end" << true;
QTest::newRow( "conditions +2" ) << "case when n then p else o end" << true;
QTest::newRow( "conditions +3" ) << "case when n then p when a then b end" << true;
QTest::newRow( "conditions +4" ) << "case when n then ym when a then b else p end" << true;

QTest::newRow( "conditions -1" ) << "case end" << false;
QTest::newRow( "conditions -2" ) << "when n then m" << false;
QTest::newRow( "conditions -2" ) << "when n then p" << false;
QTest::newRow( "conditions -3" ) << "case" << false;
QTest::newRow( "conditions -4" ) << "case when n m end" << false;
QTest::newRow( "conditions -5" ) << "case m end" << false;
QTest::newRow( "conditions -4" ) << "case when n p end" << false;
QTest::newRow( "conditions -5" ) << "case p end" << false;
}
void parsing()
{
Expand Down Expand Up @@ -443,8 +443,17 @@ class TestQgsExpression: public QObject
QTest::newRow( "end_point line" ) << "geom_to_wkt(end_point(geom_from_wkt('LINESTRING(4 1, 1 1, 2 2)')))" << false << QVariant( "Point (2 2)" );
QTest::newRow( "end_point polygon" ) << "geom_to_wkt(end_point(geom_from_wkt('POLYGON((-1 -1, 4 0, 4 2, 0 2, -1 -1))')))" << false << QVariant( "Point (-1 -1)" );
QTest::newRow( "make_point" ) << "geom_to_wkt(make_point(2.2,4.4))" << false << QVariant( "Point (2.2 4.4)" );
QTest::newRow( "make_point z" ) << "geom_to_wkt(make_point(2.2,4.4,5.5))" << false << QVariant( "PointZ (2.2 4.4 5.5)" );
QTest::newRow( "make_point zm" ) << "geom_to_wkt(make_point(2.2,4.4,5.5,6.6))" << false << QVariant( "PointZM (2.2 4.4 5.5 6.6)" );
QTest::newRow( "make_point bad" ) << "make_point(2.2)" << true << QVariant();
QTest::newRow( "make_point bad 2" ) << "make_point(2.2, 3, 3, 3, 3)" << true << QVariant();
QTest::newRow( "make_point_m" ) << "geom_to_wkt(make_point_m(2.2,4.4,5.5))" << false << QVariant( "PointM (2.2 4.4 5.5)" );
QTest::newRow( "x point" ) << "x(make_point(2.2,4.4))" << false << QVariant( 2.2 );
QTest::newRow( "y point" ) << "y(make_point(2.2,4.4))" << false << QVariant( 4.4 );
QTest::newRow( "z point" ) << "z(make_point(2.2,4.4,6.6))" << false << QVariant( 6.6 );
QTest::newRow( "z not point" ) << "z(geom_from_wkt('LINESTRING(2 0,2 2, 3 2, 3 0)'))" << false << QVariant();
QTest::newRow( "m point" ) << "m(make_point_m(2.2,4.4,7.7))" << false << QVariant( 7.7 );
QTest::newRow( "m not point" ) << "m(geom_from_wkt('LINESTRING(2 0,2 2, 3 2, 3 0)'))" << false << QVariant();
QTest::newRow( "x line" ) << "x(geom_from_wkt('LINESTRING(2 0,2 2, 3 2, 3 0)'))" << false << QVariant( 2.5 );
QTest::newRow( "x line" ) << "y(geom_from_wkt('LINESTRING(2 0,2 2, 3 2, 3 0)'))" << false << QVariant( 1.2 );
QTest::newRow( "x polygon" ) << "x(geom_from_wkt('POLYGON((2 0,2 2, 3 2, 3 0, 2 0))'))" << false << QVariant( 2.5 );
Expand Down

0 comments on commit 12e34f2

Please sign in to comment.