Skip to content

Commit

Permalink
Add a distanceWithin method to the QgsGeometryEngine virtual class
Browse files Browse the repository at this point in the history
And use it from QgsVectorLayerFeatureIterator

References #472

The current implementation is really just a wrapper around distance()
but opens the door for future improvements
  • Loading branch information
strk authored and nyalldawson committed Sep 21, 2021
1 parent 0711166 commit acf302e
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 1 deletion.
7 changes: 7 additions & 0 deletions python/core/auto_generated/geometry/qgsgeometryengine.sip.in
Expand Up @@ -166,6 +166,13 @@ Calculate the convex hull of this.
Calculates the distance between this and ``geom``.

.. versionadded:: 3.0
%End

virtual bool distanceWithin( const QgsAbstractGeometry *geom, double maxdistance, QString *errorMsg = 0 ) const = 0;
%Docstring
Checks if ``geom`` is within ``maxdistance`` distance from this geometry

.. versionadded:: 3.22
%End

virtual bool intersects( const QgsAbstractGeometry *geom, QString *errorMsg = 0 ) const = 0;
Expand Down
7 changes: 7 additions & 0 deletions src/core/geometry/qgsgeometryengine.h
Expand Up @@ -184,6 +184,13 @@ class CORE_EXPORT QgsGeometryEngine
*/
virtual double distance( const QgsAbstractGeometry *geom, QString *errorMsg = nullptr ) const = 0;

/**
* Checks if \a geom is within \a maxdistance distance from this geometry
*
* \since QGIS 3.22
*/
virtual bool distanceWithin( const QgsAbstractGeometry *geom, double maxdistance, QString *errorMsg = nullptr ) const = 0;

/**
* Checks if \a geom intersects this.
*
Expand Down
38 changes: 38 additions & 0 deletions src/core/geometry/qgsgeos.cpp
Expand Up @@ -475,6 +475,44 @@ double QgsGeos::distance( const QgsAbstractGeometry *geom, QString *errorMsg ) c
return distance;
}

bool QgsGeos::distanceWithin( const QgsAbstractGeometry *geom, double maxdist, QString *errorMsg ) const
{
if ( !mGeos )
{
return false;
}

geos::unique_ptr otherGeosGeom( asGeos( geom, mPrecision ) );
if ( !otherGeosGeom )
{
return false;
}

// TODO: optimize implementation of this function to early-exit if
// any part of othergeosGeom is found to be within the given
// distance

double distance;
try
{
#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=9 )
if ( mGeosPrepared )
{
GEOSPreparedDistance_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeosGeom.get(), &distance );
}
else
{
GEOSDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &distance );
}
#else
GEOSDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &distance );
#endif
}
CATCH_GEOS_WITH_ERRMSG( false )

return distance <= maxdist;
}

double QgsGeos::hausdorffDistance( const QgsAbstractGeometry *geom, QString *errorMsg ) const
{
double distance = -1.0;
Expand Down
1 change: 1 addition & 0 deletions src/core/geometry/qgsgeos.h
Expand Up @@ -180,6 +180,7 @@ class CORE_EXPORT QgsGeos: public QgsGeometryEngine
QgsPoint *pointOnSurface( QString *errorMsg = nullptr ) const override;
QgsAbstractGeometry *convexHull( QString *errorMsg = nullptr ) const override;
double distance( const QgsAbstractGeometry *geom, QString *errorMsg = nullptr ) const override;
bool distanceWithin( const QgsAbstractGeometry *geom, double maxdistance, QString *errorMsg = nullptr ) const override;

/**
* Returns the Hausdorff distance between this geometry and \a geom. This is basically a measure of how similar or dissimilar 2 geometries are.
Expand Down
2 changes: 1 addition & 1 deletion src/core/vector/qgsvectorlayerfeatureiterator.cpp
Expand Up @@ -903,7 +903,7 @@ bool QgsVectorLayerFeatureIterator::postProcessFeature( QgsFeature &feature )

if ( result && mDistanceWithinEngine && feature.hasGeometry() )
{
result = mDistanceWithinEngine->distance( feature.geometry().constGet() ) <= mDistanceWithin;
result = mDistanceWithinEngine->distanceWithin( feature.geometry().constGet(), mDistanceWithin );
}

return result;
Expand Down

0 comments on commit acf302e

Please sign in to comment.