Skip to content

Commit

Permalink
[FEATURE] Add get and transform geometry in Expression
Browse files Browse the repository at this point in the history
In version 2.6, new keywords has been added to Expression :
* $currentfeature - returns the current feature
* $atlasfeature - returns the atlas feature
* getFeature - gets a matching feature from a layer

But I think, Expression lacks a few keywords :
* geometry - returns the feature's geometry
* transform -  returns the transformed geometry

These new keywords can be used with getFeature for some geometry tests like
 intersects, crosses, contains, etc

Tests has been added to geometry and transform in Expression
  • Loading branch information
rldhont committed Jan 2, 2015
1 parent 2b7e49b commit a0ffad2
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 2 deletions.
12 changes: 12 additions & 0 deletions resources/function_help/geometry
@@ -0,0 +1,12 @@
<h3>getGeometry function</h3>
Returns the feature's geometry

<h4>Syntax</h4>
<pre>geometry( f )</pre>

<h4>Arguments</h4>
f &rarr; QgsFeature

<h4>Example</h4>
<pre> geomToWKT( geometry( getFeature( layer, attributeField, value ) ) ) &rarr; POINT(6 50)</pre>
<pre> intersects( $geometry, geometry( getFeature( layer, attributeField, value ) ) ) &rarr; 1</pre>
15 changes: 15 additions & 0 deletions resources/function_help/transform
@@ -0,0 +1,15 @@
<h3>transformGeometry function</h3>
Returns the geometry transforms from the source CRS to the dest CRS.

<h4>Syntax</h4>
<pre>transform( geom, sAuthId, dAuthId )</pre>

<h4>Arguments</h4>
geom &rarr; QgsGeometry

sCrsId &rarr; the Source Auth CRS Id

dCrsId &rarr; the Dest Auth CRS Id

