Skip to content

Commit

Permalink
[expressions] Add make_line and make_polygon functions
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Nov 6, 2015
1 parent fccf54b commit de15403
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 0 deletions.
13 changes: 13 additions & 0 deletions resources/function_help/json/make_line
@@ -0,0 +1,13 @@
{
"name": "make_line",
"type": "function",
"description": "Creates a line geometry from a series of point geometries.",
"variableLenArguments": true,
"arguments": [
{"arg":"point1", "syntaxOnly": true},
{"arg":"point2", "syntaxOnly": true},
{"arg":"point", "descOnly": true, "description":"a point geometry"}],
"examples": [ { "expression":"geom_to_wkt(make_line(make_point(2,4),make_point(3,5)))", "returns":"'LineString (2 4, 3 5)'"},
{ "expression":"geom_to_wkt(make_line(make_point(2,4),make_point(3,5),make_point(9,7)))", "returns":"'LineString (2 4, 3 5, 9 7)'"}
]
}
14 changes: 14 additions & 0 deletions resources/function_help/json/make_polygon
@@ -0,0 +1,14 @@
{
"name": "make_polygon",
"type": "function",
"description": "Creates a polygon geometry from an outer ring and optional series of inner ring geometries.",
"variableLenArguments": true,
"arguments": [
{"arg":"outerRing", "description": "closed line geometry for polygon's outer ring"},
{"arg":"innerRing1", "syntaxOnly": true},
{"arg":"innerRing2", "syntaxOnly": true},
{"arg":"innerRing", "descOnly": true, "description":"optional closed line geometry for inner ring"}],
"examples": [ { "expression":"geom_to_wkt(make_polygon(geom_from_wkt('LINESTRING( 0 0, 0 1, 1 1, 1 0, 0 0 )')))", "returns":"'Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))'"},
{ "expression":"geom_to_wkt(make_polygon(geom_from_wkt('LINESTRING( 0 0, 0 1, 1 1, 1 0, 0 0 )'),geom_from_wkt('LINESTRING( 0.1 0.1, 0.1 0.2, 0.2 0.2, 0.2 0.1, 0.1 0.1 )'),geom_from_wkt('LINESTRING( 0.8 0.8, 0.8 0.9, 0.9 0.9, 0.9 0.8, 0.8 0.8 )')))", "returns":"'Polygon ((0 0, 0 1, 1 1, 1 0, 0 0),(0.1 0.1, 0.1 0.2, 0.2 0.2, 0.2 0.1, 0.1 0.1),(0.8 0.8, 0.8 0.9, 0.9 0.9, 0.9 0.8, 0.8 0.8))'"}
]
}
63 changes: 63 additions & 0 deletions src/core/qgsexpression.cpp
Expand Up @@ -41,6 +41,7 @@
#include "qgsstringutils.h"
#include "qgsgeometrycollectionv2.h"
#include "qgspointv2.h"
#include "qgspolygonv2.h"

#if QT_VERSION < 0x050000
#include <qtextdocument.h>
Expand Down Expand Up @@ -1379,6 +1380,65 @@ static QVariant fcnMakePointM( const QVariantList& values, const QgsExpressionCo
return QVariant::fromValue( QgsGeometry( new QgsPointV2( QgsWKBTypes::PointM, x, y, 0.0, m ) ) );
}

