[processing] Optimise feature requests within qgis algs

- don't use setFilterFid() within loops to fetch features one
at time (as it's extremely slow), instead use setFilterFids()
outside the loop
- don't fetch unused attributes/geometry when it can be
avoided
This commit is contained in:
Nyall Dawson 2016-10-17 10:30:55 +10:00
parent 55f207108d
commit 86368f39c3
22 changed files with 43 additions and 54 deletions

View File

@ -85,9 +85,9 @@ class Difference(GeoAlgorithm):
diff_geom = QgsGeometry(geom)
attrs = inFeatA.attributes()
intersections = index.intersects(geom.boundingBox())
for i in intersections:
request = QgsFeatureRequest().setFilterFid(i)
inFeatB = next(layerB.getFeatures(request))
request = QgsFeatureRequest().setFilterFids(intersections).setSubsetOfAttributes([])
for inFeatB in layerB.getFeatures(request):
tmpGeom = inFeatB.geometry()
if diff_geom.intersects(tmpGeom):
diff_geom = QgsGeometry(diff_geom.difference(tmpGeom))

View File

@ -246,7 +246,7 @@ class Eliminate(GeoAlgorithm):
geom2Eliminate = feat.geometry()
bbox = geom2Eliminate.boundingBox()
fit = processLayer.getFeatures(
QgsFeatureRequest().setFilterRect(bbox))
QgsFeatureRequest().setFilterRect(bbox).setSubsetOfAttributes([]))
mergeWithFid = None
mergeWithGeom = None
max = 0

View File

@ -84,9 +84,8 @@ class ExtractByLocation(GeoAlgorithm):
geom = vector.snapToPrecision(f.geometry(), precision)
bbox = vector.bufferedBoundingBox(geom.boundingBox(), 0.51 * precision)
intersects = index.intersects(bbox)
for i in intersects:
request = QgsFeatureRequest().setFilterFid(i)
feat = next(layer.getFeatures(request))
request = QgsFeatureRequest().setFilterFids(intersects).setSubsetOfAttributes([])
for feat in layer.getFeatures(request):
tmpGeom = vector.snapToPrecision(feat.geometry(), precision)
res = False
for predicate in predicates:

View File

@ -109,7 +109,7 @@ class HubDistanceLines(GeoAlgorithm):
src = f.geometry().boundingBox().center()
neighbors = index.nearestNeighbor(src, 1)
ft = next(layerHubs.getFeatures(QgsFeatureRequest().setFilterFid(neighbors[0])))
ft = next(layerHubs.getFeatures(QgsFeatureRequest().setFilterFid(neighbors[0]).setSubsetOfAttributes([fieldName], layerHubs.fields())))
closest = ft.geometry().boundingBox().center()
hubDist = distance.measureLine(src, closest)

View File

@ -109,7 +109,7 @@ class HubDistancePoints(GeoAlgorithm):
src = f.geometry().boundingBox().center()
neighbors = index.nearestNeighbor(src, 1)
ft = next(layerHubs.getFeatures(QgsFeatureRequest().setFilterFid(neighbors[0])))
ft = next(layerHubs.getFeatures(QgsFeatureRequest().setFilterFid(neighbors[0]).setSubsetOfAttributes([fieldName], layerHubs.fields())))
closest = ft.geometry().boundingBox().center()
hubDist = distance.measureLine(src, closest)

View File

@ -88,9 +88,8 @@ class Intersection(GeoAlgorithm):
geom = inFeatA.geometry()
atMapA = inFeatA.attributes()
intersects = index.intersects(geom.boundingBox())
for i in intersects:
request = QgsFeatureRequest().setFilterFid(i)
inFeatB = next(vlayerB.getFeatures(request))
request = QgsFeatureRequest().setFilterFids(intersects)
for inFeatB in vlayerB.getFeatures(request):
tmpGeom = inFeatB.geometry()
if geom.intersects(tmpGeom):
atMapB = inFeatB.attributes()

View File

@ -105,9 +105,8 @@ class LinesIntersection(GeoAlgorithm):
hasIntersections = True
if hasIntersections:
for i in lines:
request = QgsFeatureRequest().setFilterFid(i)
inFeatB = next(layerB.getFeatures(request))
request = QgsFeatureRequest().setFilterFids(lines)
for inFeatB in layerB.getFeatures(request):
tmpGeom = inFeatB.geometry()
points = []

View File

@ -95,7 +95,7 @@ class NearestNeighbourAnalysis(GeoAlgorithm):
for current, feat in enumerate(features):
neighbourID = spatialIndex.nearestNeighbor(
feat.geometry().asPoint(), 2)[1]
request = QgsFeatureRequest().setFilterFid(neighbourID)
request = QgsFeatureRequest().setFilterFid(neighbourID).setSubsetOfAttributes([])
neighbour = next(layer.getFeatures(request))
sumDist += distance.measureLine(neighbour.geometry().asPoint(),
feat.geometry().asPoint())