<h4>Example</h4>
<pre> geomToWKT( transform( $geometry, 'EPSG:2154', 'EPSG:4326' ) ) &rarr; POINT(0 51)</pre>
40 changes: 38 additions & 2 deletions src/core/qgsexpression.cpp
Expand Up @@ -1298,8 +1298,14 @@ static QVariant fcnCombine( const QVariantList& values, const QgsFeature*, QgsEx
}
static QVariant fcnGeomToWKT( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
{
if ( values.length() < 1 || values.length() > 2 )
return QVariant();

QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
QString wkt = fGeom.exportToWkt();
int prec = 8;
if ( values.length() == 2 )
prec = getIntValue( values.at( 1 ), parent );
QString wkt = fGeom.exportToWkt( prec );
return QVariant( wkt );
}

Expand Down Expand Up @@ -1546,6 +1552,34 @@ static QVariant fcnSpecialColumn( const QVariantList& values, const QgsFeature*
return QgsExpression::specialColumn( varName );
}

static QVariant fcnGetGeometry( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
{
QgsFeature feat = getFeature( values.at( 0 ), parent );
QgsGeometry* geom = feat.geometry();
if ( geom )
return QVariant::fromValue( *geom );
return QVariant();
}

static QVariant fcnTransformGeometry( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
{
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
QString sAuthId = getStringValue( values.at( 1 ), parent );
QString dAuthId = getStringValue( values.at( 2 ), parent );

QgsCoordinateReferenceSystem s;
if ( ! s.createFromOgcWmsCrs( sAuthId ) )
return QVariant::fromValue( fGeom );
QgsCoordinateReferenceSystem d;
if ( ! d.createFromOgcWmsCrs( dAuthId ) )
return QVariant::fromValue( fGeom );

QgsCoordinateTransform t( s, d );
if ( fGeom.transform( t ) == 0 )
return QVariant::fromValue( fGeom );
return QVariant();
}

static QVariant fcnGetFeature( const QVariantList& values, const QgsFeature *, QgsExpression* parent )
{
//arguments: 1. layer id / name, 2. key attribute, 3. eq value
Expand Down Expand Up @@ -1765,7 +1799,9 @@ const QList<QgsExpression::Function*> &QgsExpression::Functions()
<< new StaticFunction( "symDifference", 2, fcnSymDifference, "Geometry" )
<< new StaticFunction( "combine", 2, fcnCombine, "Geometry" )
<< new StaticFunction( "union", 2, fcnCombine, "Geometry" )
<< new StaticFunction( "geomToWKT", 1, fcnGeomToWKT, "Geometry" )
<< new StaticFunction( "geomToWKT", -1, fcnGeomToWKT, "Geometry" )
<< new StaticFunction( "geometry", 1, fcnGetGeometry, "Geometry" )
<< new StaticFunction( "transform", 3, fcnTransformGeometry, "Geometry" )
<< new StaticFunction( "$rownum", 0, fcnRowNumber, "Record" )
<< new StaticFunction( "$id", 0, fcnFeatureId, "Record" )
<< new StaticFunction( "$currentfeature", 0, fcnFeature, "Record" )
Expand Down
89 changes: 89 additions & 0 deletions tests/src/core/testqgsexpression.cpp
Expand Up @@ -745,6 +745,37 @@ class TestQgsExpression: public QObject
QVariant vYMax = exp9.evaluate( &fPolygon );
QCOMPARE( vYMax.toDouble(), 6.0 );
}

void eval_geometry_wkt()
{
QgsPolyline polyline, polygon_ring;
polyline << QgsPoint( 0, 0 ) << QgsPoint( 10, 0 );
polygon_ring << QgsPoint( 2, 1 ) << QgsPoint( 10, 1 ) << QgsPoint( 10, 6 ) << QgsPoint( 2, 6 ) << QgsPoint( 2, 1 );

QgsPolygon polygon;
polygon << polygon_ring;

QgsFeature fPoint, fPolygon, fPolyline;
fPoint.setGeometry( QgsGeometry::fromPoint( QgsPoint( -1.23456789, 9.87654321 ) ) );
fPolyline.setGeometry( QgsGeometry::fromPolyline( polyline ) );
fPolygon.setGeometry( QgsGeometry::fromPolygon( polygon ) );

QgsExpression exp1( "geomToWKT($geometry)" );
QVariant vWktLine = exp1.evaluate( &fPolyline );
QCOMPARE( vWktLine.toString(), QString( "LINESTRING(0 0, 10 0)" ) );

QgsExpression exp2( "geomToWKT($geometry)" );
QVariant vWktPolygon = exp2.evaluate( &fPolygon );
QCOMPARE( vWktPolygon.toString(), QString( "POLYGON((2 1,10 1,10 6,2 6,2 1))" ) );

QgsExpression exp3( "geomToWKT($geometry)" );
QVariant vWktPoint = exp3.evaluate( &fPoint );
QCOMPARE( vWktPoint.toString(), QString( "POINT(-1.23456789 9.87654321)" ) );

QgsExpression exp4( "geomToWKT($geometry, 3)" );
QVariant vWktPointSimplify = exp4.evaluate( &fPoint );
QCOMPARE( vWktPointSimplify.toString(), QString( "POINT(-1.235 9.877)" ) );
}

void eval_geometry_constructor_data()
{
Expand Down Expand Up @@ -803,6 +834,64 @@ class TestQgsExpression: public QObject
QgsGeometry outGeom = out.value<QgsGeometry>();
QCOMPARE( geom->equals( &outGeom ), true );
}

void eval_geometry_access_transform_data()
{
QTest::addColumn<QString>( "string" );
QTest::addColumn<void*>( "geomptr" );
QTest::addColumn<bool>( "evalError" );

QgsPoint point( 123, 456 );
QgsPolyline line;
line << QgsPoint( 1, 1 ) << QgsPoint( 4, 2 ) << QgsPoint( 3, 1 );

QgsPolyline polyline, polygon_ring;
polyline << QgsPoint( 0, 0 ) << QgsPoint( 10, 0 );
polygon_ring << QgsPoint( 1, 1 ) << QgsPoint( 6, 1 ) << QgsPoint( 6, 6 ) << QgsPoint( 1, 6 ) << QgsPoint( 1, 1 );
QgsPolygon polygon;
polygon << polygon_ring;

QTest::newRow( "geometry Point" ) << "geometry( $currentfeature )" << ( void* ) QgsGeometry::fromPoint( point ) << false;
QTest::newRow( "geometry Line" ) << "geometry( $currentfeature )" << ( void* ) QgsGeometry::fromPolyline( line ) << false;
QTest::newRow( "geometry Polyline" ) << "geometry( $currentfeature )" << ( void* ) QgsGeometry::fromPolyline( polyline ) << false;
QTest::newRow( "geometry Polygon" ) << "geometry( $currentfeature )" << ( void* ) QgsGeometry::fromPolygon( polygon ) << false;

QgsCoordinateReferenceSystem s;
s.createFromOgcWmsCrs( "EPSG:4326" );
QgsCoordinateReferenceSystem d;
d.createFromOgcWmsCrs( "EPSG:3857" );
QgsCoordinateTransform t( s, d );

QgsGeometry* tLine = QgsGeometry::fromPolyline( line );
tLine->transform( t );
QgsGeometry* tPolygon = QgsGeometry::fromPolygon( polygon );
tPolygon->transform( t );

QTest::newRow( "transform Line" ) << "transform( geomFromWKT('" + QgsGeometry::fromPolyline( line )->exportToWkt() + "'), 'EPSG:4326', 'EPSG:3857' )" << ( void* ) tLine << false;
QTest::newRow( "transform Polygon" ) << "transform( geomFromWKT('" + QgsGeometry::fromPolygon( polygon )->exportToWkt() + "'), 'EPSG:4326', 'EPSG:3857' )" << ( void* ) tPolygon << false;
}

void eval_geometry_access_transform()
{
QFETCH( QString, string );
QFETCH( void*, geomptr );
QFETCH( bool, evalError );

QgsGeometry* geom = ( QgsGeometry* ) geomptr;

QgsFeature f;
f.setGeometry( geom );

QgsExpression exp( string );
QCOMPARE( exp.hasParserError(), false );
QCOMPARE( exp.needsGeometry(), false );
QVariant out = exp.evaluate( &f );
QCOMPARE( exp.hasEvalError(), evalError );

QCOMPARE( out.canConvert<QgsGeometry>(), true );
QgsGeometry outGeom = out.value<QgsGeometry>();
QCOMPARE( geom->equals( &outGeom ), true );
}

void eval_spatial_operator_data()
{
Expand Down

0 comments on commit a0ffad2

Please sign in to comment.