mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-06 00:07:29 -04:00
Add DE-9IM variant which tests against a specified pattern
(available in PyQGIS/expression engine)
This commit is contained in:
parent
9e84fcafd8
commit
da942233e7
@ -42,6 +42,16 @@ class QgsGeometryEngine
|
||||
*/
|
||||
virtual QString relate( const QgsAbstractGeometryV2& geom, QString* errorMsg = 0 ) const = 0;
|
||||
|
||||
/** Tests whether two geometries are related by a specified Dimensional Extended 9 Intersection Model (DE-9IM)
|
||||
* pattern.
|
||||
* @param geom geometry to relate to
|
||||
* @param pattern DE-9IM pattern for match
|
||||
* @param errorMsg destination storage for any error message
|
||||
* @returns true if geometry relationship matches with pattern
|
||||
* @note added in QGIS 2.14
|
||||
*/
|
||||
virtual bool relatePattern( const QgsAbstractGeometryV2& geom, const QString& pattern, QString* errorMsg = 0 ) const = 0;
|
||||
|
||||
virtual double area( QString* errorMsg = 0 ) const = 0;
|
||||
virtual double length( QString* errorMsg = 0 ) const = 0;
|
||||
virtual bool isValid( QString* errorMsg = 0 ) const = 0;
|
||||
|
@ -1,12 +1,23 @@
|
||||
{
|
||||
"name": "relate",
|
||||
"type": "function",
|
||||
"description": "Returns the Dimensional Extended 9 Intersection Model (DE-9IM) representation of the relationship between two geometries.",
|
||||
"arguments": [
|
||||
{"arg":"geometry","description":"a geometry"},
|
||||
{"arg":"geometry","description":"a geometry"}
|
||||
],
|
||||
"examples": [
|
||||
{ "expression":"relate( geom_from_wkt( 'LINESTRING(40 40,120 120)' ), geom_from_wkt( 'LINESTRING(40 40,60 120)' ) )", "returns":"'FF1F00102'"}
|
||||
]
|
||||
"description": "Tests the Dimensional Extended 9 Intersection Model (DE-9IM) representation of the relationship between two geometries.",
|
||||
"variants": [
|
||||
{ "variant": "Relationship variant",
|
||||
"variant_description": "Returns the Dimensional Extended 9 Intersection Model (DE-9IM) representation of the relationship between two geometries.",
|
||||
"arguments": [
|
||||
{"arg":"geometry","description":"a geometry"},
|
||||
{"arg":"geometry","description":"a geometry"}
|
||||
],
|
||||
"examples": [ { "expression":"relate( geom_from_wkt( 'LINESTRING(40 40,120 120)' ), geom_from_wkt( 'LINESTRING(40 40,60 120)' ) )", "returns":"'FF1F00102'" } ] },
|
||||
{
|
||||
"variant": "Pattern match variant",
|
||||
"variant_description": "Tests whether the DE-9IM relationship between two geometries matches a specified pattern.",
|
||||
"arguments": [
|
||||
{"arg":"geometry","description":"a geometry"},
|
||||
{"arg":"geometry","description":"a geometry"},
|
||||
{"arg":"pattern","description":"DE-9IM pattern to match"}
|
||||
],
|
||||
"examples": [ { "expression":"relate( geom_from_wkt( 'LINESTRING(40 40,120 120)' ), geom_from_wkt( 'LINESTRING(40 40,60 120)' ), '**1F001**' )", "returns":true}]
|
||||
}]
|
||||
}
|
||||
|
@ -69,6 +69,16 @@ class CORE_EXPORT QgsGeometryEngine
|
||||
*/
|
||||
virtual QString relate( const QgsAbstractGeometryV2& geom, QString* errorMsg = 0 ) const = 0;
|
||||
|
||||
/** Tests whether two geometries are related by a specified Dimensional Extended 9 Intersection Model (DE-9IM)
|
||||
* pattern.
|
||||
* @param geom geometry to relate to
|
||||
* @param pattern DE-9IM pattern for match
|
||||
* @param errorMsg destination storage for any error message
|
||||
* @returns true if geometry relationship matches with pattern
|
||||
* @note added in QGIS 2.14
|
||||
*/
|
||||
virtual bool relatePattern( const QgsAbstractGeometryV2& geom, const QString& pattern, QString* errorMsg = 0 ) const = 0;
|
||||
|
||||
virtual double area( QString* errorMsg = 0 ) const = 0;
|
||||
virtual double length( QString* errorMsg = 0 ) const = 0;
|
||||
virtual bool isValid( QString* errorMsg = 0 ) const = 0;
|
||||
|
@ -300,6 +300,35 @@ QString QgsGeos::relate( const QgsAbstractGeometryV2& geom, QString* errorMsg )
|
||||
return result;
|
||||
}
|
||||
|
||||
bool QgsGeos::relatePattern( const QgsAbstractGeometryV2& geom, const QString& pattern, QString* errorMsg ) const
|
||||
{
|
||||
if ( !mGeos )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
GEOSGeomScopedPtr geosGeom( asGeos( &geom, mPrecision ) );
|
||||
if ( !geosGeom )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
try
|
||||
{
|
||||
result = ( GEOSRelatePattern_r( geosinit.ctxt, mGeos, geosGeom.get(), pattern.toLocal8Bit().constData() ) == 1 );
|
||||
}
|
||||
catch ( GEOSException &e )
|
||||
{
|
||||
if ( errorMsg )
|
||||
{
|
||||
*errorMsg = e.what();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
double QgsGeos::area( QString* errorMsg ) const
|
||||
{
|
||||
double area = -1.0;
|
||||
@ -1527,7 +1556,7 @@ GEOSGeometry* QgsGeos::createGeosPoint( const QgsAbstractGeometryV2* point, int
|
||||
}
|
||||
}
|
||||
#if 0 //disabled until geos supports m-coordinates
|
||||
if (pt->isMeasure() )
|
||||
if ( pt->isMeasure() )
|
||||
{
|
||||
GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, 0, 3, pt->m() );
|
||||
}
|
||||
|
@ -62,6 +62,7 @@ class CORE_EXPORT QgsGeos: public QgsGeometryEngine
|
||||
bool contains( const QgsAbstractGeometryV2& geom, QString* errorMsg = 0 ) const override;
|
||||
bool disjoint( const QgsAbstractGeometryV2& geom, QString* errorMsg = 0 ) const override;
|
||||
QString relate( const QgsAbstractGeometryV2& geom, QString* errorMsg = 0 ) const override;
|
||||
bool relatePattern( const QgsAbstractGeometryV2& geom, const QString& pattern, QString* errorMsg = 0 ) const override;
|
||||
double area( QString* errorMsg = 0 ) const override;
|
||||
double length( QString* errorMsg = 0 ) const override;
|
||||
bool isValid( QString* errorMsg = 0 ) const override;
|
||||
|
@ -1477,17 +1477,30 @@ static QVariant fcnYMax( const QVariantList& values, const QgsExpressionContext*
|
||||
|
||||
static QVariant fcnRelate( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
|
||||
{
|
||||
if ( values.length() < 2 || values.length() > 3 )
|
||||
return QVariant();
|
||||
|
||||
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
|
||||
QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
|
||||
|
||||
if ( fGeom.isEmpty() || sGeom.isEmpty() )
|
||||
return QVariant();
|
||||
|
||||
QgsGeometryEngine* engine = QgsGeometry::createGeometryEngine( fGeom.geometry() );
|
||||
QString result = engine->relate( *sGeom.geometry() );
|
||||
delete engine;
|
||||
QScopedPointer<QgsGeometryEngine> engine( QgsGeometry::createGeometryEngine( fGeom.geometry() ) );
|
||||
|
||||
return QVariant::fromValue( result );
|
||||
if ( values.length() == 2 )
|
||||
{
|
||||
//two geometry arguments, return relation
|
||||
QString result = engine->relate( *sGeom.geometry() );
|
||||
return QVariant::fromValue( result );
|
||||
}
|
||||
else
|
||||
{
|
||||
//three arguments, test pattern
|
||||
QString pattern = getStringValue( values.at( 2 ), parent );
|
||||
bool result = engine->relatePattern( *sGeom.geometry(), pattern );
|
||||
return QVariant::fromValue( result );
|
||||
}
|
||||
}
|
||||
|
||||
static QVariant fcnBbox( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
|
||||
@ -2309,7 +2322,7 @@ const QList<QgsExpression::Function*>& QgsExpression::Functions()
|
||||
<< new StaticFunction( "y_max", 1, fcnYMax, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "ymax" )
|
||||
<< new StaticFunction( "geom_from_wkt", 1, fcnGeomFromWKT, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "geomFromWKT" )
|
||||
<< new StaticFunction( "geom_from_gml", 1, fcnGeomFromGML, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "geomFromGML" )
|
||||
<< new StaticFunction( "relate", 2, fcnRelate, "GeometryGroup" )
|
||||
<< new StaticFunction( "relate", -1, fcnRelate, "GeometryGroup" )
|
||||
<< new StaticFunction( "intersects_bbox", 2, fcnBbox, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "bbox" )
|
||||
<< new StaticFunction( "disjoint", 2, fcnDisjoint, "GeometryGroup" )
|
||||
<< new StaticFunction( "intersects", 2, fcnIntersects, "GeometryGroup" )
|
||||
|
@ -452,6 +452,8 @@ class TestQgsExpression: public QObject
|
||||
QTest::newRow( "relate valid" ) << "relate(geom_from_wkt('POINT(110 120)'),geom_from_wkt('POLYGON((60 120,60 40,160 40,160 120,60 120))'))" << false << QVariant( "F0FFFF212" );
|
||||
QTest::newRow( "relate bad 1" ) << "relate(geom_from_wkt(''),geom_from_wkt('POLYGON((60 120,60 40,160 40,160 120,60 120))'))" << false << QVariant();
|
||||
QTest::newRow( "relate bad 2" ) << "relate(geom_from_wkt('POINT(110 120)'),geom_from_wkt(''))" << false << QVariant();
|
||||
QTest::newRow( "relate pattern true" ) << "relate( geom_from_wkt( 'LINESTRING(40 40,120 120)' ), geom_from_wkt( 'LINESTRING(40 40,60 120)' ), '**1F001**' )" << false << QVariant( true );
|
||||
QTest::newRow( "relate pattern false" ) << "relate( geom_from_wkt( 'LINESTRING(40 40,120 120)' ), geom_from_wkt( 'LINESTRING(40 40,60 120)' ), '**1F002**' )" << false << QVariant( false );
|
||||
|
||||
// string functions
|
||||
QTest::newRow( "lower" ) << "lower('HeLLo')" << false << QVariant( "hello" );
|
||||
|
Loading…
x
Reference in New Issue
Block a user