Skip to content

Commit 12e34f2

Browse files
committedNov 6, 2015
[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.
1 parent 7439643 commit 12e34f2

File tree

6 files changed

+118
-16
lines changed

6 files changed

+118
-16
lines changed
 

‎resources/function_help/json/m

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"name": "m",
3+
"type": "function",
4+
"description": "Returns the m value of a point geometry.",
5+
"arguments": [ {"arg":"geom","description":"a point geometry"}],
6+
"examples": [ { "expression":"m( geom_from_wkt( 'POINTM(2 5 4)' ) )", "returns":"4"}
7+
]
8+
}
Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
{
22
"name": "make_point",
33
"type": "function",
4-
"description": "Creates a point geometry from an x and y value.",
4+
"description": "Creates a point geometry from an x and y (and optional z and m) value.",
55
"arguments": [
66
{"arg":"x","description":"x coordinate of point"},
7-
{"arg":"y","description":"y coordinate of point"} ],
8-
"examples": [ { "expression":"geom_to_wkt(make_point(2,4))", "returns":"'Point (2 4)'"}]
7+
{"arg":"y","description":"y coordinate of point"},
8+
{"arg":"z","description":"optional z coordinate of point"},
9+
{"arg":"m","description":"optional m value of point"} ],
10+
"examples": [ { "expression":"geom_to_wkt(make_point(2,4))", "returns":"'Point (2 4)'"},
11+
{ "expression":"geom_to_wkt(make_point(2,4,6))", "returns":"'PointZ (2 4 6)'"},
12+
{ "expression":"geom_to_wkt(make_point(2,4,6,8))", "returns":"'PointZM (2 4 6 8)'"}
13+
]
914
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "make_point_m",
3+
"type": "function",
4+
"description": "Creates a point geometry from an x, y coordinate and m value.",
5+
"arguments": [
6+
{"arg":"x","description":"x coordinate of point"},
7+
{"arg":"y","description":"y coordinate of point"},
8+
{"arg":"m","description":"m value of point"} ],
9+
"examples": [ { "expression":"geom_to_wkt(make_point_m(2,4,6))", "returns":"'PointM (2 4 6)'"} ]
10+
}

‎resources/function_help/json/z

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"name": "z",
3+
"type": "function",
4+
"description": "Returns the z coordinate of a point geometry.",
5+
"arguments": [ {"arg":"geom","description":"a point geometry"}],
6+
"examples": [ { "expression":"z( geom_from_wkt( 'POINTZ(2 5 7)' ) )", "returns":"7"}
7+
]
8+
}

‎src/core/qgsexpression.cpp

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1258,6 +1258,40 @@ static QVariant fcnGeomY( const QVariantList& values, const QgsExpressionContext
12581258
return result;
12591259
}
12601260

