QGIS API Documentation 3.99.0-Master (2fe06baccd8)
Loading...
Searching...
No Matches
qgsfeatureiterator.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsfeatureiterator.cpp
3 ---------------------
4 begin : Juli 2012
5 copyright : (C) 2012 by Martin Dobias
6 email : wonder dot sk at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15#include "qgsfeatureiterator.h"
16
18#include "qgsexception.h"
20#include "qgsfeedback.h"
21#include "qgssimplifymethod.h"
22
27
29{
30 bool dataOk = false;
31 if ( mRequest.limit() >= 0 && mFetchedCount >= mRequest.limit() )
32 {
33 return false;
34 }
35
36 if ( mRequest.feedback() && mRequest.feedback()->isCanceled() )
37 return false;
38
39 if ( mUseCachedFeatures )
40 {
41 if ( mFeatureIterator != mCachedFeatures.constEnd() )
42 {
43 f = mFeatureIterator->mFeature;
44 ++mFeatureIterator;
45 dataOk = true;
46 }
47 else
48 {
49 dataOk = false;
50 // even the zombie dies at this point...
51 mZombie = false;
52 }
53 }
54 else
55 {
56 switch ( mRequest.filterType() )
57 {
59 dataOk = nextFeatureFilterExpression( f );
60 break;
61
63 dataOk = nextFeatureFilterFids( f );
64 break;
65
66 default:
67 dataOk = fetchFeature( f );
68 break;
69 }
70 }
71
72 if ( dataOk )
74
75 return dataOk;
76}
77
79{
80 while ( fetchFeature( f ) )
81 {
82 mRequest.expressionContext()->setFeature( f );
83 if ( mRequest.filterExpression()->evaluate( mRequest.expressionContext() ).toBool() )
84 return true;
85 }
86 return false;
87}
88
90{
91 while ( fetchFeature( f ) )
92 {
93 if ( mRequest.filterFids().contains( f.id() ) )
94 return true;
95 }
96 return false;
97}
98
100{
101 if ( transform.isValid() && feature.hasGeometry() )
102 {
103 try
104 {
105 QgsGeometry g = feature.geometry();
107 feature.setGeometry( g );
108 }
109 catch ( QgsCsException & )
110 {
111 // transform error
112 if ( mRequest.transformErrorCallback() )
113 {
114 mRequest.transformErrorCallback()( feature );
115 }
116 // remove geometry - we can't reproject so better not return a geometry in a different crs
117 feature.clearGeometry();
118 }
119 }
120}
121
123{
124 if ( transform.isShortCircuited() )
125 return RequestToSourceCrsResult::Success; // nothing to do
126
127 switch ( request.spatialFilterType() )
128 {
131
133 {
135 request.setFilterRect( newRect );
137 }
138
140 {
141 // we can't safely handle a distance within query, as we cannot transform the
142 // static within tolerance distance from one CRS to a static distance in a different CRS.
143
144 // in this case we transform the request's distance within requirement to a "worst case" bounding box filter, so
145 // that the request itself can still take advantage of spatial indices even when we have to do the distance within check locally
147 request.setFilterRect( newRect );
148
150 }
151 }
152
154}
155
157{
158 if ( mRequest.filterRect().isNull() )
159 return QgsRectangle();
160
161 QgsCoordinateTransform extentTransform = transform;
162 extentTransform.setBallparkTransformsAreAppropriate( true );
163 return extentTransform.transformBoundingBox( mRequest.filterRect(), Qgis::TransformDirection::Reverse, true );
164}
165
167{
168 // Prepare if required the simplification of geometries to fetch:
169 // This code runs here because of 'prepareSimplification()' is virtual and it can be overridden
170 // in inherited iterators who change the default behavior.
171 // It would be better to call this method in the constructor enabling virtual-calls as it is described by example at:
172 // http://www.parashift.com/c%2B%2B-faq-lite/calling-virtuals-from-ctor-idiom.html
173 if ( refs == 0 )
174 {
175 prepareSimplification( mRequest.simplifyMethod() );
176
177 // Should be called as last preparation step since it possibly will already fetch all features
178 setupOrderBy( mRequest.orderBy() );
179 }
180 refs++;
181}
182
184{
185 refs--;
186 if ( !refs )
187 delete this;
188}
189
194
196{
197 Q_UNUSED( simplifyMethod )
198 return false;
199}
200
201void QgsAbstractFeatureIterator::setupOrderBy( const QList<QgsFeatureRequest::OrderByClause> &orderBys )
202{
203 // Let the provider try using an efficient order by strategy first
204 if ( !orderBys.isEmpty() && !prepareOrderBy( orderBys ) )
205 {
206 // No success from the provider
207
208 // Prepare the expressions
209 QList<QgsFeatureRequest::OrderByClause> preparedOrderBys( orderBys );
210 QList<QgsFeatureRequest::OrderByClause>::iterator orderByIt( preparedOrderBys.begin() );
211
212 QgsExpressionContext *expressionContext( mRequest.expressionContext() );
213 do
214 {
215 orderByIt->prepare( expressionContext );
216 }
217 while ( ++orderByIt != preparedOrderBys.end() );
218
219 // Fetch all features
220 QgsIndexedFeature indexedFeature;
221 indexedFeature.mIndexes.resize( preparedOrderBys.size() );
222
223 while ( nextFeature( indexedFeature.mFeature ) )
224 {
225 expressionContext->setFeature( indexedFeature.mFeature );
226 int i = 0;
227 const auto constPreparedOrderBys = preparedOrderBys;
228 for ( const QgsFeatureRequest::OrderByClause &orderBy : constPreparedOrderBys )
229 {
230 indexedFeature.mIndexes.replace( i++, orderBy.expression().evaluate( expressionContext ) );
231 }
232
233 // We need all features, to ignore the limit for this pre-fetch
234 // keep the fetched count at 0.
235 mFetchedCount = 0;
236 mCachedFeatures.append( indexedFeature );
237 }
238
239 std::sort( mCachedFeatures.begin(), mCachedFeatures.end(), QgsExpressionSorter( preparedOrderBys ) );
240
241 mFeatureIterator = mCachedFeatures.constBegin();
242 mUseCachedFeatures = true;
243 // The real iterator is closed, we are only serving cached features
244 mZombie = true;
245 }
246}
247
248bool QgsAbstractFeatureIterator::providerCanSimplify( QgsSimplifyMethod::MethodType methodType ) const
249{
250 Q_UNUSED( methodType )
251 return false;
252}
253
254bool QgsAbstractFeatureIterator::prepareOrderBy( const QList<QgsFeatureRequest::OrderByClause> &orderBys )
255{
256 Q_UNUSED( orderBys )
257 return false;
258}
259
263
265
267{
268 if ( this != &other )
269 {
270 if ( mIter )
271 mIter->deref();
272 mIter = other.mIter;
273 if ( mIter )
274 mIter->ref();
275 }
276 return *this;
277}
278
280{
281 return mIter && mIter->isValid();
282}
@ Fids
Filter using feature IDs.
Definition qgis.h:2226
@ Expression
Filter using expression.
Definition qgis.h:2225
@ DistanceWithin
Filter by distance to reference geometry.
Definition qgis.h:2254
@ BoundingBox
Filter using a bounding box.
Definition qgis.h:2253
@ NoFilter
No spatial filtering of features.
Definition qgis.h:2252
@ Forward
Forward transform (from source to destination).
Definition qgis.h:2672
@ Reverse
Reverse/inverse transform (from destination to source).
Definition qgis.h:2673
RequestToSourceCrsResult
Possible results from the updateRequestToSourceCrs() method.
@ Success
Request was successfully updated to the source CRS, or no changes were required.
@ DistanceWithinMustBeCheckedManually
The distance within request cannot be losslessly updated to the source CRS, and callers will need to ...
bool mZombie
A feature iterator may be closed already but still be serving features from the cache.
virtual bool nextFeatureFilterFids(QgsFeature &f)
By default, the iterator will fetch all features and check if the id is in the request.
void geometryToDestinationCrs(QgsFeature &feature, const QgsCoordinateTransform &transform) const
Transforms feature's geometry according to the specified coordinate transform.
QgsRectangle filterRectToSourceCrs(const QgsCoordinateTransform &transform) const
Returns a rectangle representing the original request's QgsFeatureRequest::filterRect().
virtual void setInterruptionChecker(QgsFeedback *interruptionChecker)
Attach an object that can be queried regularly by the iterator to check if it must stopped.
virtual bool fetchFeature(QgsFeature &f)=0
If you write a feature iterator for your provider, this is the method you need to implement!
long long mFetchedCount
Number of features already fetched by iterator.
virtual bool prepareSimplification(const QgsSimplifyMethod &simplifyMethod)
Setup the simplification of geometries to fetch using the specified simplify method.
void deref()
Remove reference, delete if refs == 0.
QgsFeatureRequest mRequest
A copy of the feature request.
QgsAbstractFeatureIterator(const QgsFeatureRequest &request)
base class constructor - stores the iteration parameters
RequestToSourceCrsResult updateRequestToSourceCrs(QgsFeatureRequest &request, const QgsCoordinateTransform &transform) const
Update a QgsFeatureRequest so that spatial filters are transformed to the source's coordinate referen...
bool compileFailed() const
Indicator if there was an error when sending the compiled query to the server.
int refs
reference counting (to allow seamless copying of QgsFeatureIterator instances)
virtual bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
virtual bool nextFeatureFilterExpression(QgsFeature &f)
By default, the iterator will fetch all features and check if the feature matches the expression.
Handles coordinate transforms between two coordinate systems.
void setBallparkTransformsAreAppropriate(bool appropriate)
Sets whether approximate "ballpark" results are appropriate for this coordinate transform.
bool isShortCircuited() const
Returns true if the transform short circuits because the source and destination are equivalent.
QgsRectangle transformBoundingBox(const QgsRectangle &rectangle, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool handle180Crossover=false) const
Transforms a rectangle from the source CRS to the destination CRS.
bool hasVerticalComponent() const
Returns true if the transform includes a vertical component, i.e.
bool isValid() const
Returns true if the coordinate transform is valid, ie both the source and destination CRS have been s...
Custom exception class for Coordinate Reference System related exceptions.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QgsAbstractFeatureIterator * mIter
QgsFeatureIterator & operator=(const QgsFeatureIterator &other)
bool isValid() const
Will return if this iterator is valid.
QgsFeatureIterator()=default
Construct invalid iterator.
Wraps a request for features to a vector layer (or directly its vector data provider).
QgsRectangle filterRect() const
Returns the rectangle from which features will be taken.
QgsExpressionContext * expressionContext()
Returns the expression context used to evaluate filter expressions.
Qgis::SpatialFilterType spatialFilterType() const
Returns the spatial filter type which is currently set on this request.
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:58
QgsFeatureId id
Definition qgsfeature.h:66
QgsGeometry geometry
Definition qgsfeature.h:69
void clearGeometry()
Removes any geometry associated with the feature.
bool hasGeometry() const
Returns true if the feature has an associated geometry.
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition qgsfeedback.h:44
A geometry is the spatial representation of a feature.
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false)
Transforms this geometry as described by the coordinate transform ct.
QVector< QVariant > mIndexes
A rectangle specified with double values.
Contains information about how to simplify geometries fetched from a QgsFeatureIterator.
#define BUILTIN_UNREACHABLE
Definition qgis.h:7208