[processing] restore Shortest path from point to layer

This commit is contained in:
Alexander Bruy 2017-07-16 11:31:11 +03:00
parent c5ed53942c
commit 494ceff3b4
2 changed files with 93 additions and 87 deletions

View File

@ -90,7 +90,7 @@ from .SelectByExpression import SelectByExpression
# from .ServiceAreaFromLayer import ServiceAreaFromLayer # from .ServiceAreaFromLayer import ServiceAreaFromLayer
# from .ServiceAreaFromPoint import ServiceAreaFromPoint # from .ServiceAreaFromPoint import ServiceAreaFromPoint
# from .ShortestPathLayerToPoint import ShortestPathLayerToPoint # from .ShortestPathLayerToPoint import ShortestPathLayerToPoint
# from .ShortestPathPointToLayer import ShortestPathPointToLayer from .ShortestPathPointToLayer import ShortestPathPointToLayer
from .ShortestPathPointToPoint import ShortestPathPointToPoint from .ShortestPathPointToPoint import ShortestPathPointToPoint
from .SimplifyGeometries import SimplifyGeometries from .SimplifyGeometries import SimplifyGeometries
from .Slope import Slope from .Slope import Slope
@ -274,6 +274,7 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
SaveSelectedFeatures(), SaveSelectedFeatures(),
SelectByAttribute(), SelectByAttribute(),
SelectByExpression(), SelectByExpression(),
ShortestPathPointToLayer(),
ShortestPathPointToPoint(), ShortestPathPointToPoint(),
SimplifyGeometries(), SimplifyGeometries(),
Slope(), Slope(),

View File

