1 /***************************************************************************
2 qgscachedfeatureiterator.cpp
3 --------------------------------------
4 Date : 12.2.2013
5 Copyright : (C) 2013 Matthias Kuhn
6 Email : matthias at opengis dot ch
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
16 #include "qgscachedfeatureiterator.h"
17 #include "qgsvectorlayercache.h"
18 #include "qgsexception.h"
19 #include "qgsvectorlayer.h"
20 #include "qgsgeometryengine.h"
21
QgsCachedFeatureIterator(QgsVectorLayerCache * vlCache,const QgsFeatureRequest & featureRequest)22 QgsCachedFeatureIterator::QgsCachedFeatureIterator( QgsVectorLayerCache *vlCache, const QgsFeatureRequest &featureRequest )
23 : QgsAbstractFeatureIterator( featureRequest )
24 , mVectorLayerCache( vlCache )
25 {
26 if ( mRequest.destinationCrs().isValid() && mRequest.destinationCrs() != mVectorLayerCache->sourceCrs() )
27 {
28 mTransform = QgsCoordinateTransform( mVectorLayerCache->sourceCrs(), mRequest.destinationCrs(), mRequest.transformContext() );
29 }
30 try
31 {
32 mFilterRect = filterRectToSourceCrs( mTransform );
33 }
34 catch ( QgsCsException & )
35 {
36 // can't reproject mFilterRect
37 close();
38 return;
39 }
40
41 // prepare spatial filter geometries for optimal speed
42 switch ( mRequest.spatialFilterType() )
43 {
44 case Qgis::SpatialFilterType::NoFilter:
45 case Qgis::SpatialFilterType::BoundingBox:
46 break;
47
48 case Qgis::SpatialFilterType::DistanceWithin:
49 if ( !mRequest.referenceGeometry().isEmpty() )
50 {
51 mDistanceWithinGeom = mRequest.referenceGeometry();
52 mDistanceWithinEngine.reset( QgsGeometry::createGeometryEngine( mDistanceWithinGeom.constGet() ) );
53 mDistanceWithinEngine->prepareGeometry();
54 mDistanceWithin = mRequest.distanceWithin();
55 }
56 break;
57 }
58
59 if ( !mFilterRect.isNull() )
60 {
61 // update request to be the unprojected filter rect
62 mRequest.setFilterRect( mFilterRect );
63 }
64
65 switch ( featureRequest.filterType() )
66 {
67 case QgsFeatureRequest::FilterFids:
68 mFeatureIds = QList< QgsFeatureId >( qgis::setToList( featureRequest.filterFids() ) );
69 break;
70
71 case QgsFeatureRequest::FilterFid:
72 mFeatureIds = QList< QgsFeatureId >() << featureRequest.filterFid();
73 break;
74
75 default:
76 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
77 mFeatureIds.clear();
78 mFeatureIds.reserve( static_cast< int >( mVectorLayerCache->mCacheOrderedKeys.size() ) );
79 for ( auto it = mVectorLayerCache->mCacheOrderedKeys.begin(); it != mVectorLayerCache->mCacheOrderedKeys.end(); ++it )
80 mFeatureIds << *it;
81 #else
82 mFeatureIds = QList( mVectorLayerCache->mCacheOrderedKeys.begin(), mVectorLayerCache->mCacheOrderedKeys.end() );
83 #endif
84 break;
85 }
86
87 mFeatureIdIterator = mFeatureIds.constBegin();
88
89 if ( mFeatureIdIterator == mFeatureIds.constEnd() )
90 close();
91 }
92
93 QgsCachedFeatureIterator::~QgsCachedFeatureIterator() = default;
94
fetchFeature(QgsFeature & f)95 bool QgsCachedFeatureIterator::fetchFeature( QgsFeature &f )
96 {
97 f.setValid( false );
98
99 if ( mClosed )
100 return false;
101
102 while ( mFeatureIdIterator != mFeatureIds.constEnd() )
103 {
104 if ( !mVectorLayerCache->mCache.contains( *mFeatureIdIterator ) )
105 {
106 ++mFeatureIdIterator;
107 continue;
108 }
109
110 f = QgsFeature( *mVectorLayerCache->mCache[*mFeatureIdIterator]->feature() );
111 ++mFeatureIdIterator;
112 if ( mRequest.acceptFeature( f ) )
113 {
114 f.setValid( true );
115 geometryToDestinationCrs( f, mTransform );
116
117 bool result = true;
118 if ( mDistanceWithinEngine && mDistanceWithinEngine->distance( f.geometry().constGet() ) > mDistanceWithin )
119 {
120 f.setValid( false );
121 result = false;
122 }
123
124 if ( result )
125 return true;
126 }
127 }
128 close();
129 return false;
130 }
131
rewind()132 bool QgsCachedFeatureIterator::rewind()
133 {
134 mFeatureIdIterator = mFeatureIds.constBegin();
135 return true;
136 }
137
close()138 bool QgsCachedFeatureIterator::close()
139 {
140 mClosed = true;
141 mFeatureIds.clear();
142 return true;
143 }
144
QgsCachedFeatureWriterIterator(QgsVectorLayerCache * vlCache,const QgsFeatureRequest & featureRequest)145 QgsCachedFeatureWriterIterator::QgsCachedFeatureWriterIterator( QgsVectorLayerCache *vlCache, const QgsFeatureRequest &featureRequest )
146 : QgsAbstractFeatureIterator( featureRequest )
147 , mVectorLayerCache( vlCache )
148 {
149 if ( mRequest.destinationCrs().isValid() && mRequest.destinationCrs() != mVectorLayerCache->sourceCrs() )
150 {
151 mTransform = QgsCoordinateTransform( mVectorLayerCache->sourceCrs(), mRequest.destinationCrs(), mRequest.transformContext() );
152 }
153 try
154 {
155 mFilterRect = filterRectToSourceCrs( mTransform );
156 }
157 catch ( QgsCsException & )
158 {
159 // can't reproject mFilterRect
160 close();
161 return;
162 }
163 if ( !mFilterRect.isNull() )
164 {
165 // update request to be the unprojected filter rect
166 mRequest.setFilterRect( mFilterRect );
167 }
168
169 mFeatIt = vlCache->layer()->getFeatures( mRequest );
170 }
171
fetchFeature(QgsFeature & f)172 bool QgsCachedFeatureWriterIterator::fetchFeature( QgsFeature &f )
173 {
174 if ( mClosed )
175 {
176 f.setValid( false );
177 return false;
178 }
179 if ( mFeatIt.nextFeature( f ) )
180 {
181 // As long as features can be fetched from the provider: Write them to cache
182 mVectorLayerCache->cacheFeature( f );
183 mFids.insert( f.id() );
184 geometryToDestinationCrs( f, mTransform );
185 return true;
186 }
187 else
188 {
189 // Once no more features can be fetched: Inform the cache, that
190 // the request has been completed
191 mVectorLayerCache->requestCompleted( mRequest, mFids );
192 return false;
193 }
194 }
195
rewind()196 bool QgsCachedFeatureWriterIterator::rewind()
197 {
198 mFids.clear();
199 return mFeatIt.rewind();
200 }
201
close()202 bool QgsCachedFeatureWriterIterator::close()
203 {
204 mClosed = true;
205 return mFeatIt.close();
206 }
207