Skip to content

Commit 2e8b848

Browse files
committedJul 15, 2017
Port sum line length algorithm to new API
and implement auto reprojection of lines to polygon layer CRS
1 parent 2230597 commit 2e8b848

File tree

3 files changed

+99
-86
lines changed

3 files changed

+99
-86
lines changed
 

‎python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,14 @@
7979
from .Smooth import Smooth
8080
from .SnapGeometries import SnapGeometriesToLayer
8181
from .SpatialiteExecuteSQL import SpatialiteExecuteSQL
82+
from .SumLines import SumLines
8283
from .SymmetricalDifference import SymmetricalDifference
8384
from .Union import Union
8485
from .VectorSplit import VectorSplit
8586
from .VoronoiPolygons import VoronoiPolygons
8687
from .ZonalStatistics import ZonalStatistics
8788

8889
# from .ExtractByLocation import ExtractByLocation
89-
# from .SumLines import SumLines
9090
# from .NearestNeighbourAnalysis import NearestNeighbourAnalysis
9191
# from .LinesIntersection import LinesIntersection
9292
# from .MeanCoords import MeanCoords
@@ -183,8 +183,7 @@ def __init__(self):
183183
self.externalAlgs = []
184184

185185
def getAlgs(self):
186-
# algs = [SumLines(),
187-
# NearestNeighbourAnalysis(), MeanCoords(),
186+
# algs = [NearestNeighbourAnalysis(), MeanCoords(),
188187
# LinesIntersection(), UniqueValues(), PointDistance(),
189188
# ExportGeometryInfo(),
190189
# SinglePartsToMultiparts(),
@@ -274,6 +273,7 @@ def getAlgs(self):
274273
Smooth(),
275274
SnapGeometriesToLayer(),
276275
SpatialiteExecuteSQL(),
276+
SumLines(),
277277
SymmetricalDifference(),
278278
Union(),
279279
VectorSplit(),

‎python/plugins/processing/algs/qgis/SumLines.py

Lines changed: 80 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,20 @@
2828
import os
2929

3030
from qgis.PyQt.QtGui import QIcon
31-
32-
from qgis.core import QgsFeature, QgsFeatureSink, QgsGeometry, QgsFeatureRequest, QgsDistanceArea, QgsProcessingUtils
31+
from qgis.PyQt.QtCore import QVariant
32+
from qgis.core import (QgsFeature,
33+
QgsFeatureSink,
34+
QgsField,
35+
QgsGeometry,
36+
QgsFeatureRequest,
37+
QgsDistanceArea,
38+
QgsProcessing,
39+
QgsProcessingParameterString,
40+
QgsProcessingParameterFeatureSource,
41+
QgsProcessingParameterFeatureSink,
42+
QgsSpatialIndex)
3343

3444
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
35-
from processing.core.parameters import ParameterVector
36-
from processing.core.parameters import ParameterString
37-
from processing.core.outputs import OutputVector
38-
from processing.tools import dataobjects, vector
3945

4046
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
4147

@@ -58,16 +64,16 @@ def __init__(self):
5864
super().__init__()
5965

6066
def initAlgorithm(self, config=None):
61-
self.addParameter(ParameterVector(self.LINES,
62-
self.tr('Lines'), [dataobjects.TYPE_VECTOR_LINE]))
63-
self.addParameter(ParameterVector(self.POLYGONS,
64-
self.tr('Polygons'), [dataobjects.TYPE_VECTOR_POLYGON]))
65-
self.addParameter(ParameterString(self.LEN_FIELD,
66-
self.tr('Lines length field name', 'LENGTH')))
67-
self.addParameter(ParameterString(self.COUNT_FIELD,
68-
self.tr('Lines count field name', 'COUNT')))
67+
self.addParameter(QgsProcessingParameterFeatureSource(self.LINES,
68+
self.tr('Lines'), [QgsProcessing.TypeVectorLine]))
69+
self.addParameter(QgsProcessingParameterFeatureSource(self.POLYGONS,
70+
self.tr('Polygons'), [QgsProcessing.TypeVectorPolygon]))
71+
self.addParameter(QgsProcessingParameterString(self.LEN_FIELD,
72+
self.tr('Lines length field name'), defaultValue='LENGTH'))
73+
self.addParameter(QgsProcessingParameterString(self.COUNT_FIELD,
74+
self.tr('Lines count field name'), defaultValue='COUNT'))
6975