@ -31,10 +31,24 @@ from collections import OrderedDict
from qgis.PyQt.QtCore import QVariant from qgis.PyQt.QtCore import QVariant
from qgis.PyQt.QtGui import QIcon from qgis.PyQt.QtGui import QIcon
from qgis.core import (QgsWkbTypes, QgsUnitTypes, QgsFeatureSink, QgsFeature, QgsGeometry, QgsPointXY, QgsFields, QgsField, QgsFeatureRequest, from qgis.core import (QgsWkbTypes,
QgsUnitTypes,
QgsFeature,
QgsFeatureSink,
QgsGeometry,
QgsFields,
QgsField,
QgsMessageLog, QgsMessageLog,
QgsProcessingParameterDefinition, QgsProcessing,
QgsProcessingUtils) QgsProcessingParameterEnum,
QgsProcessingParameterPoint,
QgsProcessingParameterField,
QgsProcessingParameterNumber,
QgsProcessingParameterString,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink,
QgsProcessingParameterVectorLayer,
QgsProcessingParameterDefinition)
from qgis.analysis import (QgsVectorLayerDirector, from qgis.analysis import (QgsVectorLayerDirector,
QgsNetworkDistanceStrategy, QgsNetworkDistanceStrategy,
QgsNetworkSpeedStrategy, QgsNetworkSpeedStrategy,
@ -44,22 +58,13 @@ from qgis.analysis import (QgsVectorLayerDirector,
from qgis.utils import iface from qgis.utils import iface
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.parameters import (ParameterVector,
ParameterPoint,
ParameterNumber,
ParameterString,
ParameterTableField,
ParameterSelection
)
from processing.core.outputs import OutputVector
from processing.tools import dataobjects
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
class ShortestPathPointToLayer(QgisAlgorithm): class ShortestPathPointToLayer(QgisAlgorithm):
INPUT_VECTOR = 'INPUT_VECTOR' INPUT = 'INPUT'
START_POINT = 'START_POINT' START_POINT = 'START_POINT'
END_POINTS = 'END_POINTS' END_POINTS = 'END_POINTS'
STRATEGY = 'STRATEGY' STRATEGY = 'STRATEGY'
@ -71,7 +76,7 @@ class ShortestPathPointToLayer(QgisAlgorithm):
SPEED_FIELD = 'SPEED_FIELD' SPEED_FIELD = 'SPEED_FIELD'
DEFAULT_SPEED = 'DEFAULT_SPEED' DEFAULT_SPEED = 'DEFAULT_SPEED'
TOLERANCE = 'TOLERANCE' TOLERANCE = 'TOLERANCE'
OUTPUT_LAYER = 'OUTPUT_LAYER' OUTPUT = 'OUTPUT'
def icon(self): def icon(self):
return QIcon(os.path.join(pluginPath, 'images', 'networkanalysis.svg')) return QIcon(os.path.join(pluginPath, 'images', 'networkanalysis.svg'))
@ -92,58 +97,59 @@ class ShortestPathPointToLayer(QgisAlgorithm):
self.tr('Fastest') self.tr('Fastest')
] ]
self.addParameter(ParameterVector(self.INPUT_VECTOR, self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT,
self.tr('Vector layer representing network'), self.tr('Vector layer representing network'),
[dataobjects.TYPE_VECTOR_LINE])) [QgsProcessing.TypeVectorLine]))
self.addParameter(ParameterPoint(self.START_POINT, self.addParameter(QgsProcessingParameterPoint(self.START_POINT,
self.tr('Start point'))) self.tr('Start point')))
self.addParameter(ParameterVector(self.END_POINTS, self.addParameter(QgsProcessingParameterFeatureSource(self.END_POINTS,
self.tr('Vector layer with end points'), self.tr('Vector layer with end points'),
[dataobjects.TYPE_VECTOR_POINT])) [QgsProcessing.TypeVectorPoint]))
self.addParameter(ParameterSelection(self.STRATEGY, self.addParameter(QgsProcessingParameterEnum(self.STRATEGY,
self.tr('Path type to calculate'), self.tr('Path type to calculate'),
self.STRATEGIES, self.STRATEGIES,
default=0)) defaultValue=0))
params = [] params = []
params.append(ParameterTableField(self.DIRECTION_FIELD, params.append(QgsProcessingParameterField(self.DIRECTION_FIELD,
self.tr('Direction field'), self.tr('Direction field'),
self.INPUT_VECTOR, None,
optional=True)) self.INPUT,
params.append(ParameterString(self.VALUE_FORWARD, optional=True))
self.tr('Value for forward direction'), params.append(QgsProcessingParameterString(self.VALUE_FORWARD,
'', self.tr('Value for forward direction'),
optional=True)) optional=True))
params.append(ParameterString(self.VALUE_BACKWARD, params.append(QgsProcessingParameterString(self.VALUE_BACKWARD,
self.tr('Value for backward direction'), self.tr('Value for backward direction'),
'', optional=True))
optional=True)) params.append(QgsProcessingParameterString(self.VALUE_BOTH,
params.append(ParameterString(self.VALUE_BOTH, self.tr('Value for both directions'),
self.tr('Value for both directions'), optional=True))
'', params.append(QgsProcessingParameterEnum(self.DEFAULT_DIRECTION,
optional=True)) self.tr('Default direction'),
params.append(ParameterSelection(self.DEFAULT_DIRECTION, list(self.DIRECTIONS.keys()),
self.tr('Default direction'), defaultValue=2))
list(self.DIRECTIONS.keys()), params.append(QgsProcessingParameterField(self.SPEED_FIELD,
default=2)) self.tr('Speed field'),
params.append(ParameterTableField(self.SPEED_FIELD, None,
self.tr('Speed field'), self.INPUT,
self.INPUT_VECTOR, optional=True))
optional=True)) params.append(QgsProcessingParameterNumber(self.DEFAULT_SPEED,
params.append(ParameterNumber(self.DEFAULT_SPEED, self.tr('Default speed (km/h)'),
self.tr('Default speed (km/h)'), QgsProcessingParameterNumber.Double,
0.0, 99999999.999999, 5.0)) 5.0, False, 0, 99999999.99))
params.append(ParameterNumber(self.TOLERANCE, params.append(QgsProcessingParameterNumber(self.TOLERANCE,
self.tr('Topology tolerance'), self.tr('Topology tolerance'),
0.0, 99999999.999999, 0.0)) QgsProcessingParameterNumber.Double,
0.0, False, 0, 99999999.99))
for p in params: for p in params:
p.setFlags(p.flags() | QgsProcessingParameterDefinition.FlagAdvanced) p.setFlags(p.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
self.addParameter(p) self.addParameter(p)
self.addOutput(OutputVector(self.OUTPUT_LAYER, self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT,
self.tr('Shortest path'), self.tr('Shortest path'),
datatype=[dataobjects.TYPE_VECTOR_LINE])) QgsProcessing.TypeVectorLine))
def name(self): def name(self):
return 'shortestpathpointtolayer' return 'shortestpathpointtolayer'
@ -152,21 +158,19 @@ class ShortestPathPointToLayer(QgisAlgorithm):
return self.tr('Shortest path (point to layer)') return self.tr('Shortest path (point to layer)')
def processAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_VECTOR), context) layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
startPoint = self.getParameterValue(self.START_POINT) startPoint = self.parameterAsPoint(parameters, self.START_POINT, context)
endPoints = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.END_POINTS), context) endPoints = self.parameterAsSource(parameters, self.END_POINTS, context)
strategy = self.getParameterValue(self.STRATEGY) strategy = self.parameterAsEnum(parameters, self.STRATEGY, context)
directionFieldName = self.getParameterValue(self.DIRECTION_FIELD) directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context)
forwardValue = self.getParameterValue(self.VALUE_FORWARD) forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context)
backwardValue = self.getParameterValue(self.VALUE_BACKWARD) backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context)
bothValue = self.getParameterValue(self.VALUE_BOTH) bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context)
defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION) defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context)
bothValue = self.getParameterValue(self.VALUE_BOTH) speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context)
defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION) defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context)
speedFieldName = self.getParameterValue(self.SPEED_FIELD) tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context)
defaultSpeed = self.getParameterValue(self.DEFAULT_SPEED)
tolerance = self.getParameterValue(self.TOLERANCE)
fields = QgsFields() fields = QgsFields()
fields.append(QgsField('start', QVariant.String, '', 254, 0)) fields.append(QgsField('start', QVariant.String, '', 254, 0))
@ -176,17 +180,14 @@ class ShortestPathPointToLayer(QgisAlgorithm):
feat = QgsFeature() feat = QgsFeature()
feat.setFields(fields) feat.setFields(fields)
writer = self.getOutputFromName( (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.OUTPUT_LAYER).getVectorWriter(fields, QgsWkbTypes.LineString, layer.crs(), context) fields, QgsWkbTypes.LineString, layer.crs())
tmp = startPoint.split(',')
startPoint = QgsPointXY(float(tmp[0]), float(tmp[1]))
directionField = -1 directionField = -1
if directionFieldName is not None: if directionFieldName:
directionField = layer.fields().lookupField(directionFieldName) directionField = layer.fields().lookupField(directionFieldName)
speedField = -1 speedField = -1
if speedFieldName is not None: if speedFieldName:
speedField = layer.fields().lookupField(speedFieldName) speedField = layer.fields().lookupField(speedFieldName)
director = QgsVectorLayerDirector(layer, director = QgsVectorLayerDirector(layer,
@ -214,12 +215,16 @@ class ShortestPathPointToLayer(QgisAlgorithm):
feedback.pushInfo(self.tr('Loading end points...')) feedback.pushInfo(self.tr('Loading end points...'))
request = QgsFeatureRequest() request = QgsFeatureRequest()
request.setFlags(request.flags() ^ QgsFeatureRequest.SubsetOfAttributes) request.setFlags(request.flags() ^ QgsFeatureRequest.SubsetOfAttributes)
features = QgsProcessingUtils.getFeatures(endPoints, context, request) features = source.getFeatures(request)
count = QgsProcessingUtils.featureCount(endPoints, context) total = 100.0 / source.featureCount() if source.featureCount() else 0
points = [startPoint] points = [startPoint]
for f in features: for current, f in enumerate(features):
if feedback.isCanceled():
break
points.append(f.geometry().asPoint()) points.append(f.geometry().asPoint())
feedback.setProgress(int(current * total))
feedback.pushInfo(self.tr('Building graph...')) feedback.pushInfo(self.tr('Building graph...'))
snappedPoints = director.makeGraph(builder, points) snappedPoints = director.makeGraph(builder, points)
@ -231,7 +236,7 @@ class ShortestPathPointToLayer(QgisAlgorithm):
tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0) tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
route = [] route = []
total = 100.0 / count if count else 1 total = 100.0 / source.featureCount() if source.featureCount() else 1
for i in range(1, count + 1): for i in range(1, count + 1):
idxEnd = graph.findVertex(snappedPoints[i]) idxEnd = graph.findVertex(snappedPoints[i])
@ -256,10 +261,10 @@ class ShortestPathPointToLayer(QgisAlgorithm):
feat['start'] = startPoint.toString() feat['start'] = startPoint.toString()
feat['end'] = points[i].toString() feat['end'] = points[i].toString()
feat['cost'] = cost / multiplier feat['cost'] = cost / multiplier
writer.addFeature(feat, QgsFeatureSink.FastInsert) sink.addFeature(feat, QgsFeatureSink.FastInsert)
route[:] = [] route[:] = []
feedback.setProgress(int(i * total)) feedback.setProgress(int(i * total))
del writer return {self.OUTPUT: dest_id}