Skip to content

Commit a3289e8

Browse files
committed
Add geometric method
1 parent 20d57b9 commit a3289e8

File tree

3 files changed

+195
-51
lines changed

3 files changed

+195
-51
lines changed

src/core/qgsexpression.cpp

+120-47
Original file line numberDiff line numberDiff line change
@@ -329,14 +329,13 @@ static QgsExpression::Interval getInterval( const QVariant& value, QgsExpression
329329

330330
return QgsExpression::Interval::invalidInterVal();
331331
}
332-
333-
static QgsGeometry* getGeometry( const QVariant& value, QgsExpression* parent)
332+
static QgsGeometry getGeometry( const QVariant& value, QgsExpression* parent)
334333
{
335-
if ( value.canConvert<QgsGeometry*>() )
336-
return value.value<QgsGeometry*>();
334+
if ( value.canConvert<QgsGeometry>() )
335+
return value.value<QgsGeometry>();
337336

338337
parent->setEvalErrorString( "Cannot convert to QgsGeometry" );
339-
return 0;
338+
return QgsGeometry();
340339
}
341340

342341

@@ -770,7 +769,7 @@ static QVariant fcnGeometry( const QVariantList& , QgsFeature* f, QgsExpression*
770769
{
771770
QgsGeometry* geom = f->geometry();
772771
if ( geom )
773-
return QVariant::fromValue( geom );
772+
return QVariant::fromValue( *geom );
774773
else
775774
return QVariant();
776775
}
@@ -779,7 +778,7 @@ static QVariant fcnGeomFromWKT( const QVariantList& values, QgsFeature*, QgsExpr
779778
QString wkt = getStringValue( values.at( 0 ), parent );
780779
QgsGeometry* geom = QgsGeometry::fromWkt( wkt );
781780
if ( geom )
782-
return QVariant::fromValue( geom );
781+
return QVariant::fromValue( *geom );
783782
else
784783
return QVariant();
785784
}
@@ -802,7 +801,7 @@ static QVariant fcnGeomFromGML2( const QVariantList& values, QgsFeature*, QgsExp
802801
geom = QgsGeometry::fromGML2( doc.documentElement() );
803802

804803
if ( geom )
805-
return QVariant::fromValue( geom );
804+
return QVariant::fromValue( *geom );
806805
else
807806
return QVariant();
808807
}
@@ -828,68 +827,132 @@ static QVariant fcnGeomPerimeter( const QVariantList& , QgsFeature* f, QgsExpres
828827

829828
static QVariant fcnBbox( const QVariantList& values, QgsFeature* , QgsExpression* parent )
830829
{
831-
QgsGeometry* fGeom = getGeometry( values.at( 0 ), parent );
832-
QgsGeometry* sGeom = getGeometry( values.at( 1 ), parent );
833-
if ( fGeom && sGeom )
834-
return fGeom->intersects( sGeom->boundingBox() ) ? TVL_True : TVL_False;
835-
return QVariant();
830+
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
831+
QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
832+
return fGeom.intersects( sGeom.boundingBox() ) ? TVL_True : TVL_False;
836833
}
837834
static QVariant fcnDisjoint( const QVariantList& values, QgsFeature* , QgsExpression* parent )
838835
{
839-
QgsGeometry* fGeom = getGeometry( values.at( 0 ), parent );
840-
QgsGeometry* sGeom = getGeometry( values.at( 1 ), parent );
841-
if ( fGeom && sGeom )
842-
return fGeom->disjoint( sGeom ) ? TVL_True : TVL_False;
843-
return QVariant();
836+
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
837+
QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
838+
return fGeom.disjoint( &sGeom ) ? TVL_True : TVL_False;
844839
}
845840
static QVariant fcnIntersects( const QVariantList& values, QgsFeature* , QgsExpression* parent )
846841
{
847-
QgsGeometry* fGeom = getGeometry( values.at( 0 ), parent );
848-
QgsGeometry* sGeom = getGeometry( values.at( 1 ), parent );
849-
if ( fGeom && sGeom )
850-
return fGeom->intersects( sGeom ) ? TVL_True : TVL_False;
851-
return QVariant();
842+
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
843+
QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
844+
return fGeom.intersects( &sGeom ) ? TVL_True : TVL_False;
852845
}
853846
static QVariant fcnTouches( const QVariantList& values, QgsFeature* , QgsExpression* parent )
854847
{
855-
QgsGeometry* fGeom = getGeometry( values.at( 0 ), parent );
856-
QgsGeometry* sGeom = getGeometry( values.at( 1 ), parent );
857-
if ( fGeom && sGeom )
858-
return fGeom->touches( sGeom ) ? TVL_True : TVL_False;
859-
return QVariant();
848+
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
849+
QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
850+
return fGeom.touches( &sGeom ) ? TVL_True : TVL_False;
860851
}
861852
static QVariant fcnCrosses( const QVariantList& values, QgsFeature* , QgsExpression* parent )
862853
{
863-
QgsGeometry* fGeom = getGeometry( values.at( 0 ), parent );
864-
QgsGeometry* sGeom = getGeometry( values.at( 1 ), parent );
865-
if ( fGeom && sGeom )
866-
return fGeom->crosses( sGeom ) ? TVL_True : TVL_False;
867-
return QVariant();
854+
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
855+
QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
856+
return fGeom.crosses( &sGeom ) ? TVL_True : TVL_False;
868857
}
869858
static QVariant fcnContains( const QVariantList& values, QgsFeature* , QgsExpression* parent )
870859
{
871-
QgsGeometry* fGeom = getGeometry( values.at( 0 ), parent );
872-
QgsGeometry* sGeom = getGeometry( values.at( 1 ), parent );
873-
if ( fGeom && sGeom )
874-
return fGeom->contains( sGeom ) ? TVL_True : TVL_False;
875-
return QVariant();
860+
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
861+
QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
862+
return fGeom.contains( &sGeom ) ? TVL_True : TVL_False;
876863
}
877864
static QVariant fcnOverlaps( const QVariantList& values, QgsFeature* , QgsExpression* parent )
878865
{
879-
QgsGeometry* fGeom = getGeometry( values.at( 0 ), parent );
880-
QgsGeometry* sGeom = getGeometry( values.at( 1 ), parent );
881-
if ( fGeom && sGeom )
882-
return fGeom->overlaps( sGeom ) ? TVL_True : TVL_False;
883-
return QVariant();
866+
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
867+
QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
868+
return fGeom.overlaps( &sGeom ) ? TVL_True : TVL_False;
884869
}
885870
static QVariant fcnWithin( const QVariantList& values, QgsFeature* , QgsExpression* parent )
886871
{
887-
QgsGeometry* fGeom = getGeometry( values.at( 0 ), parent );
888-
QgsGeometry* sGeom = getGeometry( values.at( 1 ), parent );
889-
if ( fGeom && sGeom )
890-
return fGeom->within( sGeom ) ? TVL_True : TVL_False;
872+
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
873+
QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
874+
return fGeom.within( &sGeom ) ? TVL_True : TVL_False;
875+
}
876+
static QVariant fcnBuffer( const QVariantList& values, QgsFeature*, QgsExpression* parent )
877+
{
878+
if ( values.length() < 2 || values.length() > 3 )
879+
return QVariant();
880+
881+
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
882+
double dist = getDoubleValue( values.at( 1 ), parent );
883+
int seg = 8;
884+
if ( values.length() == 3 )
885+
seg = getIntValue( values.at( 2 ), parent );
886+
887+
QgsGeometry* geom = fGeom.buffer( dist, seg );
888+
if ( geom )
889+
return QVariant::fromValue( *geom );
890+
return QVariant();
891+
}
892+
static QVariant fcnCentroid( const QVariantList& values, QgsFeature*, QgsExpression* parent )
893+
{
894+
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
895+
QgsGeometry* geom = fGeom.centroid();
896+
if ( geom )
897+
return QVariant::fromValue( *geom );
898+
return QVariant();
899+
}
900+
static QVariant fcnConvexHull( const QVariantList& values, QgsFeature*, QgsExpression* parent )
901+
{
902+
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
903+
QgsGeometry* geom = fGeom.convexHull();
904+
if ( geom )
905+
return QVariant::fromValue( *geom );
906+
return QVariant();
907+
}
908+
static QVariant fcnDifference( const QVariantList& values, QgsFeature* , QgsExpression* parent )
909+
{
910+
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
911+
QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
912+
QgsGeometry* geom = fGeom.difference( &sGeom );
913+
if ( geom )
914+
return QVariant::fromValue( *geom );
915+
return QVariant();
916+
}
917+
static QVariant fcnDistance( const QVariantList& values, QgsFeature* , QgsExpression* parent )
918+
{
919+
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
920+
QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
921+
return QVariant( fGeom.distance( sGeom ) );
922+
}
923+
static QVariant fcnIntersection( const QVariantList& values, QgsFeature* , QgsExpression* parent )
924+
{
925+
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
926+
QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
927+
QgsGeometry* geom = fGeom.intersection( &sGeom );
928+
if ( geom )
929+
return QVariant::fromValue( *geom );
891930
return QVariant();
892931
}
932+
static QVariant fcnSymDifference( const QVariantList& values, QgsFeature* , QgsExpression* parent )
933+
{
934+
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
935+
QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
936+
QgsGeometry* geom = fGeom.symDifference( &sGeom );
937+
if ( geom )
938+
return QVariant::fromValue( *geom );
939+
return QVariant();
940+
}
941+
static QVariant fcnCombine( const QVariantList& values, QgsFeature* , QgsExpression* parent )
942+
{
943+
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
944+
QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
945+
QgsGeometry* geom = fGeom.combine( &sGeom );
946+
if ( geom )
947+
return QVariant::fromValue( *geom );
948+
return QVariant();
949+
}
950+
static QVariant fcnGeomToWKT( const QVariantList& values, QgsFeature* , QgsExpression* parent )
951+
{
952+
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
953+
QString wkt = fGeom.exportToWkt();
954+
return QVariant( wkt );
955+
}
893956

894957
static QVariant fcnRound( const QVariantList& values , QgsFeature *f, QgsExpression* parent )
895958
{
@@ -1057,6 +1120,16 @@ const QList<QgsExpression::Function*> &QgsExpression::Functions()
10571120
<< new StaticFunction( "contains", 2, fcnContains, QObject::tr( "Geometry" ) )
10581121
<< new StaticFunction( "overlaps", 2, fcnOverlaps, QObject::tr( "Geometry" ) )
10591122
<< new StaticFunction( "within", 2, fcnWithin, QObject::tr( "Geometry" ) )
1123+
<< new StaticFunction( "buffer", -1, fcnBuffer, QObject::tr( "Geometry" ) )
1124+
<< new StaticFunction( "centroid", 1, fcnCentroid, QObject::tr( "Geometry" ) )
1125+
<< new StaticFunction( "convexHull", 1, fcnConvexHull, QObject::tr( "Geometry" ) )
1126+
<< new StaticFunction( "difference", 2, fcnDifference, QObject::tr( "Geometry" ) )
1127+
<< new StaticFunction( "distance", 2, fcnDistance, QObject::tr( "Geometry" ) )
1128+
<< new StaticFunction( "intersection", 2, fcnIntersection, QObject::tr( "Geometry" ) )
1129+
<< new StaticFunction( "symDifference", 2, fcnSymDifference, QObject::tr( "Geometry" ) )
1130+
<< new StaticFunction( "combine", 2, fcnCombine, QObject::tr( "Geometry" ) )
1131+
<< new StaticFunction( "union", 2, fcnCombine, QObject::tr( "Geometry" ) )
1132+
<< new StaticFunction( "geomToWKT", 1, fcnGeomToWKT, QObject::tr( "Geometry" ) )
10601133
<< new StaticFunction( "$rownum", 0, fcnRowNumber, QObject::tr( "Record" ) )
10611134
<< new StaticFunction( "$id", 0, fcnFeatureId, QObject::tr( "Record" ) )
10621135
<< new StaticFunction( "$scale", 0, fcnScale, QObject::tr( "Record" ) )

src/core/qgsexpression.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@
2424

2525
#include "qgsfield.h"
2626
#include "qgsvectorlayer.h"
27+
#include "qgsgeometry.h"
2728

2829
class QgsDistanceArea;
2930
class QgsFeature;
31+
class QgsGeometry;
3032
class QDomElement;
3133

3234
/**
@@ -606,6 +608,6 @@ class CORE_EXPORT QgsExpression
606608
};
607609

608610
Q_DECLARE_METATYPE( QgsExpression::Interval );
609-
Q_DECLARE_METATYPE( QgsGeometry * );
611+
Q_DECLARE_METATYPE( QgsGeometry );
610612

611613
#endif // QGSEXPRESSION_H

tests/src/core/testqgsexpression.cpp

+72-3
Original file line numberDiff line numberDiff line change
@@ -584,9 +584,9 @@ class TestQgsExpression: public QObject
584584
QVariant out = exp.evaluate( &f );
585585
QCOMPARE( exp.hasEvalError(), evalError );
586586

587-
QCOMPARE( out.canConvert<QgsGeometry*>(), true );
588-
QgsGeometry* outGeom = out.value<QgsGeometry*>();
589-
QCOMPARE( geom->equals( outGeom ), true );
587+
QCOMPARE( out.canConvert<QgsGeometry>(), true );
588+
QgsGeometry outGeom = out.value<QgsGeometry>();
589+
QCOMPARE( geom->equals( &outGeom ), true );
590590
}
591591

592592
void eval_spatial_operator_data()
@@ -645,6 +645,75 @@ class TestQgsExpression: public QObject
645645
QCOMPARE( out.toInt(), result.toInt() );
646646
}
647647

648+
void eval_geometry_method_data()
649+
{
650+
QTest::addColumn<QString>( "string" );
651+
QTest::addColumn<void*>( "geomptr" );
652+
QTest::addColumn<bool>( "evalError" );
653+
QTest::addColumn<bool>( "needGeom" );
654+
QTest::addColumn<void*>( "resultptr" );
655+
656+
QgsPolyline polygon_ring;
657+
polygon_ring << QgsPoint( 0, 0 ) << QgsPoint( 10, 10 ) << QgsPoint( 10, 0 ) << QgsPoint( 0, 0 );
658+
QgsPolygon polygon;
659+
polygon << polygon_ring;
660+
661+
QgsGeometry* geom = QgsGeometry::fromPolygon( polygon );
662+
663+
QTest::newRow( "buffer" ) << "buffer( $geometry, 1.0, 3)" << ( void* ) geom << false << true << ( void* ) geom->buffer( 1.0, 3 );
664+
geom = QgsGeometry::fromPolygon( polygon );
665+
QTest::newRow( "buffer" ) << "buffer( $geometry, 2.0)" << ( void* ) geom << false << true << ( void* ) geom->buffer( 2.0, 8 );
666+
667+
QgsPoint point1( 10, 20 );
668+
QgsPoint point2( 30, 20 );
669+
QgsGeometry* pnt1 = QgsGeometry::fromPoint( point1 );
670+
QgsGeometry* pnt2 = QgsGeometry::fromPoint( point2 );
671+
QTest::newRow( "union" ) << "union( $geometry, geomFromWKT('"+pnt2->exportToWkt()+"') )" << ( void* ) pnt1 << false << true << ( void* ) pnt1->combine( pnt2 );
672+
673+
geom = QgsGeometry::fromPolygon( polygon );
674+
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))" );
675+
geom = QgsGeometry::fromPolygon( polygon );
676+
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))" );
677+
geom = QgsGeometry::fromPolygon( polygon );
678+
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)))" );
679+
680+
geom = QgsGeometry::fromPolygon( polygon );
681+
QTest::newRow( "centroid polygon" ) << "centroid( $geometry )" << ( void* ) geom << false << true << ( void* ) geom->centroid();
682+
geom = QgsGeometry::fromPolygon( polygon );
683+
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)" );
684+
geom = QgsGeometry::fromPolygon( polygon );
685+
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)" );
686+
geom = QgsGeometry::fromPolygon( polygon );
687+
QTest::newRow( "convexHull simple" ) << "convexHull( $geometry )" << ( void* ) geom << false << true << ( void* ) geom->convexHull();
688+
geom = QgsGeometry::fromPolygon( polygon );
689+
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))" );
690+
}
691+
692+
void eval_geometry_method()
693+
{
694+
QFETCH( QString, string );
695+
QFETCH( void*, geomptr );
696+
QFETCH( bool, evalError );
697+
QFETCH( bool, needGeom );
698+
QFETCH( void*, resultptr );
699+
700+
QgsGeometry* geom = ( QgsGeometry* ) geomptr;
701+
QgsGeometry* result = ( QgsGeometry* ) resultptr;
702+
703+
QgsFeature f;
704+
f.setGeometry( geom );
705+
706+
QgsExpression exp( string );
707+
QCOMPARE( exp.hasParserError(), false );
708+
QCOMPARE( exp.needsGeometry(), needGeom );
709+
QVariant out = exp.evaluate( &f );
710+
QCOMPARE( exp.hasEvalError(), evalError );
711+
712+
QCOMPARE( out.canConvert<QgsGeometry>(), true );
713+
QgsGeometry outGeom = out.value<QgsGeometry>();
714+
QCOMPARE( outGeom.exportToWkt(), result->exportToWkt() );
715+
}
716+
648717
void eval_special_columns()
649718
{
650719
QTest::addColumn<QString>( "string" );

0 commit comments

Comments
 (0)