70-
self.addOutput(OutputVector(self.OUTPUT, self.tr('Line length'), datatype=[dataobjects.TYPE_VECTOR_POLYGON]))
76+
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Line length'), QgsProcessing.TypeVectorPolygon))
7177

7278
def name(self):
7379
return 'sumlinelengths'
@@ -76,66 +82,73 @@ def displayName(self):
7682
return self.tr('Sum line lengths')
7783

7884
def processAlgorithm(self, parameters, context, feedback):
79-
lineLayer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.LINES), context)
80-
polyLayer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.POLYGONS), context)
81-
lengthFieldName = self.getParameterValue(self.LEN_FIELD)
82-
countFieldName = self.getParameterValue(self.COUNT_FIELD)
83-
84-
(idxLength, fieldList) = vector.findOrCreateField(polyLayer,
85-
polyLayer.fields(), lengthFieldName)
86-
(idxCount, fieldList) = vector.findOrCreateField(polyLayer, fieldList,
87-
countFieldName)
88-
89-
writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fieldList, polyLayer.wkbType(),
90-
polyLayer.crs(), context)
91-
92-
spatialIndex = QgsProcessingUtils.createSpatialIndex(lineLayer, context)
93-
94-
ftLine = QgsFeature()
95-
ftPoly = QgsFeature()
96-
outFeat = QgsFeature()
97-
inGeom = QgsGeometry()
98-
outGeom = QgsGeometry()
85+
line_source = self.parameterAsSource(parameters, self.LINES, context)
86+
poly_source = self.parameterAsSource(parameters, self.POLYGONS, context)
87+
88+
length_field_name = self.parameterAsString(parameters, self.LEN_FIELD, context)
89+
count_field_name = self.parameterAsString(parameters, self.COUNT_FIELD, context)
90+
91+
fields = poly_source.fields()
92+
if fields.lookupField(length_field_name) < 0:
93+
fields.append(QgsField(length_field_name, QVariant.Double))
94+
length_field_index = fields.lookupField(length_field_name)
95+
if fields.lookupField(count_field_name) < 0:
96+
fields.append(QgsField(count_field_name, QVariant.Int))
97+
count_field_index = fields.lookupField(count_field_name)
98+
99+
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
100+
fields, poly_source.wkbType(), poly_source.sourceCrs())
101+
102+
spatialIndex = QgsSpatialIndex(line_source.getFeatures(
103+
QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(poly_source.sourceCrs())))
104+
99105
distArea = QgsDistanceArea()
100106

