Skip to content
Permalink
Browse files

Merge pull request #4860 from nyalldawson/sum_lines

Port sum line length algorithm to new API
  • Loading branch information
nyalldawson committed Jul 15, 2017
2 parents 2230597 + 2e8b848 commit bbe466ff984d63358b9611c8f21223dbf23d5dd2
@@ -79,14 +79,14 @@
from .Smooth import Smooth
from .SnapGeometries import SnapGeometriesToLayer
from .SpatialiteExecuteSQL import SpatialiteExecuteSQL
from .SumLines import SumLines
from .SymmetricalDifference import SymmetricalDifference
from .Union import Union
from .VectorSplit import VectorSplit
from .VoronoiPolygons import VoronoiPolygons
from .ZonalStatistics import ZonalStatistics

# from .ExtractByLocation import ExtractByLocation
# from .SumLines import SumLines
# from .NearestNeighbourAnalysis import NearestNeighbourAnalysis
# from .LinesIntersection import LinesIntersection
# from .MeanCoords import MeanCoords
@@ -183,8 +183,7 @@ def __init__(self):
self.externalAlgs = []

def getAlgs(self):
# algs = [SumLines(),
# NearestNeighbourAnalysis(), MeanCoords(),
# algs = [NearestNeighbourAnalysis(), MeanCoords(),
# LinesIntersection(), UniqueValues(), PointDistance(),
# ExportGeometryInfo(),
# SinglePartsToMultiparts(),
@@ -274,6 +273,7 @@ def getAlgs(self):
Smooth(),
SnapGeometriesToLayer(),
SpatialiteExecuteSQL(),
SumLines(),
SymmetricalDifference(),
Union(),
VectorSplit(),
@@ -28,14 +28,20 @@
import os

from qgis.PyQt.QtGui import QIcon

from qgis.core import QgsFeature, QgsFeatureSink, QgsGeometry, QgsFeatureRequest, QgsDistanceArea, QgsProcessingUtils
from qgis.PyQt.QtCore import QVariant
from qgis.core import (QgsFeature,
QgsFeatureSink,
QgsField,
QgsGeometry,
QgsFeatureRequest,
QgsDistanceArea,
QgsProcessing,
QgsProcessingParameterString,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink,
QgsSpatialIndex)

from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.parameters import ParameterVector
from processing.core.parameters import ParameterString
from processing.core.outputs import OutputVector
from processing.tools import dataobjects, vector

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

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

def initAlgorithm(self, config=None):
self.addParameter(ParameterVector(self.LINES,
self.tr('Lines'), [dataobjects.TYPE_VECTOR_LINE]))
self.addParameter(ParameterVector(self.POLYGONS,
self.tr('Polygons'), [dataobjects.TYPE_VECTOR_POLYGON]))
self.addParameter(ParameterString(self.LEN_FIELD,
self.tr('Lines length field name', 'LENGTH')))
self.addParameter(ParameterString(self.COUNT_FIELD,
self.tr('Lines count field name', 'COUNT')))
self.addParameter(QgsProcessingParameterFeatureSource(self.LINES,
self.tr('Lines'), [QgsProcessing.TypeVectorLine]))
self.addParameter(QgsProcessingParameterFeatureSource(self.POLYGONS,
self.tr('Polygons'), [QgsProcessing.TypeVectorPolygon]))
self.addParameter(QgsProcessingParameterString(self.LEN_FIELD,
self.tr('Lines length field name'), defaultValue='LENGTH'))
self.addParameter(QgsProcessingParameterString(self.COUNT_FIELD,
self.tr('Lines count field name'), defaultValue='COUNT'))

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

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

def processAlgorithm(self, parameters, context, feedback):
lineLayer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.LINES), context)
polyLayer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.POLYGONS), context)
lengthFieldName = self.getParameterValue(self.LEN_FIELD)
countFieldName = self.getParameterValue(self.COUNT_FIELD)

(idxLength, fieldList) = vector.findOrCreateField(polyLayer,
polyLayer.fields(), lengthFieldName)
(idxCount, fieldList) = vector.findOrCreateField(polyLayer, fieldList,
countFieldName)

writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fieldList, polyLayer.wkbType(),
polyLayer.crs(), context)

spatialIndex = QgsProcessingUtils.createSpatialIndex(lineLayer, context)

ftLine = QgsFeature()
ftPoly = QgsFeature()
outFeat = QgsFeature()
inGeom = QgsGeometry()
outGeom = QgsGeometry()
line_source = self.parameterAsSource(parameters, self.LINES, context)
poly_source = self.parameterAsSource(parameters, self.POLYGONS, context)

