42
42
QgsProviderRegistry ,
43
43
QgsProviderMetadata ,
44
44
QgsGeometryEngine ,
45
+ QgsSpatialIndex ,
45
46
)
46
47
47
48
from qgis .PyQt .QtCore import QVariant
@@ -65,6 +66,9 @@ def __init__(self, source, request):
65
66
else :
66
67
self ._select_rect_engine = None
67
68
self ._select_rect_geom = None
69
+ self ._feature_id_list = None
70
+ if self ._filter_rect is not None and self ._source ._provider ._spatialindex is not None :
71
+ self ._feature_id_list = self ._source ._provider ._spatialindex .intersects (self ._filter_rect )
68
72
69
73
def fetchFeature (self , f ):
70
74
"""fetch next feature, return true on success"""
@@ -77,6 +81,21 @@ def fetchFeature(self, f):
77
81
while not found :
78
82
_f = self ._source ._features [list (self ._source ._features .keys ())[self ._index ]]
79
83
self ._index += 1
84
+
85
+ if self ._feature_id_list is not None and f .id () not in self ._feature_id_list :
86
+ continue
87
+
88
+ if not self ._filter_rect .isNull ():
89
+ if not _f .hasGeometry ():
90
+ continue
91
+ if self ._request .flags () & QgsFeatureRequest .ExactIntersect :
92
+ # do exact check in case we're doing intersection
93
+ if not self ._select_rect_engine .intersects (_f .geometry ().constGet ()):
94
+ continue
95
+ else :
96
+ if not _f .geometry ().boundingBox ().intersects (self ._filter_rect ):
97
+ continue
98
+
80
99
self ._source ._expression_context .setFeature (_f )
81
100
if self ._request .filterType () == QgsFeatureRequest .FilterExpression :
82
101
if not self ._request .filterExpression ().evaluate (self ._source ._expression_context ):
@@ -90,16 +109,6 @@ def fetchFeature(self, f):
90
109
elif self ._request .filterType () == QgsFeatureRequest .FilterFid :
91
110
if _f .id () != self ._request .filterFid ():
92
111
continue
93
- if not self ._filter_rect .isNull ():
94
- if not _f .hasGeometry ():
95
- continue
96
- if self ._request .flags () & QgsFeatureRequest .ExactIntersect :
97
- # do exact check in case we're doing intersection
98
- if not self ._select_rect_engine .intersects (_f .geometry ().constGet ()):
99
- continue
100
- else :
101
- if not _f .geometry ().boundingBox ().intersects (self ._filter_rect ):
102
- continue
103
112
f .setGeometry (_f .geometry ())
104
113
self .geometryToDestinationCrs (f , self ._transform )
105
114
f .setFields (_f .fields ())
@@ -198,6 +207,9 @@ def __init__(self, uri=''):
198
207
self ._extent .setMinimal ()
199
208
self ._subset_string = ''
200
209
self ._crs = mlayer .crs ()
210
+ self ._spatialindex = None
211
+ if 'index=yes' in self ._uri :
212
+ self .createSpatialIndex ()
201
213
202
214
def featureSource (self ):
203
215
return PyFeatureSource (self )
@@ -256,6 +268,9 @@ def addFeatures(self, flist, flags=None):
256
268
added = True
257
269
f_added .append (_f )
258
270
271
+ if self ._spatialindex is not None :
272
+ self ._spatialindex .insertFeature (_f )
273
+
259
274
if len (f_added ):
260
275
self .updateExtents ()
261
276
@@ -267,6 +282,8 @@ def deleteFeatures(self, ids):
267
282
removed = False
268
283
for id in ids :
269
284
if id in self ._features :
285
+ if self ._spatialindex is not None :
286
+ self ._spatialindex .deleteFeature (self ._features [id ])
270
287
del self ._features [id ]
271
288
removed = True
272
289
if removed :
@@ -349,6 +366,10 @@ def supportsSubsetString(self):
349
366
return True
350
367
351
368
def createSpatialIndex (self ):
369
+ if self ._spatialindex is None :
370
+ self ._spatialindex = QgsSpatialIndex ()
371
+ for f in self ._features :
372
+ self ._spatialindex .insertFeature (f )
352
373
return True
353
374
354
375
def capabilities (self ):
0 commit comments