101-
features = QgsProcessingUtils.getFeatures(polyLayer, context)
102-
total = 100.0 / polyLayer.featureCount() if polyLayer.featureCount() else 0
103-
hasIntersections = False
104-
for current, ftPoly in enumerate(features):
105-
inGeom = ftPoly.geometry()
106-
attrs = ftPoly.attributes()
107+
features = poly_source.getFeatures()
108+
total = 100.0 / poly_source.featureCount() if poly_source.featureCount() else 0
109+
for current, poly_feature in enumerate(features):
110+
if feedback.isCanceled():
111+
break
112+
113+
output_feature = QgsFeature()
107114
count = 0
108115
length = 0
109-
hasIntersections = False
110-
lines = spatialIndex.intersects(inGeom.boundingBox())
111-
engine = None
112-
if len(lines) > 0:
113-
hasIntersections = True
114-
# use prepared geometries for faster intersection tests
115-
engine = QgsGeometry.createGeometryEngine(inGeom.geometry())
116-
engine.prepareGeometry()
117-
118-
if hasIntersections:
119-
request = QgsFeatureRequest().setFilterFids(lines).setSubsetOfAttributes([])
120-
for ftLine in lineLayer.getFeatures(request):
121-
tmpGeom = ftLine.geometry()
122-
if engine.intersects(tmpGeom.geometry()):
123-
outGeom = inGeom.intersection(tmpGeom)
124-
length += distArea.measureLength(outGeom)
125-
count += 1
126-
127-
outFeat.setGeometry(inGeom)
128-
if idxLength == len(attrs):
116+
if poly_feature.hasGeometry():
117+
poly_geom = poly_feature.geometry()
118+
has_intersections = False
119+
lines = spatialIndex.intersects(poly_geom.boundingBox())
120+
engine = None
121+
if len(lines) > 0:
122+
has_intersections = True
123+
# use prepared geometries for faster intersection tests
124+
engine = QgsGeometry.createGeometryEngine(poly_geom.geometry())
125+
engine.prepareGeometry()
126+
127+
if has_intersections:
128+
request = QgsFeatureRequest().setFilterFids(lines).setSubsetOfAttributes([]).setDestinationCrs(poly_source.sourceCrs())
129+
for line_feature in line_source.getFeatures(request):
130+
if feedback.isCanceled():
131+
break
132+
133+
if engine.intersects(line_feature.geometry().geometry()):
134+
outGeom = poly_geom.intersection(line_feature.geometry())
135+
length += distArea.measureLength(outGeom)
136+
count += 1
137+
138+
output_feature.setGeometry(poly_geom)
139+
140+
attrs = poly_feature.attributes()
141+
if length_field_index == len(attrs):
129142
attrs.append(length)
130143
else:
131-
attrs[idxLength] = length
132-
if idxCount == len(attrs):
144+
attrs[length_field_index] = length
145+
if count_field_index == len(attrs):
133146
attrs.append(count)
134147
else:
135-
attrs[idxCount] = count
136-
outFeat.setAttributes(attrs)
137-
writer.addFeature(outFeat, QgsFeatureSink.FastInsert)
148+
attrs[count_field_index] = count
149+
output_feature.setAttributes(attrs)
150+
sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
138151

139152
feedback.setProgress(int(current * total))
140153

141-
del writer
154+
return {self.OUTPUT: dest_id}

‎python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1144,22 +1144,22 @@ tests:
11441144
# OUTPUT:
11451145
# name: expected/line_intersection.gml
11461146
# type: vector
1147-
#
1148-
# - algorithm: qgis:sumlinelengths
1149-
# name: Sum line lengths
1150-
# params:
1151-
# COUNT_FIELD: line_count
1152-
# LEN_FIELD: line_len
1153-
# LINES:
1154-
# name: lines.gml
1155-
# type: vector
1156-
# POLYGONS:
1157-
# name: polys.gml
1158-
# type: vector
1159-
# results:
1160-
# OUTPUT:
1161-
# name: expected/sum_line_length.gml
1162-
# type: vector
1147+
1148+
- algorithm: qgis:sumlinelengths
1149+
name: Sum line lengths
1150+
params:
1151+
COUNT_FIELD: line_count
1152+
LEN_FIELD: line_len
1153+
LINES:
1154+
name: lines.gml
1155+
type: vector
1156+
POLYGONS:
1157+
name: polys.gml
1158+
type: vector
1159+
results:
1160+
OUTPUT:
1161+
name: expected/sum_line_length.gml
1162+
type: vector
11631163

11641164
- algorithm: qgis:delaunaytriangulation
11651165
name: Delaunay triangulation (multipoint data)

0 commit comments

Comments
 (0)
Please sign in to comment.