length_field_name = self.parameterAsString(parameters, self.LEN_FIELD, context)
count_field_name = self.parameterAsString(parameters, self.COUNT_FIELD, context)

fields = poly_source.fields()
if fields.lookupField(length_field_name) < 0:
fields.append(QgsField(length_field_name, QVariant.Double))
length_field_index = fields.lookupField(length_field_name)
if fields.lookupField(count_field_name) < 0:
fields.append(QgsField(count_field_name, QVariant.Int))
count_field_index = fields.lookupField(count_field_name)

(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, poly_source.wkbType(), poly_source.sourceCrs())

spatialIndex = QgsSpatialIndex(line_source.getFeatures(
QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(poly_source.sourceCrs())))

distArea = QgsDistanceArea()

features = QgsProcessingUtils.getFeatures(polyLayer, context)
total = 100.0 / polyLayer.featureCount() if polyLayer.featureCount() else 0
hasIntersections = False
for current, ftPoly in enumerate(features):
inGeom = ftPoly.geometry()
attrs = ftPoly.attributes()
features = poly_source.getFeatures()
total = 100.0 / poly_source.featureCount() if poly_source.featureCount() else 0
for current, poly_feature in enumerate(features):
if feedback.isCanceled():
break

output_feature = QgsFeature()
count = 0
length = 0
hasIntersections = False
lines = spatialIndex.intersects(inGeom.boundingBox())
engine = None
if len(lines) > 0:
hasIntersections = True
# use prepared geometries for faster intersection tests
engine = QgsGeometry.createGeometryEngine(inGeom.geometry())
engine.prepareGeometry()

if hasIntersections:
request = QgsFeatureRequest().setFilterFids(lines).setSubsetOfAttributes([])
for ftLine in lineLayer.getFeatures(request):
tmpGeom = ftLine.geometry()
if engine.intersects(tmpGeom.geometry()):
outGeom = inGeom.intersection(tmpGeom)
length += distArea.measureLength(outGeom)
count += 1

outFeat.setGeometry(inGeom)
if idxLength == len(attrs):
if poly_feature.hasGeometry():
poly_geom = poly_feature.geometry()
has_intersections = False
lines = spatialIndex.intersects(poly_geom.boundingBox())
engine = None
if len(lines) > 0:
has_intersections = True
# use prepared geometries for faster intersection tests
engine = QgsGeometry.createGeometryEngine(poly_geom.geometry())
engine.prepareGeometry()

if has_intersections:
request = QgsFeatureRequest().setFilterFids(lines).setSubsetOfAttributes([]).setDestinationCrs(poly_source.sourceCrs())
for line_feature in line_source.getFeatures(request):
if feedback.isCanceled():
break

if engine.intersects(line_feature.geometry().geometry()):
outGeom = poly_geom.intersection(line_feature.geometry())
length += distArea.measureLength(outGeom)
count += 1

output_feature.setGeometry(poly_geom)

attrs = poly_feature.attributes()
if length_field_index == len(attrs):
attrs.append(length)
else:
attrs[idxLength] = length
if idxCount == len(attrs):
attrs[length_field_index] = length
if count_field_index == len(attrs):
attrs.append(count)
else:
attrs[idxCount] = count
outFeat.setAttributes(attrs)
writer.addFeature(outFeat, QgsFeatureSink.FastInsert)
attrs[count_field_index] = count
output_feature.setAttributes(attrs)
sink.addFeature(output_feature, QgsFeatureSink.FastInsert)

feedback.setProgress(int(current * total))

del writer
return {self.OUTPUT: dest_id}
@@ -1144,22 +1144,22 @@ tests:
# OUTPUT:
# name: expected/line_intersection.gml
# type: vector
#
# - algorithm: qgis:sumlinelengths
# name: Sum line lengths
# params:
# COUNT_FIELD: line_count
# LEN_FIELD: line_len
# LINES:
# name: lines.gml
# type: vector
# POLYGONS:
# name: polys.gml
# type: vector
# results:
# OUTPUT:
# name: expected/sum_line_length.gml
# type: vector

- algorithm: qgis:sumlinelengths
name: Sum line lengths
params:
COUNT_FIELD: line_count
LEN_FIELD: line_len
LINES:
name: lines.gml
type: vector
POLYGONS:
name: polys.gml
type: vector
results:
OUTPUT:
name: expected/sum_line_length.gml
type: vector

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

0 comments on commit bbe466f

Please sign in to comment.
You can’t perform that action at this time.