29 QgsMemoryFeatureIterator::QgsMemoryFeatureIterator( QgsMemoryFeatureSource *source,
bool ownSource,
const QgsFeatureRequest &request )
32 if ( mRequest.destinationCrs().isValid() && mRequest.destinationCrs() != mSource->mCrs )
34 mTransform =
QgsCoordinateTransform( mSource->mCrs, mRequest.destinationCrs(), mRequest.transformContext() );
38 mFilterRect = filterRectToSourceCrs( mTransform );
47 if ( !mSource->mSubsetString.isEmpty() )
49 mSubsetExpression = qgis::make_unique< QgsExpression >( mSource->mSubsetString );
50 mSubsetExpression->prepare( mSource->expressionContext() );
57 mSelectRectEngine->prepareGeometry();
62 if ( !mFilterRect.isNull() && mSource->mSpatialIndex )
64 mUsingFeatureIdList =
true;
65 mFeatureIdList = mSource->mSpatialIndex->intersects( mFilterRect );
66 QgsDebugMsgLevel(
"Features returned by spatial index: " + QString::number( mFeatureIdList.count() ), 2 );
70 mUsingFeatureIdList =
true;
71 QgsFeatureMap::const_iterator it = mSource->mFeatures.constFind( mRequest.filterFid() );
72 if ( it != mSource->mFeatures.constEnd() )
73 mFeatureIdList.append( mRequest.filterFid() );
77 mUsingFeatureIdList =
true;
78 mFeatureIdList = qgis::setToList( mRequest.filterFids() );
82 mUsingFeatureIdList =
false;
88 QgsMemoryFeatureIterator::~QgsMemoryFeatureIterator()
93 bool QgsMemoryFeatureIterator::fetchFeature(
QgsFeature &feature )
100 if ( mUsingFeatureIdList )
101 return nextFeatureUsingList( feature );
103 return nextFeatureTraverseAll( feature );
107 bool QgsMemoryFeatureIterator::nextFeatureUsingList(
QgsFeature &feature )
109 bool hasFeature =
false;
113 while ( mFeatureIdListIterator != mFeatureIdList.constEnd() )
115 candidate = mSource->mFeatures.value( *mFeatureIdListIterator );
116 if ( !mFilterRect.isNull() )
124 else if ( mSource->mSpatialIndex )
139 if ( hasFeature && mSubsetExpression )
141 mSource->expressionContext()->setFeature( candidate );
142 if ( !mSubsetExpression->evaluate( mSource->expressionContext() ).toBool() )
149 ++mFeatureIdListIterator;
156 ++mFeatureIdListIterator;
164 geometryToDestinationCrs( feature, mTransform );
171 bool QgsMemoryFeatureIterator::nextFeatureTraverseAll(
QgsFeature &feature )
173 bool hasFeature =
false;
176 while ( mSelectIterator != mSource->mFeatures.constEnd() )
178 if ( mFilterRect.isNull() )
188 if ( mSelectIterator->hasGeometry() && mSelectRectEngine->intersects( mSelectIterator->geometry().constGet() ) )
194 if ( mSelectIterator->hasGeometry() && mSelectIterator->geometry().boundingBox().intersects( mFilterRect ) )
199 if ( mSubsetExpression )
201 mSource->expressionContext()->setFeature( *mSelectIterator );
202 if ( !mSubsetExpression->evaluate( mSource->expressionContext() ).toBool() )
215 feature = mSelectIterator.value();
219 geometryToDestinationCrs( feature, mTransform );
227 bool QgsMemoryFeatureIterator::rewind()
232 if ( mUsingFeatureIdList )
233 mFeatureIdListIterator = mFeatureIdList.constBegin();
235 mSelectIterator = mSource->mFeatures.constBegin();
240 bool QgsMemoryFeatureIterator::close()
253 QgsMemoryFeatureSource::QgsMemoryFeatureSource(
const QgsMemoryProvider *p )
254 : mFields( p->mFields )
255 , mFeatures( p->mFeatures )
256 , mSpatialIndex( p->mSpatialIndex ? qgis::make_unique<
QgsSpatialIndex >( *p->mSpatialIndex ) : nullptr )
257 , mSubsetString( p->mSubsetString )
271 if ( !mExpressionContext )
273 mExpressionContext = qgis::make_unique< QgsExpressionContext >(
274 QList<QgsExpressionContextScope *>()
277 mExpressionContext->setFields( mFields );
279 return mExpressionContext.get();
Helper template that cares of two things: 1.
Custom exception class for Coordinate Reference System related exceptions.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Wrapper for iterator of features from vector data provider or vector layer.
This class wraps a request for features to a vector layer (or directly its vector data provider).
@ ExactIntersect
Use exact geometry intersection (slower) instead of bounding boxes.
@ FilterFid
Filter using feature ID.
@ FilterFids
Filter using feature IDs.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
void setFields(const QgsFields &fields, bool initAttributes=false)
Assign a field map with the feature to allow attribute access by attribute name.
void setValid(bool validity)
Sets the validity of the feature.
bool hasGeometry() const
Returns true if the feature has an associated geometry.
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
bool boundingBoxIntersects(const QgsRectangle &rectangle) const
Returns true if the bounding box of this geometry intersects with a rectangle.
static QgsGeometry fromRect(const QgsRectangle &rect) SIP_HOLDGIL
Creates a new geometry from a QgsRectangle.
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine.
static QgsProject * instance()
Returns the QgsProject singleton instance.
A spatial index for QgsFeature objects.
#define QgsDebugMsgLevel(str, level)