Skip to content

Commit

Permalink
Add geometric method
Browse files Browse the repository at this point in the history
  • Loading branch information
rldhont committed Nov 14, 2012
1 parent 20d57b9 commit a3289e8
Show file tree
Hide file tree
Showing 3 changed files with 195 additions and 51 deletions.
167 changes: 120 additions & 47 deletions src/core/qgsexpression.cpp
Expand Up @@ -329,14 +329,13 @@ static QgsExpression::Interval getInterval( const QVariant& value, QgsExpression

return QgsExpression::Interval::invalidInterVal();
}

static QgsGeometry* getGeometry( const QVariant& value, QgsExpression* parent)
static QgsGeometry getGeometry( const QVariant& value, QgsExpression* parent)
{
if ( value.canConvert<QgsGeometry*>() )
return value.value<QgsGeometry*>();
if ( value.canConvert<QgsGeometry>() )
return value.value<QgsGeometry>();

parent->setEvalErrorString( "Cannot convert to QgsGeometry" );
return 0;
return QgsGeometry();
}


Expand Down Expand Up @@ -770,7 +769,7 @@ static QVariant fcnGeometry( const QVariantList& , QgsFeature* f, QgsExpression*
{
QgsGeometry* geom = f->geometry();
if ( geom )
return QVariant::fromValue( geom );
return QVariant::fromValue( *geom );
else
return QVariant();
}
Expand All @@ -779,7 +778,7 @@ static QVariant fcnGeomFromWKT( const QVariantList& values, QgsFeature*, QgsExpr
QString wkt = getStringValue( values.at( 0 ), parent );
QgsGeometry* geom = QgsGeometry::fromWkt( wkt );
if ( geom )
return QVariant::fromValue( geom );
return QVariant::fromValue( *geom );
else
return QVariant();
}
Expand All @@ -802,7 +801,7 @@ static QVariant fcnGeomFromGML2( const QVariantList& values, QgsFeature*, QgsExp
geom = QgsGeometry::fromGML2( doc.documentElement() );

if ( geom )
return QVariant::fromValue( geom );
return QVariant::fromValue( *geom );
else
return QVariant();
}
Expand All @@ -828,68 +827,132 @@ static QVariant fcnGeomPerimeter( const QVariantList& , QgsFeature* f, QgsExpres

static QVariant fcnBbox( const QVariantList& values, QgsFeature* , QgsExpression* parent )
{
QgsGeometry* fGeom = getGeometry( values.at( 0 ), parent );
QgsGeometry* sGeom = getGeometry( values.at( 1 ), parent );
if ( fGeom && sGeom )
return fGeom->intersects( sGeom->boundingBox() ) ? TVL_True : TVL_False;
return QVariant();
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
return fGeom.intersects( sGeom.boundingBox() ) ? TVL_True : TVL_False;
}
static QVariant fcnDisjoint( const QVariantList& values, QgsFeature* , QgsExpression* parent )
{
QgsGeometry* fGeom = getGeometry( values.at( 0 ), parent );
QgsGeometry* sGeom = getGeometry( values.at( 1 ), parent );
if ( fGeom && sGeom )
return fGeom->disjoint( sGeom ) ? TVL_True : TVL_False;
return QVariant();
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
return fGeom.disjoint( &sGeom ) ? TVL_True : TVL_False;
}
static QVariant fcnIntersects( const QVariantList& values, QgsFeature* , QgsExpression* parent )
{
QgsGeometry* fGeom = getGeometry( values.at( 0 ), parent );
QgsGeometry* sGeom = getGeometry( values.at( 1 ), parent );
if ( fGeom && sGeom )
return fGeom->intersects( sGeom ) ? TVL_True : TVL_False;
return QVariant();
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
return fGeom.intersects( &sGeom ) ? TVL_True : TVL_False;
}
static QVariant fcnTouches( const QVariantList& values, QgsFeature* , QgsExpression* parent )
{
QgsGeometry* fGeom = getGeometry( values.at( 0 ), parent );
QgsGeometry* sGeom = getGeometry( values.at( 1 ), parent );
if ( fGeom && sGeom )
return fGeom->touches( sGeom ) ? TVL_True : TVL_False;
return QVariant();
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
return fGeom.touches( &sGeom ) ? TVL_True : TVL_False;
}
static QVariant fcnCrosses( const QVariantList& values, QgsFeature* , QgsExpression* parent )
{
QgsGeometry* fGeom = getGeometry( values.at( 0 ), parent );
QgsGeometry* sGeom = getGeometry( values.at( 1 ), parent );
if ( fGeom && sGeom )
return fGeom->crosses( sGeom ) ? TVL_True : TVL_False;
return QVariant();
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
return fGeom.crosses( &sGeom ) ? TVL_True : TVL_False;
}
static QVariant fcnContains( const QVariantList& values, QgsFeature* , QgsExpression* parent )
{
QgsGeometry* fGeom = getGeometry( values.at( 0 ), parent );
QgsGeometry* sGeom = getGeometry( values.at( 1 ), parent );
if ( fGeom && sGeom )
return fGeom->contains( sGeom ) ? TVL_True : TVL_False;
return QVariant();
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
return fGeom.contains( &sGeom ) ? TVL_True : TVL_False;
}
static QVariant fcnOverlaps( const QVariantList& values, QgsFeature* , QgsExpression* parent )
{
QgsGeometry* fGeom = getGeometry( values.at( 0 ), parent );
QgsGeometry* sGeom = getGeometry( values.at( 1 ), parent );
if ( fGeom && sGeom )
return fGeom->overlaps( sGeom ) ? TVL_True : TVL_False;
return QVariant();
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
return fGeom.overlaps( &sGeom ) ? TVL_True : TVL_False;
}
static QVariant fcnWithin( const QVariantList& values, QgsFeature* , QgsExpression* parent )
{
QgsGeometry* fGeom = getGeometry( values.at( 0 ), parent );
QgsGeometry* sGeom = getGeometry( values.at( 1 ), parent );
if ( fGeom && sGeom )
return fGeom->within( sGeom ) ? TVL_True : TVL_False;
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
return fGeom.within( &sGeom ) ? TVL_True : TVL_False;
}
static QVariant fcnBuffer( const QVariantList& values, QgsFeature*, QgsExpression* parent )
{
if ( values.length() < 2 || values.length() > 3 )
return QVariant();

QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
double dist = getDoubleValue( values.at( 1 ), parent );
int seg = 8;
if ( values.length() == 3 )
seg = getIntValue( values.at( 2 ), parent );

QgsGeometry* geom = fGeom.buffer( dist, seg );
if ( geom )
return QVariant::fromValue( *geom );
return QVariant();
}
static QVariant fcnCentroid( const QVariantList& values, QgsFeature*, QgsExpression* parent )
{
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
QgsGeometry* geom = fGeom.centroid();
if ( geom )
return QVariant::fromValue( *geom );
return QVariant();
}
static QVariant fcnConvexHull( const QVariantList& values, QgsFeature*, QgsExpression* parent )
{
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
QgsGeometry* geom = fGeom.convexHull();
if ( geom )
return QVariant::fromValue( *geom );
return QVariant();
}
static QVariant fcnDifference( const QVariantList& values, QgsFeature* , QgsExpression* parent )
{
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
QgsGeometry* geom = fGeom.difference( &sGeom );
if ( geom )
return QVariant::fromValue( *geom );
return QVariant();
}
static QVariant fcnDistance( const QVariantList& values, QgsFeature* , QgsExpression* parent )
{
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
return QVariant( fGeom.distance( sGeom ) );
}
static QVariant fcnIntersection( const QVariantList& values, QgsFeature* , QgsExpression* parent )
{
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
QgsGeometry* geom = fGeom.intersection( &sGeom );
if ( geom )
return QVariant::fromValue( *geom );
return QVariant();
}
static QVariant fcnSymDifference( const QVariantList& values, QgsFeature* , QgsExpression* parent )
{
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
QgsGeometry* geom = fGeom.symDifference( &sGeom );
if ( geom )
return QVariant::fromValue( *geom );
return QVariant();
}
static QVariant fcnCombine( const QVariantList& values, QgsFeature* , QgsExpression* parent )
{
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
QgsGeometry* geom = fGeom.combine( &sGeom );
if ( geom )
return QVariant::fromValue( *geom );
return QVariant();
}
static QVariant fcnGeomToWKT( const QVariantList& values, QgsFeature* , QgsExpression* parent )
{
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
QString wkt = fGeom.exportToWkt();
return QVariant( wkt );
}

static QVariant fcnRound( const QVariantList& values , QgsFeature *f, QgsExpression* parent )
{
Expand Down Expand Up @@ -1057,6 +1120,16 @@ const QList<QgsExpression::Function*> &QgsExpression::Functions()
<< new StaticFunction( "contains", 2, fcnContains, QObject::tr( "Geometry" ) )
<< new StaticFunction( "overlaps", 2, fcnOverlaps, QObject::tr( "Geometry" ) )
<< new StaticFunction( "within", 2, fcnWithin, QObject::tr( "Geometry" ) )
<< new StaticFunction( "buffer", -1, fcnBuffer, QObject::tr( "Geometry" ) )
<< new StaticFunction( "centroid", 1, fcnCentroid, QObject::tr( "Geometry" ) )
<< new StaticFunction( "convexHull", 1, fcnConvexHull, QObject::tr( "Geometry" ) )
<< new StaticFunction( "difference", 2, fcnDifference, QObject::tr( "Geometry" ) )
<< new StaticFunction( "distance", 2, fcnDistance, QObject::tr( "Geometry" ) )
<< new StaticFunction( "intersection", 2, fcnIntersection, QObject::tr( "Geometry" ) )
<< new StaticFunction( "symDifference", 2, fcnSymDifference, QObject::tr( "Geometry" ) )
<< new StaticFunction( "combine", 2, fcnCombine, QObject::tr( "Geometry" ) )
<< new StaticFunction( "union", 2, fcnCombine, QObject::tr( "Geometry" ) )
<< new StaticFunction( "geomToWKT", 1, fcnGeomToWKT, QObject::tr( "Geometry" ) )
<< new StaticFunction( "$rownum", 0, fcnRowNumber, QObject::tr( "Record" ) )
<< new StaticFunction( "$id", 0, fcnFeatureId, QObject::tr( "Record" ) )
<< new StaticFunction( "$scale", 0, fcnScale, QObject::tr( "Record" ) )
Expand Down
4 changes: 3 additions & 1 deletion src/core/qgsexpression.h
Expand Up @@ -24,9 +24,11 @@

#include "qgsfield.h"
#include "qgsvectorlayer.h"
#include "qgsgeometry.h"

class QgsDistanceArea;
class QgsFeature;
class QgsGeometry;
class QDomElement;

/**
Expand Down Expand Up @@ -606,6 +608,6 @@ class CORE_EXPORT QgsExpression
};

Q_DECLARE_METATYPE( QgsExpression::Interval );
Q_DECLARE_METATYPE( QgsGeometry * );
Q_DECLARE_METATYPE( QgsGeometry );

#endif // QGSEXPRESSION_H
75 changes: 72 additions & 3 deletions tests/src/core/testqgsexpression.cpp
Expand Up @@ -584,9 +584,9 @@ class TestQgsExpression: public QObject
QVariant out = exp.evaluate( &f );
QCOMPARE( exp.hasEvalError(), evalError );

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

void eval_spatial_operator_data()
Expand Down Expand Up @@ -645,6 +645,75 @@ class TestQgsExpression: public QObject
QCOMPARE( out.toInt(), result.toInt() );
}

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

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

QgsGeometry* geom = QgsGeometry::fromPolygon( polygon );

QTest::newRow( "buffer" ) << "buffer( $geometry, 1.0, 3)" << ( void* ) geom << false << true << ( void* ) geom->buffer( 1.0, 3 );
geom = QgsGeometry::fromPolygon( polygon );
QTest::newRow( "buffer" ) << "buffer( $geometry, 2.0)" << ( void* ) geom << false << true << ( void* ) geom->buffer( 2.0, 8 );

QgsPoint point1( 10, 20 );
QgsPoint point2( 30, 20 );
QgsGeometry* pnt1 = QgsGeometry::fromPoint( point1 );
QgsGeometry* pnt2 = QgsGeometry::fromPoint( point2 );
QTest::newRow( "union" ) << "union( $geometry, geomFromWKT('"+pnt2->exportToWkt()+"') )" << ( void* ) pnt1 << false << true << ( void* ) pnt1->combine( pnt2 );

geom = QgsGeometry::fromPolygon( polygon );
QTest::newRow( "intersection" ) << "intersection( $geometry, geomFromWKT('POLYGON((0 0, 0 10, 10 0, 0 0))') )" << ( void* ) geom << false << true << ( void* ) QgsGeometry::fromWkt( "POLYGON ((0 0,5 5,10 0,0 0))" );
geom = QgsGeometry::fromPolygon( polygon );
QTest::newRow( "difference" ) << "difference( $geometry, geomFromWKT('POLYGON((0 0, 0 10, 10 0, 0 0))') )" << ( void* ) geom << false << true << ( void* ) QgsGeometry::fromWkt( "POLYGON ((5 5,10 10,10 0,5 5))" );
geom = QgsGeometry::fromPolygon( polygon );
QTest::newRow( "symDifference" ) << "symDifference( $geometry, geomFromWKT('POLYGON((0 0, 0 10, 10 0, 0 0))') )" << ( void* ) geom << false << true << ( void* ) QgsGeometry::fromWkt( "MULTIPOLYGON(((5 5,0 0,0 10,5 5)),((5 5,10 10,10 0,5 5)))" );

geom = QgsGeometry::fromPolygon( polygon );
QTest::newRow( "centroid polygon" ) << "centroid( $geometry )" << ( void* ) geom << false << true << ( void* ) geom->centroid();
geom = QgsGeometry::fromPolygon( polygon );
QTest::newRow( "centroid self intersecting polygon" ) << "centroid( geomFromWKT('POLYGON((0 0, 0 2, 2 -0.1, 2 2.1, 0 0))') )" << ( void* ) geom << false << false << ( void* ) QgsGeometry::fromWkt( "POINT (8.0 1.0)" );
geom = QgsGeometry::fromPolygon( polygon );
QTest::newRow( "centroid multi polygon" ) << "centroid( geomFromWKT('MULTIPOLYGON(((0 0,0 1,1 1,1 0,0 0)),((2 0,2 1,3 1,3 0,2 0)))') )" << ( void* ) geom << false << false << ( void* ) QgsGeometry::fromWkt( "POINT (1.5 0.5)" );
geom = QgsGeometry::fromPolygon( polygon );
QTest::newRow( "convexHull simple" ) << "convexHull( $geometry )" << ( void* ) geom << false << true << ( void* ) geom->convexHull();
geom = QgsGeometry::fromPolygon( polygon );
QTest::newRow( "convexHull multi" ) << "convexHull( geomFromWKT('GEOMETRYCOLLECTION(POINT(0 1), POINT(0 0), POINT(1 0), POINT(1 1))') )" << ( void* ) geom << false << false << ( void* ) QgsGeometry::fromWkt( "POLYGON ((0 0,0 1,1 1,1 0,0 0))" );
}

void eval_geometry_method()
{
QFETCH( QString, string );
QFETCH( void*, geomptr );
QFETCH( bool, evalError );
QFETCH( bool, needGeom );
QFETCH( void*, resultptr );

QgsGeometry* geom = ( QgsGeometry* ) geomptr;
QgsGeometry* result = ( QgsGeometry* ) resultptr;

QgsFeature f;
f.setGeometry( geom );

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

QCOMPARE( out.canConvert<QgsGeometry>(), true );
QgsGeometry outGeom = out.value<QgsGeometry>();
QCOMPARE( outGeom.exportToWkt(), result->exportToWkt() );
}

void eval_special_columns()
{
QTest::addColumn<QString>( "string" );
Expand Down

0 comments on commit a3289e8

Please sign in to comment.