Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Handle distance within feature requests in memory provider
  • Loading branch information
nyalldawson committed Aug 5, 2021
1 parent 686a6e5 commit 69aa279
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 6 deletions.
57 changes: 51 additions & 6 deletions src/core/providers/memory/qgsmemoryfeatureiterator.cpp
Expand Up @@ -50,11 +50,29 @@ QgsMemoryFeatureIterator::QgsMemoryFeatureIterator( QgsMemoryFeatureSource *sour
mSubsetExpression->prepare( mSource->expressionContext() );
}

if ( !mFilterRect.isNull() && mRequest.flags() & QgsFeatureRequest::ExactIntersect )
// prepare spatial filter geometries for optimal speed
switch ( mRequest.spatialFilterType() )
{
mSelectRectGeom = QgsGeometry::fromRect( mFilterRect );
mSelectRectEngine.reset( QgsGeometry::createGeometryEngine( mSelectRectGeom.constGet() ) );
mSelectRectEngine->prepareGeometry();
case Qgis::SpatialFilterType::NoFilter:
break;

case Qgis::SpatialFilterType::BoundingBox:
if ( !mFilterRect.isNull() && mRequest.flags() & QgsFeatureRequest::ExactIntersect )
{
mSelectRectGeom = QgsGeometry::fromRect( mFilterRect );
mSelectRectEngine.reset( QgsGeometry::createGeometryEngine( mSelectRectGeom.constGet() ) );
mSelectRectEngine->prepareGeometry();
}
break;

case Qgis::SpatialFilterType::DistanceWithin:
if ( !mRequest.referenceGeometry().isEmpty() )
{
mDistanceWithinGeom = mRequest.referenceGeometry();
mDistanceWithinEngine.reset( QgsGeometry::createGeometryEngine( mDistanceWithinGeom.constGet() ) );
mDistanceWithinEngine->prepareGeometry();
}
break;
}

// if there's spatial index, use it!
Expand Down Expand Up @@ -115,7 +133,7 @@ bool QgsMemoryFeatureIterator::nextFeatureUsingList( QgsFeature &feature )
candidate = mSource->mFeatures.value( *mFeatureIdListIterator );
if ( !mFilterRect.isNull() )
{
if ( mRequest.flags() & QgsFeatureRequest::ExactIntersect )
if ( mRequest.spatialFilterType() == Qgis::SpatialFilterType::BoundingBox && mRequest.flags() & QgsFeatureRequest::ExactIntersect )
{
// do exact check in case we're doing intersection
if ( candidate.hasGeometry() && mSelectRectEngine->intersects( candidate.geometry().constGet() ) )
Expand All @@ -132,6 +150,20 @@ bool QgsMemoryFeatureIterator::nextFeatureUsingList( QgsFeature &feature )
if ( candidate.hasGeometry() && candidate.geometry().boundingBoxIntersects( mFilterRect ) )
hasFeature = true;
}

if ( mRequest.spatialFilterType() == Qgis::SpatialFilterType::DistanceWithin && hasFeature )
{
if ( !mTransform.isShortCircuited() )
{
QgsFeature transformedCandidate( candidate );
geometryToDestinationCrs( transformedCandidate, mTransform );
hasFeature = transformedCandidate.hasGeometry() && mDistanceWithinEngine->distance( transformedCandidate.geometry().constGet() ) <= mRequest.distanceWithin();
}
else
{
hasFeature = mDistanceWithinEngine->distance( candidate.geometry().constGet() ) <= mRequest.distanceWithin();
}
}
}
else
hasFeature = true;
Expand Down Expand Up @@ -182,7 +214,7 @@ bool QgsMemoryFeatureIterator::nextFeatureTraverseAll( QgsFeature &feature )
}
else
{
if ( mRequest.flags() & QgsFeatureRequest::ExactIntersect )
if ( mRequest.spatialFilterType() == Qgis::SpatialFilterType::BoundingBox && mRequest.flags() & QgsFeatureRequest::ExactIntersect )
{
// using exact test when checking for intersection
if ( mSelectIterator->hasGeometry() && mSelectRectEngine->intersects( mSelectIterator->geometry().constGet() ) )
Expand All @@ -194,6 +226,19 @@ bool QgsMemoryFeatureIterator::nextFeatureTraverseAll( QgsFeature &feature )
if ( mSelectIterator->hasGeometry() && mSelectIterator->geometry().boundingBox().intersects( mFilterRect ) )
hasFeature = true;
}
if ( mRequest.spatialFilterType() == Qgis::SpatialFilterType::DistanceWithin && hasFeature )
{
if ( !mTransform.isShortCircuited() )
{
QgsFeature transformedCandidate( *mSelectIterator );
geometryToDestinationCrs( transformedCandidate, mTransform );
hasFeature = transformedCandidate.hasGeometry() && mDistanceWithinEngine->distance( transformedCandidate.geometry().constGet() ) <= mRequest.distanceWithin();
}
else
{
hasFeature = mDistanceWithinEngine->distance( mSelectIterator->geometry().constGet() ) <= mRequest.distanceWithin();
}
}
}

if ( mSubsetExpression )
Expand Down
2 changes: 2 additions & 0 deletions src/core/providers/memory/qgsmemoryfeatureiterator.h
Expand Up @@ -72,6 +72,8 @@ class QgsMemoryFeatureIterator final: public QgsAbstractFeatureIteratorFromSourc

QgsGeometry mSelectRectGeom;
std::unique_ptr< QgsGeometryEngine > mSelectRectEngine;
QgsGeometry mDistanceWithinGeom;
std::unique_ptr< QgsGeometryEngine > mDistanceWithinEngine;
QgsRectangle mFilterRect;
QgsFeatureMap::const_iterator mSelectIterator;
bool mUsingFeatureIdList = false;
Expand Down

0 comments on commit 69aa279

Please sign in to comment.