1261+
static QVariant fcnGeomZ( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1262+
{
1263+
QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1264+
if ( geom.isEmpty() )
1265+
return QVariant(); //or 0?
1266+
1267+
//if single point, return the point's z coordinate
1268+
if ( geom.type() == QGis::Point && !geom.isMultipart() )
1269+
{
1270+
QgsPointV2* point = dynamic_cast< QgsPointV2* >( geom.geometry() );
1271+
if ( point )
1272+
return point->z();
1273+
}
1274+
1275+
return QVariant();
1276+
}
1277+
1278+
static QVariant fcnGeomM( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1279+
{
1280+
QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1281+
if ( geom.isEmpty() )
1282+
return QVariant(); //or 0?
1283+
1284+
//if single point, return the point's m value
1285+
if ( geom.type() == QGis::Point && !geom.isMultipart() )
1286+
{
1287+
QgsPointV2* point = dynamic_cast< QgsPointV2* >( geom.geometry() );
1288+
if ( point )
1289+
return point->m();
1290+
}
1291+
1292+
return QVariant();
1293+
}
1294+
12611295
static QVariant fcnPointN( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
12621296
{
12631297
QgsGeometry geom = getGeometry( values.at( 0 ), parent );
@@ -1314,10 +1348,35 @@ static QVariant fcnEndPoint( const QVariantList& values, const QgsExpressionCont
13141348
}
13151349

13161350
static QVariant fcnMakePoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1351+
{
1352+
if ( values.count() < 2 || values.count() > 4 )
1353+
{
1354+
parent->setEvalErrorString( QObject::tr( "Function make_point requires 2-4 arguments" ) );
1355+
return QVariant();
1356+
}
1357+
1358+
double x = getDoubleValue( values.at( 0 ), parent );
1359+
double y = getDoubleValue( values.at( 1 ), parent );
1360+
double z = values.count() >= 3 ? getDoubleValue( values.at( 2 ), parent ) : 0.0;
1361+
double m = values.count() >= 4 ? getDoubleValue( values.at( 3 ), parent ) : 0.0;
1362+
switch ( values.count() )
1363+
{
1364+
case 2:
1365+
return QVariant::fromValue( QgsGeometry( new QgsPointV2( x, y ) ) );
1366+
case 3:
1367+
return QVariant::fromValue( QgsGeometry( new QgsPointV2( QgsWKBTypes::PointZ, x, y, z ) ) );
1368+
case 4:
1369+
return QVariant::fromValue( QgsGeometry( new QgsPointV2( QgsWKBTypes::PointZM, x, y, z, m ) ) );
1370+
}
1371+
return QVariant(); //avoid warning
1372+
}
1373+
1374+
static QVariant fcnMakePointM( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
13171375
{
13181376
double x = getDoubleValue( values.at( 0 ), parent );
13191377
double y = getDoubleValue( values.at( 1 ), parent );
1320-
return QVariant::fromValue( QgsGeometry( new QgsPointV2( x, y ) ) );
1378+
double m = getDoubleValue( values.at( 2 ), parent );
1379+
return QVariant::fromValue( QgsGeometry( new QgsPointV2( QgsWKBTypes::PointM, x, y, 0.0, m ) ) );
13211380
}
13221381

13231382
static QVariant pointAt( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent ) // helper function
@@ -2034,7 +2093,7 @@ static QVariant fcnGetFeature( const QVariantList& values, const QgsExpressionCo
20342093
const QVariant& attVal = values.at( 2 );
20352094
QgsFeatureRequest req;
20362095
req.setFilterExpression( QString( "%1=%2" ).arg( QgsExpression::quotedColumnRef( attribute ),
2037-
QgsExpression::quotedString( attVal.toString() ) ) );
2096+
QgsExpression::quotedString( attVal.toString() ) ) );
20382097
if ( !parent->needsGeometry() )
20392098
{
20402099
req.setFlags( QgsFeatureRequest::NoGeometry );
@@ -2192,8 +2251,8 @@ const QStringList& QgsExpression::BuiltinFunctions()
21922251
<< "color_hsl" << "color_hsla" << "color_hsv" << "color_hsva"
21932252
<< "color_cmyk" << "color_cmyka" << "color_part" << "set_color_part"
21942253
<< "xat" << "yat" << "$area" << "area" << "perimeter"
2195-
<< "$length" << "$perimeter" << "x" << "y" << "$x" << "$y" << "num_points"
2196-
<< "point_n" << "start_point" << "end_point" << "make_point"
2254+
<< "$length" << "$perimeter" << "x" << "y" << "$x" << "$y" << "z" << "m" << "num_points"
2255+
<< "point_n" << "start_point" << "end_point" << "make_point" << "make_point_m"
21972256
<< "$x_at" << "x_at" << "xat" << "$y_at" << "y_at" << "yat" << "x_min" << "xmin" << "x_max" << "xmax"
21982257
<< "y_min" << "ymin" << "y_max" << "ymax" << "geom_from_wkt" << "geomFromWKT"
21992258
<< "geom_from_gml" << "geomFromGML" << "intersects_bbox" << "bbox"
@@ -2308,10 +2367,13 @@ const QList<QgsExpression::Function*>& QgsExpression::Functions()
23082367
<< new StaticFunction( "$y", 0, fcnY, "GeometryGroup", QString(), true )
23092368
<< new StaticFunction( "x", 1, fcnGeomX, "GeometryGroup" )
23102369
<< new StaticFunction( "y", 1, fcnGeomY, "GeometryGroup" )
2370+
<< new StaticFunction( "z", 1, fcnGeomZ, "GeometryGroup" )
2371+
<< new StaticFunction( "m", 1, fcnGeomM, "GeometryGroup" )
23112372
<< new StaticFunction( "point_n", 2, fcnPointN, "GeometryGroup" )
23122373
<< new StaticFunction( "start_point", 1, fcnStartPoint, "GeometryGroup" )
23132374
<< new StaticFunction( "end_point", 1, fcnEndPoint, "GeometryGroup" )
2314-
<< new StaticFunction( "make_point", 2, fcnMakePoint, "GeometryGroup" )
2375+
<< new StaticFunction( "make_point", -1, fcnMakePoint, "GeometryGroup" )
2376+
<< new StaticFunction( "make_point_m", 3, fcnMakePointM, "GeometryGroup" )
23152377
<< new StaticFunction( "$x_at", 1, fcnXat, "GeometryGroup", QString(), true, QStringList(), false, QStringList() << "xat" << "x_at" )
23162378
<< new StaticFunction( "$y_at", 1, fcnYat, "GeometryGroup", QString(), true, QStringList(), false, QStringList() << "yat" << "y_at" )
23172379
<< new StaticFunction( "x_min", 1, fcnXMin, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "xmin" )

‎tests/src/core/testqgsexpression.cpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ class TestQgsExpression: public QObject
122122
QTest::newRow( "invalid binary operator" ) << "1+" << false;
123123
QTest::newRow( "invalid function no params" ) << "cos" << false;
124124
QTest::newRow( "invalid function not known" ) << "coz(1)" << false;
125-
QTest::newRow( "invalid operator IN" ) << "n in m" << false;
125+
QTest::newRow( "invalid operator IN" ) << "n in p" << false;
126126
QTest::newRow( "empty node list" ) << "1 in ()" << false;
127127
QTest::newRow( "invalid sqrt params" ) << "sqrt(2,4)" << false;
128128
QTest::newRow( "special column as function" ) << "$id()" << false;
@@ -145,16 +145,16 @@ class TestQgsExpression: public QObject
145145
QTest::newRow( "arithmetics" ) << "1+2*3" << true;
146146
QTest::newRow( "logic" ) << "be or not be" << true;
147147

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

153153
QTest::newRow( "conditions -1" ) << "case end" << false;
154-
QTest::newRow( "conditions -2" ) << "when n then m" << false;
154+
QTest::newRow( "conditions -2" ) << "when n then p" << false;
155155
QTest::newRow( "conditions -3" ) << "case" << false;
156-
QTest::newRow( "conditions -4" ) << "case when n m end" << false;
157-
QTest::newRow( "conditions -5" ) << "case m end" << false;
156+
QTest::newRow( "conditions -4" ) << "case when n p end" << false;
157+
QTest::newRow( "conditions -5" ) << "case p end" << false;
158158
}
159159
void parsing()
160160
{
@@ -443,8 +443,17 @@ class TestQgsExpression: public QObject
443443
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)" );
444444
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)" );
445445
QTest::newRow( "make_point" ) << "geom_to_wkt(make_point(2.2,4.4))" << false << QVariant( "Point (2.2 4.4)" );
446+
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)" );
447+
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)" );
448+
QTest::newRow( "make_point bad" ) << "make_point(2.2)" << true << QVariant();
449+
QTest::newRow( "make_point bad 2" ) << "make_point(2.2, 3, 3, 3, 3)" << true << QVariant();
450+
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)" );
446451
QTest::newRow( "x point" ) << "x(make_point(2.2,4.4))" << false << QVariant( 2.2 );
447452
QTest::newRow( "y point" ) << "y(make_point(2.2,4.4))" << false << QVariant( 4.4 );
453+
QTest::newRow( "z point" ) << "z(make_point(2.2,4.4,6.6))" << false << QVariant( 6.6 );
454+
QTest::newRow( "z not point" ) << "z(geom_from_wkt('LINESTRING(2 0,2 2, 3 2, 3 0)'))" << false << QVariant();
455+
QTest::newRow( "m point" ) << "m(make_point_m(2.2,4.4,7.7))" << false << QVariant( 7.7 );
456+
QTest::newRow( "m not point" ) << "m(geom_from_wkt('LINESTRING(2 0,2 2, 3 2, 3 0)'))" << false << QVariant();
448457
QTest::newRow( "x line" ) << "x(geom_from_wkt('LINESTRING(2 0,2 2, 3 2, 3 0)'))" << false << QVariant( 2.5 );
449458
QTest::newRow( "x line" ) << "y(geom_from_wkt('LINESTRING(2 0,2 2, 3 2, 3 0)'))" << false << QVariant( 1.2 );
450459
QTest::newRow( "x polygon" ) << "x(geom_from_wkt('POLYGON((2 0,2 2, 3 2, 3 0, 2 0))'))" << false << QVariant( 2.5 );

0 commit comments

Comments
 (0)
Please sign in to comment.