static QVariant fcnMakeLine( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
{
if ( values.count() < 2 )
{
return QVariant();
}

QgsLineStringV2* lineString = new QgsLineStringV2();
lineString->clear();

Q_FOREACH ( const QVariant& value, values )
{
QgsGeometry geom = getGeometry( value, parent );
if ( geom.isEmpty() )
continue;

if ( geom.type() != QGis::Point || geom.isMultipart() )
continue;

QgsPointV2* point = dynamic_cast< QgsPointV2* >( geom.geometry() );
if ( !point )
continue;

lineString->addVertex( *point );
}

return QVariant::fromValue( QgsGeometry( lineString ) );
}

static QVariant fcnMakePolygon( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
{
if ( values.count() < 1 )
{
parent->setEvalErrorString( QObject::tr( "Function make_polygon requires an argument" ) );
return QVariant();
}

QgsGeometry outerRing = getGeometry( values.at( 0 ), parent );
if ( outerRing.type() != QGis::Line || outerRing.isMultipart() || outerRing.isEmpty() )
return QVariant();

QgsPolygonV2* polygon = new QgsPolygonV2();
polygon->setExteriorRing( dynamic_cast< QgsCurveV2* >( outerRing.geometry()->clone() ) );

for ( int i = 1; i < values.count(); ++i )
{
QgsGeometry ringGeom = getGeometry( values.at( i ), parent );
if ( ringGeom.isEmpty() )
continue;

if ( ringGeom.type() != QGis::Line || ringGeom.isMultipart() || ringGeom.isEmpty() )
continue;

polygon->addInteriorRing( dynamic_cast< QgsCurveV2* >( ringGeom.geometry()->clone() ) );
}

return QVariant::fromValue( QgsGeometry( polygon ) );
}

static QVariant pointAt( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent ) // helper function
{
FEAT_FROM_CONTEXT( context, f );
Expand Down Expand Up @@ -2253,6 +2313,7 @@ const QStringList& QgsExpression::BuiltinFunctions()
<< "xat" << "yat" << "$area" << "area" << "perimeter"
<< "$length" << "$perimeter" << "x" << "y" << "$x" << "$y" << "z" << "m" << "num_points"
<< "point_n" << "start_point" << "end_point" << "make_point" << "make_point_m"
<< "make_line" << "make_polygon"
<< "$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 @@ -2374,6 +2435,8 @@ const QList<QgsExpression::Function*>& QgsExpression::Functions()
<< new StaticFunction( "end_point", 1, fcnEndPoint, "GeometryGroup" )
<< new StaticFunction( "make_point", -1, fcnMakePoint, "GeometryGroup" )
<< new StaticFunction( "make_point_m", 3, fcnMakePointM, "GeometryGroup" )
<< new StaticFunction( "make_line", -1, fcnMakeLine, "GeometryGroup" )
<< new StaticFunction( "make_polygon", -1, fcnMakePolygon, "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
8 changes: 8 additions & 0 deletions tests/src/core/testqgsexpression.cpp
Expand Up @@ -448,6 +448,14 @@ class TestQgsExpression: public QObject
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( "make_line bad" ) << "make_line(make_point(2,4))" << false << QVariant();
QTest::newRow( "make_line" ) << "geom_to_wkt(make_line(make_point(2,4),make_point(4,6)))" << false << QVariant( "LineString (2 4, 4 6)" );
QTest::newRow( "make_line" ) << "geom_to_wkt(make_line(make_point(2,4),make_point(4,6),make_point(7,9)))" << false << QVariant( "LineString (2 4, 4 6, 7 9)" );
QTest::newRow( "make_line" ) << "geom_to_wkt(make_line(make_point(2,4,1,3),make_point(4,6,9,8),make_point(7,9,3,4)))" << false << QVariant( "LineStringZM (2 4 1 3, 4 6 9 8, 7 9 3 4)" );
QTest::newRow( "make_polygon bad" ) << "make_polygon(make_point(2,4))" << false << QVariant();
QTest::newRow( "make_polygon" ) << "geom_to_wkt(make_polygon(geom_from_wkt('LINESTRING( 0 0, 0 1, 1 1, 1 0, 0 0 )')))" << false << QVariant( "Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))" );
QTest::newRow( "make_polygon rings" ) << "geom_to_wkt(make_polygon(geom_from_wkt('LINESTRING( 0 0, 0 1, 1 1, 1 0, 0 0 )'),geom_from_wkt('LINESTRING( 0.1 0.1, 0.1 0.2, 0.2 0.2, 0.2 0.1, 0.1 0.1 )'),geom_from_wkt('LINESTRING( 0.8 0.8, 0.8 0.9, 0.9 0.9, 0.9 0.8, 0.8 0.8 )')))" << false
<< QVariant( "Polygon ((0 0, 0 1, 1 1, 1 0, 0 0),(0.1 0.1, 0.1 0.2, 0.2 0.2, 0.2 0.1, 0.1 0.1),(0.8 0.8, 0.8 0.9, 0.9 0.9, 0.9 0.8, 0.8 0.8))" );
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 );
Expand Down

0 comments on commit de15403

Please sign in to comment.