View File

@ -136,9 +136,8 @@ class PointDistance(GeoAlgorithm):
featList = index.nearestNeighbor(inGeom.asPoint(), nPoints)
distList = []
vari = 0.0
for i in featList:
request = QgsFeatureRequest().setFilterFid(i)
outFeat = next(targetLayer.getFeatures(request))
request = QgsFeatureRequest().setFilterFids(featList).setSubsetOfAttributes([outIdx])
for outFeat in targetLayer.getFeatures(request):
outID = outFeat.attributes()[outIdx]
outGeom = outFeat.geometry()
dist = distArea.measureLine(inGeom.asPoint(),

View File

@ -86,11 +86,10 @@ class PointsDisplacement(GeoAlgorithm):
fullPerimeter = 2 * math.pi
request = QgsFeatureRequest()
for (geom, fids) in list(duplicates.items()):
count = len(fids)
if count == 1:
f = next(layer.getFeatures(request.setFilterFid(fids[0])))
f = next(layer.getFeatures(QgsFeatureRequest().setFilterFid(fids[0])))
writer.addFeature(f)
else:
angleStep = fullPerimeter / count
@ -100,14 +99,14 @@ class PointsDisplacement(GeoAlgorithm):
currentAngle = 0
old_point = QgsGeometry.fromWkt(geom).asPoint()
for fid in fids:
request = QgsFeatureRequest().setFilterFids(fids).setFlags(QgsFeatureRequest.NoGeometry)
for f in layer.getFeatures(request):
sinusCurrentAngle = math.sin(currentAngle)
cosinusCurrentAngle = math.cos(currentAngle)
dx = radius * sinusCurrentAngle
dy = radius * cosinusCurrentAngle
f = next(layer.getFeatures(request.setFilterFid(fid)))
new_point = QgsPoint(old_point.x() + dx, old_point.y()
+ dy)
out_feature = QgsFeature()

View File

@ -96,7 +96,7 @@ class PointsInPolygon(GeoAlgorithm):
count = 0
points = spatialIndex.intersects(geom.boundingBox())
if len(points) > 0:
request = QgsFeatureRequest().setFilterFids(points)
request = QgsFeatureRequest().setFilterFids(points).setSubsetOfAttributes([])
fit = pointLayer.getFeatures(request)
ftPoint = QgsFeature()
while fit.nextFeature(ftPoint):

View File

@ -90,7 +90,7 @@ class PointsInPolygonUnique(GeoAlgorithm):
classes = set()
points = spatialIndex.intersects(geom.boundingBox())
if len(points) > 0:
request = QgsFeatureRequest().setFilterFids(points)
request = QgsFeatureRequest().setFilterFids(points).setSubsetOfAttributes([classFieldIndex])
fit = pointLayer.getFeatures(request)
ftPoint = QgsFeature()
while fit.nextFeature(ftPoint):

View File

@ -98,7 +98,7 @@ class PointsInPolygonWeighted(GeoAlgorithm):
points = spatialIndex.intersects(geom.boundingBox())
if len(points) > 0:
progress.setText(str(len(points)))
request = QgsFeatureRequest().setFilterFids(points)
request = QgsFeatureRequest().setFilterFids(points).setSubsetOfAttributes([fieldIdx])
fit = pointLayer.getFeatures(request)
ftPoint = QgsFeature()
while fit.nextFeature(ftPoint):

View File

@ -88,7 +88,7 @@ class RandomPointsAlongLines(GeoAlgorithm):
while nIterations < maxIterations and nPoints < pointCount:
# pick random feature
fid = random.randint(0, featureCount - 1)
f = next(layer.getFeatures(request.setFilterFid(fid)))
f = next(layer.getFeatures(request.setFilterFid(fid).setSubsetOfAttributes([])))
fGeom = f.geometry()
if fGeom.isMultipart():

View File

@ -88,8 +88,6 @@ class RandomPointsLayer(GeoAlgorithm):
index = QgsSpatialIndex()
points = dict()
request = QgsFeatureRequest()
random.seed()
while nIterations < maxIterations and nPoints < pointCount:
@ -101,8 +99,8 @@ class RandomPointsLayer(GeoAlgorithm):
ids = idxLayer.intersects(geom.buffer(5, 5).boundingBox())
if len(ids) > 0 and \
vector.checkMinDistance(pnt, index, minDistance, points):
for i in ids:
f = next(layer.getFeatures(request.setFilterFid(i)))
request = QgsFeatureRequest().setFilterFids(ids).setSubsetOfAttributes([])
for f in layer.getFeatures(request):
tmpGeom = f.geometry()
if geom.within(tmpGeom):
f = QgsFeature(nPoints)

View File

@ -111,7 +111,7 @@ class SelectByAttribute(GeoAlgorithm):
qExp = QgsExpression(expr)
if not qExp.hasParserError():
qReq = QgsFeatureRequest(qExp)
qReq = QgsFeatureRequest(qExp).setSubsetOfAttributes([])
else:
raise GeoAlgorithmExecutionException(qExp.parserErrorString())
selected = [f.id() for f in layer.getFeatures(qReq)]

View File

@ -82,8 +82,8 @@ class SelectByAttributeSum(GeoAlgorithm):
progress.setInfo(self.tr('No adjacent features found.'))
break
for i in intersected:
ft = next(layer.getFeatures(req.setFilterFid(i)))
req = QgsFeatureRequest().setFilterFids(intersected).setSubsetOfAttributes([fieldName], layer.fields())
for ft in layer.getFeatures(req):
tmpGeom = ft.geometry()
if tmpGeom.touches(geom):
geom = tmpGeom.combine(geom)

View File

@ -105,9 +105,8 @@ class SelectByLocation(GeoAlgorithm):
bbox = vector.bufferedBoundingBox(geom.boundingBox(), 0.51 * precision)
intersects = index.intersects(bbox)
for i in intersects:
request = QgsFeatureRequest().setFilterFid(i)
feat = next(inputLayer.getFeatures(request))
request = QgsFeatureRequest().setFilterFids(intersects).setSubsetOfAttributes([])
for feat in inputLayer.getFeatures(request):
tmpGeom = vector.snapToPrecision(feat.geometry(), precision)
res = False

View File

@ -79,9 +79,8 @@ class SplitLinesWithLines(GeoAlgorithm):
if len(lines) > 0: # hasIntersections
splittingLines = []
for i in lines:
request = QgsFeatureRequest().setFilterFid(i)
inFeatB = next(layerB.getFeatures(request))
request = QgsFeatureRequest().setFilterFids(lines).setSubsetOfAttributes([])
for inFeatB in layerB.getFeatures(request):
# check if trying to self-intersect
if sameLayer:
if inFeatA.id() == inFeatB.id():

View File

@ -104,9 +104,8 @@ class SumLines(GeoAlgorithm):
hasIntersections = True
if hasIntersections:
for i in lines:
request = QgsFeatureRequest().setFilterFid(i)
ftLine = next(lineLayer.getFeatures(request))
request = QgsFeatureRequest().setFilterFids(lines).setSubsetOfAttributes([])
for ftLine in lineLayer.getFeatures(request):
tmpGeom = ftLine.geometry()
if inGeom.intersects(tmpGeom):
outGeom = inGeom.intersection(tmpGeom)

View File

@ -88,8 +88,8 @@ class SymmetricalDifference(GeoAlgorithm):
diffGeom = QgsGeometry(geom)
attrs = featA.attributes()
intersects = indexA.intersects(geom.boundingBox())
for i in intersects:
layerB.getFeatures(QgsFeatureRequest().setFilterFid(i)).nextFeature(featB)
request = QgsFeatureRequest().setFilterFids(intersects).setSubsetOfAttributes([])
for featB in layerB.getFeatures(request):
tmpGeom = featB.geometry()
if diffGeom.intersects(tmpGeom):
diffGeom = QgsGeometry(diffGeom.difference(tmpGeom))
@ -123,8 +123,8 @@ class SymmetricalDifference(GeoAlgorithm):
attrs = featA.attributes()
attrs = [NULL] * length + attrs
intersects = indexB.intersects(geom.boundingBox())
for i in intersects:
layerA.getFeatures(QgsFeatureRequest().setFilterFid(i)).nextFeature(featB)
request = QgsFeatureRequest().setFilterFids(intersects).setSubsetOfAttributes([])
for featB in layerA.getFeatures(request):
tmpGeom = featB.geometry()
if diffGeom.intersects(tmpGeom):
diffGeom = QgsGeometry(diffGeom.difference(tmpGeom))

View File

@ -105,10 +105,10 @@ class Union(GeoAlgorithm):
ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))
else:
for id in intersects:
request = QgsFeatureRequest().setFilterFids(intersects)
for inFeatB in vlayerB.getFeatures(request):
count += 1
request = QgsFeatureRequest().setFilterFid(id)
inFeatB = next(vlayerB.getFeatures(request))
atMapB = inFeatB.attributes()
tmpGeom = inFeatB.geometry()
@ -197,9 +197,8 @@ class Union(GeoAlgorithm):
ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))
else:
for id in intersects:
request = QgsFeatureRequest().setFilterFid(id)
inFeatB = next(vlayerA.getFeatures(request))
request = QgsFeatureRequest().setFilterFids(intersects)
for inFeatB in vlayerA.getFeatures(request):
atMapB = inFeatB.attributes()
tmpGeom = inFeatB.geometry()