diff --git a/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py b/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py index dfc6305dfdc..83ce8145ffa 100644 --- a/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py +++ b/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py @@ -89,7 +89,7 @@ from .SelectByAttribute import SelectByAttribute from .SelectByExpression import SelectByExpression # from .ServiceAreaFromLayer import ServiceAreaFromLayer # from .ServiceAreaFromPoint import ServiceAreaFromPoint -# from .ShortestPathLayerToPoint import ShortestPathLayerToPoint +from .ShortestPathLayerToPoint import ShortestPathLayerToPoint from .ShortestPathPointToLayer import ShortestPathPointToLayer from .ShortestPathPointToPoint import ShortestPathPointToPoint from .SimplifyGeometries import SimplifyGeometries @@ -274,6 +274,7 @@ class QGISAlgorithmProvider(QgsProcessingProvider): SaveSelectedFeatures(), SelectByAttribute(), SelectByExpression(), + ShortestPathLayerToPoint(), ShortestPathPointToLayer(), ShortestPathPointToPoint(), SimplifyGeometries(), diff --git a/python/plugins/processing/algs/qgis/ShortestPathLayerToPoint.py b/python/plugins/processing/algs/qgis/ShortestPathLayerToPoint.py index 87948058ed5..5f97db978d1 100644 --- a/python/plugins/processing/algs/qgis/ShortestPathLayerToPoint.py +++ b/python/plugins/processing/algs/qgis/ShortestPathLayerToPoint.py @@ -36,13 +36,19 @@ from qgis.core import (QgsWkbTypes, QgsFeature, QgsFeatureSink, QgsGeometry, - QgsPointXY, QgsFields, QgsField, - QgsFeatureRequest, QgsMessageLog, - QgsProcessingParameterDefinition, - QgsProcessingUtils) + QgsProcessing, + QgsProcessingParameterEnum, + QgsProcessingParameterPoint, + QgsProcessingParameterField, + QgsProcessingParameterNumber, + QgsProcessingParameterString, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterFeatureSink, + QgsProcessingParameterVectorLayer, + QgsProcessingParameterDefinition) from qgis.analysis import (QgsVectorLayerDirector, QgsNetworkDistanceStrategy, QgsNetworkSpeedStrategy, @@ -52,23 +58,14 @@ from qgis.analysis import (QgsVectorLayerDirector, from qgis.utils import iface 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] class ShortestPathLayerToPoint(QgisAlgorithm): - INPUT_VECTOR = 'INPUT_VECTOR' - START_POINTS = 'START_POINT' + INPUT = 'INPUT' + START_POINTS = 'START_POINTS' END_POINT = 'END_POINT' STRATEGY = 'STRATEGY' DIRECTION_FIELD = 'DIRECTION_FIELD' @@ -79,7 +76,7 @@ class ShortestPathLayerToPoint(QgisAlgorithm): SPEED_FIELD = 'SPEED_FIELD' DEFAULT_SPEED = 'DEFAULT_SPEED' TOLERANCE = 'TOLERANCE' - OUTPUT_LAYER = 'OUTPUT_LAYER' + OUTPUT = 'OUTPUT' def icon(self): return QIcon(os.path.join(pluginPath, 'images', 'networkanalysis.svg')) @@ -100,58 +97,59 @@ class ShortestPathLayerToPoint(QgisAlgorithm): self.tr('Fastest') ] - self.addParameter(ParameterVector(self.INPUT_VECTOR, - self.tr('Vector layer representing network'), - [dataobjects.TYPE_VECTOR_LINE])) - self.addParameter(ParameterVector(self.START_POINTS, - self.tr('Vector layer with start points'), - [dataobjects.TYPE_VECTOR_POINT])) - self.addParameter(ParameterPoint(self.END_POINT, - self.tr('End point'))) - self.addParameter(ParameterSelection(self.STRATEGY, - self.tr('Path type to calculate'), - self.STRATEGIES, - default=0)) + self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT, + self.tr('Vector layer representing network'), + [QgsProcessing.TypeVectorLine])) + self.addParameter(QgsProcessingParameterFeatureSource(self.START_POINTS, + self.tr('Vector layer with start points'), + [QgsProcessing.TypeVectorPoint])) + self.addParameter(QgsProcessingParameterPoint(self.END_POINT, + self.tr('End point'))) + self.addParameter(QgsProcessingParameterEnum(self.STRATEGY, + self.tr('Path type to calculate'), + self.STRATEGIES, + defaultValue=0)) params = [] - params.append(ParameterTableField(self.DIRECTION_FIELD, - self.tr('Direction field'), - self.INPUT_VECTOR, - optional=True)) - params.append(ParameterString(self.VALUE_FORWARD, - self.tr('Value for forward direction'), - '', - optional=True)) - params.append(ParameterString(self.VALUE_BACKWARD, - self.tr('Value for backward direction'), - '', - optional=True)) - params.append(ParameterString(self.VALUE_BOTH, - self.tr('Value for both directions'), - '', - optional=True)) - params.append(ParameterSelection(self.DEFAULT_DIRECTION, - self.tr('Default direction'), - list(self.DIRECTIONS.keys()), - default=2)) - params.append(ParameterTableField(self.SPEED_FIELD, - self.tr('Speed field'), - self.INPUT_VECTOR, - optional=True)) - params.append(ParameterNumber(self.DEFAULT_SPEED, - self.tr('Default speed (km/h)'), - 0.0, 99999999.999999, 5.0)) - params.append(ParameterNumber(self.TOLERANCE, - self.tr('Topology tolerance'), - 0.0, 99999999.999999, 0.0)) + params.append(QgsProcessingParameterField(self.DIRECTION_FIELD, + self.tr('Direction field'), + None, + self.INPUT, + optional=True)) + params.append(QgsProcessingParameterString(self.VALUE_FORWARD, + self.tr('Value for forward direction'), + optional=True)) + params.append(QgsProcessingParameterString(self.VALUE_BACKWARD, + self.tr('Value for backward direction'), + optional=True)) + params.append(QgsProcessingParameterString(self.VALUE_BOTH, + self.tr('Value for both directions'), + optional=True)) + params.append(QgsProcessingParameterEnum(self.DEFAULT_DIRECTION, + self.tr('Default direction'), + list(self.DIRECTIONS.keys()), + defaultValue=2)) + params.append(QgsProcessingParameterField(self.SPEED_FIELD, + self.tr('Speed field'), + None, + self.INPUT, + optional=True)) + params.append(QgsProcessingParameterNumber(self.DEFAULT_SPEED, + self.tr('Default speed (km/h)'), + QgsProcessingParameterNumber.Double, + 5.0, False, 0, 99999999.99)) + params.append(QgsProcessingParameterNumber(self.TOLERANCE, + self.tr('Topology tolerance'), + QgsProcessingParameterNumber.Double, + 0.0, False, 0, 99999999.99)) for p in params: p.setFlags(p.flags() | QgsProcessingParameterDefinition.FlagAdvanced) self.addParameter(p) - self.addOutput(OutputVector(self.OUTPUT_LAYER, - self.tr('Shortest path'), - datatype=[dataobjects.TYPE_VECTOR_LINE])) + self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, + self.tr('Shortest path'), + QgsProcessing.TypeVectorLine)) def name(self): return 'shortestpathlayertopoint' @@ -160,21 +158,19 @@ class ShortestPathLayerToPoint(QgisAlgorithm): return self.tr('Shortest path (layer to point)') def processAlgorithm(self, parameters, context, feedback): - layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_VECTOR), context) - startPoints = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.START_POINTS), context) - endPoint = self.getParameterValue(self.END_POINT) - strategy = self.getParameterValue(self.STRATEGY) + layer = self.parameterAsVectorLayer(parameters, self.INPUT, context) + startPoints = self.parameterAsSource(parameters, self.START_POINTS, context) + endPoint = self.parameterAsPoint(parameters, self.END_POINT, context) + strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) - directionFieldName = self.getParameterValue(self.DIRECTION_FIELD) - forwardValue = self.getParameterValue(self.VALUE_FORWARD) - backwardValue = self.getParameterValue(self.VALUE_BACKWARD) - bothValue = self.getParameterValue(self.VALUE_BOTH) - defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION) - bothValue = self.getParameterValue(self.VALUE_BOTH) - defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION) - speedFieldName = self.getParameterValue(self.SPEED_FIELD) - defaultSpeed = self.getParameterValue(self.DEFAULT_SPEED) - tolerance = self.getParameterValue(self.TOLERANCE) + directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context) + forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context) + backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context) + bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context) + defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context) + speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context) + defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context) + tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) fields = QgsFields() fields.append(QgsField('start', QVariant.String, '', 254, 0)) @@ -184,17 +180,14 @@ class ShortestPathLayerToPoint(QgisAlgorithm): feat = QgsFeature() feat.setFields(fields) - writer = self.getOutputFromName( - self.OUTPUT_LAYER).getVectorWriter(fields, QgsWkbTypes.LineString, layer.crs(), context) - - tmp = endPoint.split(',') - endPoint = QgsPointXY(float(tmp[0]), float(tmp[1])) + (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, + fields, QgsWkbTypes.LineString, layer.crs()) directionField = -1 - if directionFieldName is not None: + if directionFieldName: directionField = layer.fields().lookupField(directionFieldName) speedField = -1 - if speedFieldName is not None: + if speedFieldName: speedField = layer.fields().lookupField(speedFieldName) director = QgsVectorLayerDirector(layer, @@ -222,12 +215,16 @@ class ShortestPathLayerToPoint(QgisAlgorithm): feedback.pushInfo(self.tr('Loading start points...')) request = QgsFeatureRequest() request.setFlags(request.flags() ^ QgsFeatureRequest.SubsetOfAttributes) - features = QgsProcessingUtils.getFeatures(startPoints, context, request) - count = QgsProcessingUtils.featureCount(startPoints, context) + features = source.getFeatures(request) + total = 100.0 / source.featureCount() if source.featureCount() else 0 points = [endPoint] - for f in features: + for current, f in enumerate(features): + if feedback.isCanceled(): + break + points.append(f.geometry().asPoint()) + feedback.setProgress(int(current * total)) feedback.pushInfo(self.tr('Building graph...')) snappedPoints = director.makeGraph(builder, points) @@ -238,7 +235,7 @@ class ShortestPathLayerToPoint(QgisAlgorithm): idxEnd = graph.findVertex(snappedPoints[0]) 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): idxStart = graph.findVertex(snappedPoints[i]) tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0) @@ -264,10 +261,10 @@ class ShortestPathLayerToPoint(QgisAlgorithm): feat['start'] = points[i].toString() feat['end'] = endPoint.toString() feat['cost'] = cost / multiplier - writer.addFeature(feat, QgsFeatureSink.FastInsert) + sink.addFeature(feat, QgsFeatureSink.FastInsert) route[:] = [] feedback.setProgress(int(i * total)) - del writer + return {self.OUTPUT: dest_id}