diff --git a/images/images.qrc b/images/images.qrc index d59f73da082..c3d94176453 100755 --- a/images/images.qrc +++ b/images/images.qrc @@ -98,6 +98,7 @@ themes/default/algorithms/mAlgorithmMergeLayers.svg themes/default/algorithms/mAlgorithmMultiToSingle.svg themes/default/algorithms/mAlgorithmNearestNeighbour.svg + themes/default/algorithms/mAlgorithmNetworkAnalysis.svg themes/default/algorithms/mAlgorithmPolygonToLine.svg themes/default/algorithms/mAlgorithmRandomPointsWithinPolygon.svg themes/default/algorithms/mAlgorithmRandomPointsWithinExtent.svg diff --git a/images/themes/default/algorithms/mAlgorithmNetworkAnalysis.svg b/images/themes/default/algorithms/mAlgorithmNetworkAnalysis.svg new file mode 100644 index 00000000000..1ecbadb6fa9 --- /dev/null +++ b/images/themes/default/algorithms/mAlgorithmNetworkAnalysis.svg @@ -0,0 +1,798 @@ + + + + + Fast road + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + Fast road + 2012-08-13 + + + Robert Szczepanek + + + + + Robert Szczepanek + + + + + vector + network + optimization + + + GIS icons 0.2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py b/python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py index 8bc08d0c9f6..6959ad16c6a 100644 --- a/python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py +++ b/python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py @@ -125,9 +125,6 @@ from .SetMValue import SetMValue from .SetRasterStyle import SetRasterStyle from .SetVectorStyle import SetVectorStyle from .SetZValue import SetZValue -from .ShortestPathLayerToPoint import ShortestPathLayerToPoint -from .ShortestPathPointToLayer import ShortestPathPointToLayer -from .ShortestPathPointToPoint import ShortestPathPointToPoint from .SingleSidedBuffer import SingleSidedBuffer from .Slope import Slope from .SnapGeometries import SnapGeometriesToLayer @@ -239,9 +236,6 @@ class QgisAlgorithmProvider(QgsProcessingProvider): SetRasterStyle(), SetVectorStyle(), SetZValue(), - ShortestPathLayerToPoint(), - ShortestPathPointToLayer(), - ShortestPathPointToPoint(), SingleSidedBuffer(), Slope(), SnapGeometriesToLayer(), diff --git a/python/plugins/processing/algs/qgis/ShortestPathLayerToPoint.py b/python/plugins/processing/algs/qgis/ShortestPathLayerToPoint.py deleted file mode 100644 index 067da78614f..00000000000 --- a/python/plugins/processing/algs/qgis/ShortestPathLayerToPoint.py +++ /dev/null @@ -1,295 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -*************************************************************************** - ShortestPathLayerToPoint.py - --------------------- - Date : December 2016 - Copyright : (C) 2016 by Alexander Bruy - Email : alexander dot bruy at gmail dot com -*************************************************************************** -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * -* * -*************************************************************************** -""" - -__author__ = 'Alexander Bruy' -__date__ = 'December 2016' -__copyright__ = '(C) 2016, Alexander Bruy' - -# This will get replaced with a git SHA1 when you do a git archive - -__revision__ = '$Format:%H$' - -import os -from collections import OrderedDict - -from qgis.PyQt.QtCore import QVariant, QCoreApplication -from qgis.PyQt.QtGui import QIcon - -from qgis.core import (QgsWkbTypes, - QgsUnitTypes, - QgsFeature, - QgsFeatureRequest, - QgsFeatureSink, - QgsGeometry, - QgsField, - QgsPointXY, - QgsProcessing, - QgsProcessingException, - QgsProcessingParameterEnum, - QgsProcessingParameterPoint, - QgsProcessingParameterField, - QgsProcessingParameterNumber, - QgsProcessingParameterDistance, - QgsProcessingParameterString, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterFeatureSink, - QgsProcessingParameterDefinition) -from qgis.analysis import (QgsVectorLayerDirector, - QgsNetworkDistanceStrategy, - QgsNetworkSpeedStrategy, - QgsGraphBuilder, - QgsGraphAnalyzer - ) - -from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm - -pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] - - -class ShortestPathLayerToPoint(QgisAlgorithm): - - INPUT = 'INPUT' - START_POINTS = 'START_POINTS' - END_POINT = 'END_POINT' - STRATEGY = 'STRATEGY' - DIRECTION_FIELD = 'DIRECTION_FIELD' - VALUE_FORWARD = 'VALUE_FORWARD' - VALUE_BACKWARD = 'VALUE_BACKWARD' - VALUE_BOTH = 'VALUE_BOTH' - DEFAULT_DIRECTION = 'DEFAULT_DIRECTION' - SPEED_FIELD = 'SPEED_FIELD' - DEFAULT_SPEED = 'DEFAULT_SPEED' - TOLERANCE = 'TOLERANCE' - OUTPUT = 'OUTPUT' - - def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'networkanalysis.svg')) - - def group(self): - return self.tr('Network analysis') - - def groupId(self): - return 'networkanalysis' - - def __init__(self): - super().__init__() - - def initAlgorithm(self, config=None): - self.DIRECTIONS = OrderedDict([ - (self.tr('Forward direction'), QgsVectorLayerDirector.DirectionForward), - (self.tr('Backward direction'), QgsVectorLayerDirector.DirectionBackward), - (self.tr('Both directions'), QgsVectorLayerDirector.DirectionBoth)]) - - self.STRATEGIES = [self.tr('Shortest'), - self.tr('Fastest') - ] - - self.addParameter(QgsProcessingParameterFeatureSource(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(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(QgsProcessingParameterDistance(self.TOLERANCE, - self.tr('Topology tolerance'), - 0.0, self.INPUT, False, 0, 99999999.99)) - - for p in params: - p.setFlags(p.flags() | QgsProcessingParameterDefinition.FlagAdvanced) - self.addParameter(p) - - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, - self.tr('Shortest path'), - QgsProcessing.TypeVectorLine)) - - def name(self): - return 'shortestpathlayertopoint' - - def displayName(self): - return self.tr('Shortest path (layer to point)') - - def processAlgorithm(self, parameters, context, feedback): - network = self.parameterAsSource(parameters, self.INPUT, context) - if network is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) - - startPoints = self.parameterAsSource(parameters, self.START_POINTS, context) - if startPoints is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.START_POINTS)) - - endPoint = self.parameterAsPoint(parameters, self.END_POINT, context, network.sourceCrs()) - strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) - - 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 = startPoints.fields() - fields.append(QgsField('start', QVariant.String, '', 254, 0)) - fields.append(QgsField('end', QVariant.String, '', 254, 0)) - fields.append(QgsField('cost', QVariant.Double, '', 20, 7)) - - feat = QgsFeature() - feat.setFields(fields) - - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - fields, QgsWkbTypes.LineString, network.sourceCrs()) - if sink is None: - raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) - - directionField = -1 - if directionFieldName: - directionField = network.fields().lookupField(directionFieldName) - speedField = -1 - if speedFieldName: - speedField = network.fields().lookupField(speedFieldName) - - director = QgsVectorLayerDirector(network, - directionField, - forwardValue, - backwardValue, - bothValue, - defaultDirection) - - distUnit = context.project().crs().mapUnits() - multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters) - if strategy == 0: - strategy = QgsNetworkDistanceStrategy() - else: - strategy = QgsNetworkSpeedStrategy(speedField, - defaultSpeed, - multiplier * 1000.0 / 3600.0) - multiplier = 3600 - - director.addStrategy(strategy) - builder = QgsGraphBuilder(network.sourceCrs(), - True, - tolerance) - - feedback.pushInfo(QCoreApplication.translate('ShortestPathLayerToPoint', 'Loading start points…')) - request = QgsFeatureRequest() - request.setDestinationCrs(network.sourceCrs(), context.transformContext()) - features = startPoints.getFeatures(request) - total = 100.0 / startPoints.featureCount() if startPoints.featureCount() else 0 - - points = [endPoint] - source_attributes = {} - i = 1 - for current, f in enumerate(features): - if feedback.isCanceled(): - break - - if not f.hasGeometry(): - continue - - for p in f.geometry().vertices(): - points.append(QgsPointXY(p)) - source_attributes[i] = f.attributes() - i += 1 - - feedback.setProgress(int(current * total)) - - feedback.pushInfo(QCoreApplication.translate('ShortestPathLayerToPoint', 'Building graph…')) - snappedPoints = director.makeGraph(builder, points, feedback) - - feedback.pushInfo(QCoreApplication.translate('ShortestPathLayerToPoint', 'Calculating shortest paths…')) - graph = builder.graph() - - idxEnd = graph.findVertex(snappedPoints[0]) - - nPoints = len(snappedPoints) - total = 100.0 / nPoints if nPoints else 1 - for i in range(1, nPoints): - if feedback.isCanceled(): - break - - idxStart = graph.findVertex(snappedPoints[i]) - - tree, costs = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0) - - if tree[idxEnd] == -1: - msg = self.tr('There is no route from start point ({}) to end point ({}).'.format(points[i].toString(), endPoint.toString())) - feedback.reportError(msg) - # add feature with no geometry - feat.clearGeometry() - attrs = source_attributes[i] - attrs.append(points[i].toString()) - feat.setAttributes(attrs) - sink.addFeature(feat, QgsFeatureSink.FastInsert) - continue - - route = [graph.vertex(idxEnd).point()] - cost = costs[idxEnd] - current = idxEnd - while current != idxStart: - current = graph.edge(tree[current]).fromVertex() - route.append(graph.vertex(current).point()) - - route.reverse() - - geom = QgsGeometry.fromPolylineXY(route) - feat.setGeometry(geom) - attrs = source_attributes[i] - attrs.extend([points[i].toString(), endPoint.toString(), cost / multiplier]) - feat.setAttributes(attrs) - sink.addFeature(feat, QgsFeatureSink.FastInsert) - - feedback.setProgress(int(i * total)) - - return {self.OUTPUT: dest_id} diff --git a/python/plugins/processing/algs/qgis/ShortestPathPointToLayer.py b/python/plugins/processing/algs/qgis/ShortestPathPointToLayer.py deleted file mode 100644 index 8f59f67c7e4..00000000000 --- a/python/plugins/processing/algs/qgis/ShortestPathPointToLayer.py +++ /dev/null @@ -1,295 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -*************************************************************************** - ShortestPathPointToLayer.py - --------------------- - Date : December 2016 - Copyright : (C) 2016 by Alexander Bruy - Email : alexander dot bruy at gmail dot com -*************************************************************************** -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * -* * -*************************************************************************** -""" - -__author__ = 'Alexander Bruy' -__date__ = 'December 2016' -__copyright__ = '(C) 2016, Alexander Bruy' - -# This will get replaced with a git SHA1 when you do a git archive - -__revision__ = '$Format:%H$' - -import os -from collections import OrderedDict - -from qgis.PyQt.QtCore import QVariant, QCoreApplication -from qgis.PyQt.QtGui import QIcon - -from qgis.core import (NULL, - QgsWkbTypes, - QgsUnitTypes, - QgsFeature, - QgsFeatureSink, - QgsGeometry, - QgsFeatureRequest, - QgsField, - QgsPointXY, - QgsProcessing, - QgsProcessingException, - QgsProcessingParameterEnum, - QgsProcessingParameterDistance, - QgsProcessingParameterPoint, - QgsProcessingParameterField, - QgsProcessingParameterNumber, - QgsProcessingParameterString, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterFeatureSink, - QgsProcessingParameterDefinition) -from qgis.analysis import (QgsVectorLayerDirector, - QgsNetworkDistanceStrategy, - QgsNetworkSpeedStrategy, - QgsGraphBuilder, - QgsGraphAnalyzer - ) - -from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm - -pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] - - -class ShortestPathPointToLayer(QgisAlgorithm): - - INPUT = 'INPUT' - START_POINT = 'START_POINT' - END_POINTS = 'END_POINTS' - STRATEGY = 'STRATEGY' - DIRECTION_FIELD = 'DIRECTION_FIELD' - VALUE_FORWARD = 'VALUE_FORWARD' - VALUE_BACKWARD = 'VALUE_BACKWARD' - VALUE_BOTH = 'VALUE_BOTH' - DEFAULT_DIRECTION = 'DEFAULT_DIRECTION' - SPEED_FIELD = 'SPEED_FIELD' - DEFAULT_SPEED = 'DEFAULT_SPEED' - TOLERANCE = 'TOLERANCE' - OUTPUT = 'OUTPUT' - - def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'networkanalysis.svg')) - - def group(self): - return self.tr('Network analysis') - - def groupId(self): - return 'networkanalysis' - - def __init__(self): - super().__init__() - - def initAlgorithm(self, config=None): - self.DIRECTIONS = OrderedDict([ - (self.tr('Forward direction'), QgsVectorLayerDirector.DirectionForward), - (self.tr('Backward direction'), QgsVectorLayerDirector.DirectionBackward), - (self.tr('Both directions'), QgsVectorLayerDirector.DirectionBoth)]) - - self.STRATEGIES = [self.tr('Shortest'), - self.tr('Fastest') - ] - - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Vector layer representing network'), - [QgsProcessing.TypeVectorLine])) - self.addParameter(QgsProcessingParameterPoint(self.START_POINT, - self.tr('Start point'))) - self.addParameter(QgsProcessingParameterFeatureSource(self.END_POINTS, - self.tr('Vector layer with end points'), - [QgsProcessing.TypeVectorPoint])) - self.addParameter(QgsProcessingParameterEnum(self.STRATEGY, - self.tr('Path type to calculate'), - self.STRATEGIES, - defaultValue=0)) - - params = [] - 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(QgsProcessingParameterDistance(self.TOLERANCE, - self.tr('Topology tolerance'), - 0.0, self.INPUT, False, 0, 99999999.99)) - - for p in params: - p.setFlags(p.flags() | QgsProcessingParameterDefinition.FlagAdvanced) - self.addParameter(p) - - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, - self.tr('Shortest path'), - QgsProcessing.TypeVectorLine)) - - def name(self): - return 'shortestpathpointtolayer' - - def displayName(self): - return self.tr('Shortest path (point to layer)') - - def processAlgorithm(self, parameters, context, feedback): - network = self.parameterAsSource(parameters, self.INPUT, context) - if network is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) - - startPoint = self.parameterAsPoint(parameters, self.START_POINT, context, network.sourceCrs()) - endPoints = self.parameterAsSource(parameters, self.END_POINTS, context) - if endPoints is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.END_POINTS)) - - strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) - - 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 = endPoints.fields() - fields.append(QgsField('start', QVariant.String, '', 254, 0)) - fields.append(QgsField('end', QVariant.String, '', 254, 0)) - fields.append(QgsField('cost', QVariant.Double, '', 20, 7)) - - feat = QgsFeature() - feat.setFields(fields) - - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - fields, QgsWkbTypes.LineString, network.sourceCrs()) - if sink is None: - raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) - - directionField = -1 - if directionFieldName: - directionField = network.fields().lookupField(directionFieldName) - speedField = -1 - if speedFieldName: - speedField = network.fields().lookupField(speedFieldName) - - director = QgsVectorLayerDirector(network, - directionField, - forwardValue, - backwardValue, - bothValue, - defaultDirection) - - distUnit = context.project().crs().mapUnits() - multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters) - if strategy == 0: - strategy = QgsNetworkDistanceStrategy() - else: - strategy = QgsNetworkSpeedStrategy(speedField, - defaultSpeed, - multiplier * 1000.0 / 3600.0) - multiplier = 3600 - - director.addStrategy(strategy) - builder = QgsGraphBuilder(network.sourceCrs(), - True, - tolerance) - - feedback.pushInfo(QCoreApplication.translate('ShortestPathPointToLayer', 'Loading end points…')) - request = QgsFeatureRequest() - request.setDestinationCrs(network.sourceCrs(), context.transformContext()) - features = endPoints.getFeatures(request) - total = 100.0 / endPoints.featureCount() if endPoints.featureCount() else 0 - - points = [startPoint] - source_attributes = {} - i = 1 - for current, f in enumerate(features): - if feedback.isCanceled(): - break - - if not f.hasGeometry(): - continue - - for p in f.geometry().vertices(): - points.append(QgsPointXY(p)) - source_attributes[i] = f.attributes() - i += 1 - - feedback.setProgress(int(current * total)) - - feedback.pushInfo(QCoreApplication.translate('ShortestPathPointToLayer', 'Building graph…')) - snappedPoints = director.makeGraph(builder, points, feedback) - - feedback.pushInfo(QCoreApplication.translate('ShortestPathPointToLayer', 'Calculating shortest paths…')) - graph = builder.graph() - - idxStart = graph.findVertex(snappedPoints[0]) - tree, costs = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0) - - nPoints = len(snappedPoints) - total = 100.0 / nPoints if nPoints else 1 - for i in range(1, nPoints): - if feedback.isCanceled(): - break - - idxEnd = graph.findVertex(snappedPoints[i]) - - if tree[idxEnd] == -1: - msg = self.tr('There is no route from start point ({}) to end point ({}).'.format(startPoint.toString(), points[i].toString())) - feedback.reportError(msg) - # add feature with no geometry - feat.clearGeometry() - attrs = source_attributes[i] - attrs.extend([NULL, points[i].toString()]) - feat.setAttributes(attrs) - sink.addFeature(feat, QgsFeatureSink.FastInsert) - continue - - route = [graph.vertex(idxEnd).point()] - cost = costs[idxEnd] - current = idxEnd - while current != idxStart: - current = graph.edge(tree[current]).fromVertex() - route.append(graph.vertex(current).point()) - - route.reverse() - - geom = QgsGeometry.fromPolylineXY(route) - attrs = source_attributes[i] - attrs.extend([startPoint.toString(), points[i].toString(), cost / multiplier]) - feat.setAttributes(attrs) - feat.setGeometry(geom) - sink.addFeature(feat, QgsFeatureSink.FastInsert) - - feedback.setProgress(int(i * total)) - - return {self.OUTPUT: dest_id} diff --git a/python/plugins/processing/algs/qgis/ShortestPathPointToPoint.py b/python/plugins/processing/algs/qgis/ShortestPathPointToPoint.py deleted file mode 100644 index b86bddbc864..00000000000 --- a/python/plugins/processing/algs/qgis/ShortestPathPointToPoint.py +++ /dev/null @@ -1,255 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -*************************************************************************** - ShortestPathPointToPoint.py - --------------------- - Date : November 2016 - Copyright : (C) 2016 by Alexander Bruy - Email : alexander dot bruy at gmail dot com -*************************************************************************** -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * -* * -*************************************************************************** -""" - -__author__ = 'Alexander Bruy' -__date__ = 'November 2016' -__copyright__ = '(C) 2016, Alexander Bruy' - -# This will get replaced with a git SHA1 when you do a git archive - -__revision__ = '$Format:%H$' - -import os -from collections import OrderedDict - -from qgis.PyQt.QtCore import QVariant, QCoreApplication -from qgis.PyQt.QtGui import QIcon - -from qgis.core import (QgsWkbTypes, - QgsUnitTypes, - QgsFeature, - QgsFeatureSink, - QgsGeometry, - QgsFields, - QgsField, - QgsProcessing, - QgsProcessingException, - QgsProcessingOutputNumber, - QgsProcessingParameterDistance, - QgsProcessingParameterEnum, - QgsProcessingParameterPoint, - QgsProcessingParameterField, - QgsProcessingParameterNumber, - QgsProcessingParameterString, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterFeatureSink, - QgsProcessingParameterDefinition) -from qgis.analysis import (QgsVectorLayerDirector, - QgsNetworkDistanceStrategy, - QgsNetworkSpeedStrategy, - QgsGraphBuilder, - QgsGraphAnalyzer - ) - -from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm - -pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] - - -class ShortestPathPointToPoint(QgisAlgorithm): - - INPUT = 'INPUT' - START_POINT = 'START_POINT' - END_POINT = 'END_POINT' - STRATEGY = 'STRATEGY' - DIRECTION_FIELD = 'DIRECTION_FIELD' - VALUE_FORWARD = 'VALUE_FORWARD' - VALUE_BACKWARD = 'VALUE_BACKWARD' - VALUE_BOTH = 'VALUE_BOTH' - DEFAULT_DIRECTION = 'DEFAULT_DIRECTION' - SPEED_FIELD = 'SPEED_FIELD' - DEFAULT_SPEED = 'DEFAULT_SPEED' - TOLERANCE = 'TOLERANCE' - TRAVEL_COST = 'TRAVEL_COST' - OUTPUT = 'OUTPUT' - - def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'networkanalysis.svg')) - - def group(self): - return self.tr('Network analysis') - - def groupId(self): - return 'networkanalysis' - - def __init__(self): - super().__init__() - - def initAlgorithm(self, config=None): - self.DIRECTIONS = OrderedDict([ - (self.tr('Forward direction'), QgsVectorLayerDirector.DirectionForward), - (self.tr('Backward direction'), QgsVectorLayerDirector.DirectionBackward), - (self.tr('Both directions'), QgsVectorLayerDirector.DirectionBoth)]) - - self.STRATEGIES = [self.tr('Shortest'), - self.tr('Fastest') - ] - - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Vector layer representing network'), - [QgsProcessing.TypeVectorLine])) - self.addParameter(QgsProcessingParameterPoint(self.START_POINT, - self.tr('Start point'))) - 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(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(QgsProcessingParameterDistance(self.TOLERANCE, - self.tr('Topology tolerance'), - 0.0, self.INPUT, False, 0, 99999999.99)) - - for p in params: - p.setFlags(p.flags() | QgsProcessingParameterDefinition.FlagAdvanced) - self.addParameter(p) - - self.addOutput(QgsProcessingOutputNumber(self.TRAVEL_COST, - self.tr('Travel cost'))) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, - self.tr('Shortest path'), - QgsProcessing.TypeVectorLine)) - - def name(self): - return 'shortestpathpointtopoint' - - def displayName(self): - return self.tr('Shortest path (point to point)') - - def processAlgorithm(self, parameters, context, feedback): - network = self.parameterAsSource(parameters, self.INPUT, context) - if network is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) - - startPoint = self.parameterAsPoint(parameters, self.START_POINT, context, network.sourceCrs()) - endPoint = self.parameterAsPoint(parameters, self.END_POINT, context, network.sourceCrs()) - strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) - - 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)) - fields.append(QgsField('end', QVariant.String, '', 254, 0)) - fields.append(QgsField('cost', QVariant.Double, '', 20, 7)) - - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - fields, QgsWkbTypes.LineString, network.sourceCrs()) - if sink is None: - raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) - - directionField = -1 - if directionField: - directionField = network.fields().lookupField(directionFieldName) - speedField = -1 - if speedFieldName: - speedField = network.fields().lookupField(speedFieldName) - - director = QgsVectorLayerDirector(network, - directionField, - forwardValue, - backwardValue, - bothValue, - defaultDirection) - - distUnit = context.project().crs().mapUnits() - multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters) - if strategy == 0: - strategy = QgsNetworkDistanceStrategy() - else: - strategy = QgsNetworkSpeedStrategy(speedField, - defaultSpeed, - multiplier * 1000.0 / 3600.0) - multiplier = 3600 - - director.addStrategy(strategy) - builder = QgsGraphBuilder(network.sourceCrs(), - True, - tolerance) - feedback.pushInfo(QCoreApplication.translate('ShortestPathPointToPoint', 'Building graph…')) - snappedPoints = director.makeGraph(builder, [startPoint, endPoint], feedback) - - feedback.pushInfo(QCoreApplication.translate('ShortestPathPointToPoint', 'Calculating shortest path…')) - graph = builder.graph() - idxStart = graph.findVertex(snappedPoints[0]) - idxEnd = graph.findVertex(snappedPoints[1]) - - tree, costs = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0) - if tree[idxEnd] == -1: - raise QgsProcessingException( - self.tr('There is no route from start point to end point.')) - - route = [graph.vertex(idxEnd).point()] - cost = costs[idxEnd] - current = idxEnd - while current != idxStart: - current = graph.edge(tree[current]).fromVertex() - route.append(graph.vertex(current).point()) - - route.reverse() - - feedback.pushInfo(QCoreApplication.translate('ShortestPathPointToPoint', 'Writing results…')) - geom = QgsGeometry.fromPolylineXY(route) - feat = QgsFeature() - feat.setFields(fields) - feat['start'] = startPoint.toString() - feat['end'] = endPoint.toString() - feat['cost'] = cost / multiplier - feat.setGeometry(geom) - sink.addFeature(feat, QgsFeatureSink.FastInsert) - - results = {} - results[self.TRAVEL_COST] = cost / multiplier - results[self.OUTPUT] = dest_id - return results diff --git a/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml b/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml index d043870663f..91a5ea6d0e2 100644 --- a/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml +++ b/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml @@ -2977,7 +2977,7 @@ tests: name: expected/join_attribute_table_subset.gml type: vector - - algorithm: qgis:shortestpathpointtopoint + - algorithm: native:shortestpathpointtopoint name: Shortest path (point to point, shortest route) params: DEFAULT_DIRECTION: 2 @@ -3006,7 +3006,7 @@ tests: start: skip end: skip - - algorithm: qgis:shortestpathpointtopoint + - algorithm: native:shortestpathpointtopoint name: Shortest path (point to point, fastest route) params: DEFAULT_DIRECTION: 2 @@ -3036,7 +3036,7 @@ tests: start: skip end: skip - - algorithm: qgis:shortestpathlayertopoint + - algorithm: native:shortestpathlayertopoint name: Shortest path layer to point params: DEFAULT_DIRECTION: 2 @@ -3066,7 +3066,7 @@ tests: start: skip end: skip - - algorithm: qgis:shortestpathpointtolayer + - algorithm: native:shortestpathpointtolayer name: Shortest path point to layer params: DEFAULT_DIRECTION: 2 @@ -5799,7 +5799,7 @@ tests: OUTPUT: name: expected/dbscan_multiple_clusters.gml type: vector - + - algorithm: qgis:rastersampling name: Single band raster params: diff --git a/src/analysis/CMakeLists.txt b/src/analysis/CMakeLists.txt index 95805245971..244cbf90fad 100755 --- a/src/analysis/CMakeLists.txt +++ b/src/analysis/CMakeLists.txt @@ -77,6 +77,9 @@ SET(QGIS_ANALYSIS_SRCS processing/qgsalgorithmrotate.cpp processing/qgsalgorithmsaveselectedfeatures.cpp processing/qgsalgorithmsegmentize.cpp + processing/qgsalgorithmshortestpathlayertopoint.cpp + processing/qgsalgorithmshortestpathpointtolayer.cpp + processing/qgsalgorithmshortestpathpointtopoint.cpp processing/qgsalgorithmsimplify.cpp processing/qgsalgorithmsmooth.cpp processing/qgsalgorithmsnaptogrid.cpp @@ -95,6 +98,8 @@ SET(QGIS_ANALYSIS_SRCS processing/qgsalgorithmwedgebuffers.cpp processing/qgsalgorithmzonalhistogram.cpp + processing/qgsalgorithmnetworkanalysisbase.cpp + processing/qgsnativealgorithms.cpp processing/qgsoverlayutils.cpp processing/qgsrasteranalysisutils.cpp diff --git a/src/analysis/processing/qgsalgorithmnetworkanalysisbase.cpp b/src/analysis/processing/qgsalgorithmnetworkanalysisbase.cpp new file mode 100644 index 00000000000..8f788e03c75 --- /dev/null +++ b/src/analysis/processing/qgsalgorithmnetworkanalysisbase.cpp @@ -0,0 +1,166 @@ +/*************************************************************************** + qgsalgorithmnetworkanalysisbase.cpp + --------------------- + begin : July 2018 + copyright : (C) 2018 by Alexander Bruy + email : alexander dot bruy at gmail dot com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "qgsalgorithmnetworkanalysisbase.h" + +#include "qgsgraphanalyzer.h" +#include "qgsnetworkspeedstrategy.h" +#include "qgsnetworkdistancestrategy.h" + +///@cond PRIVATE + +// +// QgsNetworkAnalysisAlgorithmBase +// + +QString QgsNetworkAnalysisAlgorithmBase::group() const +{ + return QObject::tr( "Network analysis" ); +} + +QString QgsNetworkAnalysisAlgorithmBase::groupId() const +{ + return QStringLiteral( "networkanalysis" ); +} + +void QgsNetworkAnalysisAlgorithmBase::addCommonParams() +{ + addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Vector layer representing network" ), QList< int >() << QgsProcessing::TypeVectorLine ) ); + addParameter( new QgsProcessingParameterEnum( QStringLiteral( "STRATEGY" ), QObject::tr( "Path type to calculate" ), QStringList() << QObject::tr( "Shortest" ) << QObject::tr( "Fastest" ), false, 0 ) ); + + std::unique_ptr< QgsProcessingParameterField > directionField = qgis::make_unique< QgsProcessingParameterField >( QStringLiteral( "DIRECTION_FIELD" ), + QObject::tr( "Direction field" ), QVariant(), QStringLiteral( "INPUT" ), QgsProcessingParameterField::Any, false, true ); + directionField->setFlags( directionField->flags() | QgsProcessingParameterDefinition::FlagAdvanced ); + addParameter( directionField.release() ); + + std::unique_ptr< QgsProcessingParameterString > forwardValue = qgis::make_unique< QgsProcessingParameterString >( QStringLiteral( "VALUE_FORWARD" ), + QObject::tr( "Value for forward direction" ), QVariant(), false, true ); + forwardValue->setFlags( forwardValue->flags() | QgsProcessingParameterDefinition::FlagAdvanced ); + addParameter( forwardValue.release() ); + + std::unique_ptr< QgsProcessingParameterString > backwardValue = qgis::make_unique< QgsProcessingParameterString >( QStringLiteral( "VALUE_BACKWARD" ), + QObject::tr( "Value for backward direction" ), QVariant(), false, true ); + backwardValue->setFlags( backwardValue->flags() | QgsProcessingParameterDefinition::FlagAdvanced ); + addParameter( backwardValue.release() ); + + std::unique_ptr< QgsProcessingParameterString > bothValue = qgis::make_unique< QgsProcessingParameterString >( QStringLiteral( "VALUE_BOTH" ), + QObject::tr( "Value for both directions" ), QVariant(), false, true ); + bothValue->setFlags( bothValue->flags() | QgsProcessingParameterDefinition::FlagAdvanced ); + addParameter( bothValue.release() ); + + std::unique_ptr< QgsProcessingParameterEnum > directionValue = qgis::make_unique< QgsProcessingParameterEnum >( QStringLiteral( "DEFAULT_DIRECTION" ), + QObject::tr( "Default direction" ), QStringList() << QObject::tr( "Forward direction" ) << QObject::tr( "Backward direction" ) << QObject::tr( "Both directions" ), false, 2 ); + directionValue->setFlags( directionValue->flags() | QgsProcessingParameterDefinition::FlagAdvanced ); + addParameter( directionValue.release() ); + + std::unique_ptr< QgsProcessingParameterField > speedField = qgis::make_unique< QgsProcessingParameterField >( QStringLiteral( "SPEED_FIELD" ), + QObject::tr( "Speed field" ), QVariant(), QStringLiteral( "INPUT" ), QgsProcessingParameterField::Numeric, false, true ); + speedField->setFlags( speedField->flags() | QgsProcessingParameterDefinition::FlagAdvanced ); + addParameter( speedField.release() ); + + std::unique_ptr< QgsProcessingParameterNumber > speed = qgis::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "DEFAULT_SPEED" ), QObject::tr( "Default speed (km/h)" ), QgsProcessingParameterNumber::Double, 50, false, 0 ); + speed->setFlags( speed->flags() | QgsProcessingParameterDefinition::FlagAdvanced ); + addParameter( speed.release() ); + + std::unique_ptr< QgsProcessingParameterNumber > tolerance = qgis::make_unique < QgsProcessingParameterDistance >( QStringLiteral( "TOLERANCE" ), QObject::tr( "Topology tolerance" ), 0, QStringLiteral( "INPUT" ), false, 0 ); + tolerance->setFlags( tolerance->flags() | QgsProcessingParameterDefinition::FlagAdvanced ); + addParameter( tolerance.release() ); +} + +void QgsNetworkAnalysisAlgorithmBase::loadCommonParams( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) +{ + Q_UNUSED( feedback ); + + mNetwork.reset( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) ); + if ( !mNetwork ) + throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) ); + + int strategy = parameterAsInt( parameters, QStringLiteral( "STRATEGY" ), context ); + QString directionFieldName = parameterAsString( parameters, QStringLiteral( "DIRECTION_FIELD" ), context ); + QString forwardValue = parameterAsString( parameters, QStringLiteral( "VALUE_FORWARD" ), context ); + QString backwardValue = parameterAsString( parameters, QStringLiteral( "VALUE_BACKWARD" ), context ); + QString bothValue = parameterAsString( parameters, QStringLiteral( "VALUE_BOTH" ), context ); + QgsVectorLayerDirector::Direction defaultDirection = static_cast< QgsVectorLayerDirector::Direction>( parameterAsInt( parameters, QStringLiteral( "DEFAULT_DIRECTION" ), context ) ); + QString speedFieldName = parameterAsString( parameters, QStringLiteral( "SPEED_FIELD" ), context ); + double defaultSpeed = parameterAsDouble( parameters, QStringLiteral( "DEFAULT_SPEED" ), context ); + double tolerance = parameterAsDouble( parameters, QStringLiteral( "TOLERANCE" ), context ); + + int directionField = -1; + if ( !directionFieldName.isEmpty() ) + { + directionField = mNetwork->fields().lookupField( directionFieldName ); + } + + int speedField = -1; + if ( !speedFieldName.isEmpty() ) + { + speedField = mNetwork->fields().lookupField( speedFieldName ); + } + + mDirector = new QgsVectorLayerDirector( mNetwork.get(), directionField, forwardValue, backwardValue, bothValue, defaultDirection ); + + QgsUnitTypes::DistanceUnit distanceUnits = context.project()->crs().mapUnits(); + mMultiplier = QgsUnitTypes::fromUnitToUnitFactor( distanceUnits, QgsUnitTypes::DistanceMeters ); + + if ( strategy ) + { + mDirector->addStrategy( new QgsNetworkSpeedStrategy( speedField, defaultSpeed, mMultiplier * 1000.0 / 3600.0 ) ); + mMultiplier = 3600; + } + else + { + mDirector->addStrategy( new QgsNetworkDistanceStrategy() ); + } + + mBuilder = qgis::make_unique< QgsGraphBuilder >( mNetwork->sourceCrs(), true, tolerance ); +} + +void QgsNetworkAnalysisAlgorithmBase::loadPoints( QgsFeatureSource *source, QVector< QgsPointXY > &points, QHash< int, QgsAttributes > &attributes, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) +{ + feedback->pushInfo( QObject::tr( "Loading points…" ) ); + + QgsFeature feat; + int i = 0; + int pointId = 1; + double step = source->featureCount() > 0 ? 100.0 / source->featureCount() : 0; + QgsFeatureIterator features = source->getFeatures( QgsFeatureRequest().setDestinationCrs( mNetwork->sourceCrs(), context.transformContext() ) ); + + while ( features.nextFeature( feat ) ) + { + i++; + if ( feedback->isCanceled() ) + { + break; + } + + feedback->setProgress( i * step ); + if ( !feat.hasGeometry() ) + continue; + + QgsGeometry geom = feat.geometry(); + QgsAbstractGeometry::vertex_iterator it = geom.vertices_begin(); + while ( it != geom.vertices_end() ) + { + points.push_back( QgsPointXY( *it ) ); + attributes.insert( pointId, feat.attributes() ); + it++; + pointId++; + } + } +} + +///@endcond diff --git a/src/analysis/processing/qgsalgorithmnetworkanalysisbase.h b/src/analysis/processing/qgsalgorithmnetworkanalysisbase.h new file mode 100644 index 00000000000..e03dc5c6a3a --- /dev/null +++ b/src/analysis/processing/qgsalgorithmnetworkanalysisbase.h @@ -0,0 +1,71 @@ +/*************************************************************************** + qgsalgorithmnetworkanalysisbase.h + --------------------- + begin : July 2018 + copyright : (C) 2018 by Alexander Bruy + email : alexander dot bruy at gmail dot com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSALGORITHMNETWORKANALYSISBASE_H +#define QGSALGORITHMNETWORKANALYSISBASE_H + +#define SIP_NO_FILE + +#include "qgis.h" +#include "qgsprocessingalgorithm.h" + +#include "qgsgraph.h" +#include "qgsgraphbuilder.h" +#include "qgsvectorlayerdirector.h" + +///@cond PRIVATE + +/** + * Base class for networkanalysis algorithms. + */ +class QgsNetworkAnalysisAlgorithmBase : public QgsProcessingAlgorithm +{ + public: + + QString group() const final; + QString groupId() const final; + QIcon icon() const override { return QgsApplication::getThemeIcon( QStringLiteral( "/algorithms/mAlgorithmNetworkAnalysis.svg" ) ); } + QString svgIconPath() const override { return QgsApplication::iconPath( QStringLiteral( "/algorithms/mAlgorithmNetworkAnalysis.svg" ) ); } + + protected: + + /** + * Adds common algorithm parameters. + */ + void addCommonParams(); + + /** + * Populates common parameters with values. + */ + void loadCommonParams( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ); + + /** + * Loads point from the feature source for further processing. + */ + void loadPoints( QgsFeatureSource *source, QVector< QgsPointXY > &points, QHash< int, QgsAttributes > &attributes, QgsProcessingContext &context, QgsProcessingFeedback *feedback ); + + std::unique_ptr< QgsFeatureSource > mNetwork; + QgsVectorLayerDirector *mDirector = nullptr; + std::unique_ptr< QgsGraphBuilder > mBuilder; + std::unique_ptr< QgsGraph > mGraph; + double mMultiplier = 1; +}; + +///@endcond PRIVATE + +#endif // QGSALGORITHMNETWORKANALYSISBASE_H + diff --git a/src/analysis/processing/qgsalgorithmshortestpathlayertopoint.cpp b/src/analysis/processing/qgsalgorithmshortestpathlayertopoint.cpp new file mode 100644 index 00000000000..578e4c93431 --- /dev/null +++ b/src/analysis/processing/qgsalgorithmshortestpathlayertopoint.cpp @@ -0,0 +1,158 @@ +/*************************************************************************** + qgsalgorithmshortestpathlayertopoint.cpp + --------------------- + begin : July 2018 + copyright : (C) 2018 by Alexander Bruy + email : alexander dot bruy at gmail dot com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "qgsalgorithmshortestpathlayertopoint.h" + +#include "qgsgraphanalyzer.h" + +#include "qgsmessagelog.h" + +///@cond PRIVATE + +QString QgsShortestPathLayerToPointAlgorithm::name() const +{ + return QStringLiteral( "shortestpathlayertopoint" ); +} + +QString QgsShortestPathLayerToPointAlgorithm::displayName() const +{ + return QObject::tr( "Shortest path (layer to point)" ); +} + +QStringList QgsShortestPathLayerToPointAlgorithm::tags() const +{ + return QObject::tr( "network,path,shortest,fastest" ).split( ',' ); +} + +QString QgsShortestPathLayerToPointAlgorithm::shortHelpString() const +{ + return QObject::tr( "This algorithm computes optimal (shortest or fastest) route from multiple start points defined by vector layer and given end point." ); +} + +QgsShortestPathLayerToPointAlgorithm *QgsShortestPathLayerToPointAlgorithm::createInstance() const +{ + return new QgsShortestPathLayerToPointAlgorithm(); +} + +void QgsShortestPathLayerToPointAlgorithm::initAlgorithm( const QVariantMap & ) +{ + addCommonParams(); + addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "START_POINTS" ), QObject::tr( "Vector layer with start points" ), QList< int >() << QgsProcessing::TypeVectorPoint ) ); + addParameter( new QgsProcessingParameterPoint( QStringLiteral( "END_POINT" ), QObject::tr( "End point" ) ) ); + + addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Shortest path" ), QgsProcessing::TypeVectorLine ) ); +} + +QVariantMap QgsShortestPathLayerToPointAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) +{ + loadCommonParams( parameters, context, feedback ); + + QgsPointXY endPoint = parameterAsPoint( parameters, QStringLiteral( "END_POINT" ), context, mNetwork->sourceCrs() ); + + std::unique_ptr< QgsFeatureSource > startPoints( parameterAsSource( parameters, QStringLiteral( "START_POINTS" ), context ) ); + if ( !startPoints ) + throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "START_POINTS" ) ) ); + + QgsFields fields = startPoints->fields(); + fields.append( QgsField( QStringLiteral( "start" ), QVariant::String ) ); + fields.append( QgsField( QStringLiteral( "end" ), QVariant::String ) ); + fields.append( QgsField( QStringLiteral( "cost" ), QVariant::Double ) ); + + QString dest; + std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, fields, QgsWkbTypes::LineString, mNetwork->sourceCrs() ) ); + if ( !sink ) + throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) ); + + QVector< QgsPointXY > points; + points.push_front( endPoint ); + QHash< int, QgsAttributes > sourceAttributes; + loadPoints( startPoints.get(), points, sourceAttributes, context, feedback ); + + feedback->pushInfo( QObject::tr( "Building graph…" ) ); + QVector< QgsPointXY > snappedPoints; + mDirector->makeGraph( mBuilder.get(), points, snappedPoints, feedback ); + + feedback->pushInfo( QObject::tr( "Calculating shortest paths…" ) ); + QgsGraph *graph = mBuilder->graph(); + int idxEnd = graph->findVertex( snappedPoints[0] ); + int idxStart; + int currentIdx; + + QVector< int > tree; + QVector< double > costs; + + QVector route; + double cost; + + QgsFeature feat; + feat.setFields( fields ); + QgsAttributes attributes; + + int step = points.size() > 0 ? 100.0 / points.size() : 1; + for ( int i = 1; i < points.size(); i++ ) + { + if ( feedback->isCanceled() ) + { + break; + } + + idxStart = graph->findVertex( snappedPoints[i] ); + QgsGraphAnalyzer::dijkstra( graph, idxStart, 0, &tree, &costs ); + + if ( tree.at( idxEnd ) == -1 ) + { + feedback->reportError( QObject::tr( "There is no route from start point (%1) to end point (%2)." ) + .arg( points[i].toString() ) + .arg( endPoint.toString() ) ); + feat.clearGeometry(); + attributes = sourceAttributes.value( i ); + attributes.append( points[i].toString() ); + feat.setAttributes( attributes ); + sink->addFeature( feat, QgsFeatureSink::FastInsert ); + continue; + } + + route.clear(); + route.push_front( graph->vertex( idxEnd ).point() ); + cost = costs.at( idxEnd ); + currentIdx = idxEnd; + while ( currentIdx != idxStart ) + { + currentIdx = graph->edge( tree.at( currentIdx ) ).fromVertex(); + route.push_front( graph->vertex( currentIdx ).point() ); + } + + QgsGeometry geom = QgsGeometry::fromPolylineXY( route ); + QgsFeature feat; + feat.setFields( fields ); + attributes = sourceAttributes.value( i ); + attributes.append( points[i].toString() ); + attributes.append( endPoint.toString() ); + attributes.append( cost / mMultiplier ); + feat.setAttributes( attributes ); + feat.setGeometry( geom ); + sink->addFeature( feat, QgsFeatureSink::FastInsert ); + + feedback->setProgress( i * step ); + } + + QVariantMap outputs; + outputs.insert( QStringLiteral( "OUTPUT" ), dest ); + return outputs; +} + +///@endcond diff --git a/src/analysis/processing/qgsalgorithmshortestpathlayertopoint.h b/src/analysis/processing/qgsalgorithmshortestpathlayertopoint.h new file mode 100644 index 00000000000..431bca1e7d0 --- /dev/null +++ b/src/analysis/processing/qgsalgorithmshortestpathlayertopoint.h @@ -0,0 +1,53 @@ +/*************************************************************************** + qgsalgorithmshortestpathlayertopoint.h + --------------------- + begin : JUly 2018 + copyright : (C) 2018 by Alexander Bruy + email : alexander dot bruy at gmail dot com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSALGORITHMSHORTESTPATHLAYERTOPOINT_H +#define QGSALGORITHMSHORTESTPATHLAYERTOPOINT_H + +#define SIP_NO_FILE + +#include "qgis.h" +#include "qgsalgorithmnetworkanalysisbase.h" + +///@cond PRIVATE + +/** + * Native shortest path (layer to point) algorithm. + */ +class QgsShortestPathLayerToPointAlgorithm : public QgsNetworkAnalysisAlgorithmBase +{ + + public: + + QgsShortestPathLayerToPointAlgorithm() = default; + void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override; + QString name() const override; + QString displayName() const override; + QStringList tags() const override; + QString shortHelpString() const override; + QgsShortestPathLayerToPointAlgorithm *createInstance() const override SIP_FACTORY; + + protected: + + QVariantMap processAlgorithm( const QVariantMap ¶meters, + QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override; + +}; + +///@endcond PRIVATE + +#endif // QGSALGORITHMSHORTESTPATHLAYERTOPOINT_H diff --git a/src/analysis/processing/qgsalgorithmshortestpathpointtolayer.cpp b/src/analysis/processing/qgsalgorithmshortestpathpointtolayer.cpp new file mode 100644 index 00000000000..9b1cb10818e --- /dev/null +++ b/src/analysis/processing/qgsalgorithmshortestpathpointtolayer.cpp @@ -0,0 +1,156 @@ +/*************************************************************************** + qgsalgorithmshortestpathpointtolayer.cpp + --------------------- + begin : July 2018 + copyright : (C) 2018 by Alexander Bruy + email : alexander dot bruy at gmail dot com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "qgsalgorithmshortestpathpointtolayer.h" + +#include "qgsgraphanalyzer.h" + +#include "qgsmessagelog.h" + +///@cond PRIVATE + +QString QgsShortestPathPointToLayerAlgorithm::name() const +{ + return QStringLiteral( "shortestpathpointtolayer" ); +} + +QString QgsShortestPathPointToLayerAlgorithm::displayName() const +{ + return QObject::tr( "Shortest path (point to layer)" ); +} + +QStringList QgsShortestPathPointToLayerAlgorithm::tags() const +{ + return QObject::tr( "network,path,shortest,fastest" ).split( ',' ); +} + +QString QgsShortestPathPointToLayerAlgorithm::shortHelpString() const +{ + return QObject::tr( "This algorithm computes optimal (shortest or fastest) route between given start point and multiple end points defined by point vector layer." ); +} + +QgsShortestPathPointToLayerAlgorithm *QgsShortestPathPointToLayerAlgorithm::createInstance() const +{ + return new QgsShortestPathPointToLayerAlgorithm(); +} + +void QgsShortestPathPointToLayerAlgorithm::initAlgorithm( const QVariantMap & ) +{ + addCommonParams(); + addParameter( new QgsProcessingParameterPoint( QStringLiteral( "START_POINT" ), QObject::tr( "Start point" ) ) ); + addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "END_POINTS" ), QObject::tr( "Vector layer with end points" ), QList< int >() << QgsProcessing::TypeVectorPoint ) ); + + addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Shortest path" ), QgsProcessing::TypeVectorLine ) ); +} + +QVariantMap QgsShortestPathPointToLayerAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) +{ + loadCommonParams( parameters, context, feedback ); + + QgsPointXY startPoint = parameterAsPoint( parameters, QStringLiteral( "START_POINT" ), context, mNetwork->sourceCrs() ); + + std::unique_ptr< QgsFeatureSource > endPoints( parameterAsSource( parameters, QStringLiteral( "END_POINTS" ), context ) ); + if ( !endPoints ) + throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "END_POINTS" ) ) ); + + QgsFields fields = endPoints->fields(); + fields.append( QgsField( QStringLiteral( "start" ), QVariant::String ) ); + fields.append( QgsField( QStringLiteral( "end" ), QVariant::String ) ); + fields.append( QgsField( QStringLiteral( "cost" ), QVariant::Double ) ); + + QString dest; + std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, fields, QgsWkbTypes::LineString, mNetwork->sourceCrs() ) ); + if ( !sink ) + throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) ); + + QVector< QgsPointXY > points; + points.push_front( startPoint ); + QHash< int, QgsAttributes > sourceAttributes; + loadPoints( endPoints.get(), points, sourceAttributes, context, feedback ); + + feedback->pushInfo( QObject::tr( "Building graph…" ) ); + QVector< QgsPointXY > snappedPoints; + mDirector->makeGraph( mBuilder.get(), points, snappedPoints, feedback ); + + feedback->pushInfo( QObject::tr( "Calculating shortest paths…" ) ); + QgsGraph *graph = mBuilder->graph(); + int idxStart = graph->findVertex( snappedPoints[0] ); + int idxEnd; + + QVector< int > tree; + QVector< double > costs; + QgsGraphAnalyzer::dijkstra( graph, idxStart, 0, &tree, &costs ); + + QVector route; + double cost; + + QgsFeature feat; + feat.setFields( fields ); + QgsAttributes attributes; + + int step = points.size() > 0 ? 100.0 / points.size() : 1; + for ( int i = 1; i < points.size(); i++ ) + { + if ( feedback->isCanceled() ) + { + break; + } + + idxEnd = graph->findVertex( snappedPoints[i] ); + if ( tree.at( idxEnd ) == -1 ) + { + feedback->reportError( QObject::tr( "There is no route from start point (%1) to end point (%2)." ) + .arg( startPoint.toString() ) + .arg( points[i].toString() ) ); + feat.clearGeometry(); + attributes = sourceAttributes.value( i ); + attributes.append( QVariant() ); + attributes.append( points[i].toString() ); + feat.setAttributes( attributes ); + sink->addFeature( feat, QgsFeatureSink::FastInsert ); + continue; + } + + route.clear(); + route.push_front( graph->vertex( idxEnd ).point() ); + cost = costs.at( idxEnd ); + while ( idxEnd != idxStart ) + { + idxEnd = graph->edge( tree.at( idxEnd ) ).fromVertex(); + route.push_front( graph->vertex( idxEnd ).point() ); + } + + QgsGeometry geom = QgsGeometry::fromPolylineXY( route ); + QgsFeature feat; + feat.setFields( fields ); + attributes = sourceAttributes.value( i ); + attributes.append( startPoint.toString() ); + attributes.append( points[i].toString() ); + attributes.append( cost / mMultiplier ); + feat.setAttributes( attributes ); + feat.setGeometry( geom ); + sink->addFeature( feat, QgsFeatureSink::FastInsert ); + + feedback->setProgress( i * step ); + } + + QVariantMap outputs; + outputs.insert( QStringLiteral( "OUTPUT" ), dest ); + return outputs; +} + +///@endcond diff --git a/src/analysis/processing/qgsalgorithmshortestpathpointtolayer.h b/src/analysis/processing/qgsalgorithmshortestpathpointtolayer.h new file mode 100644 index 00000000000..cd7e2e2c50d --- /dev/null +++ b/src/analysis/processing/qgsalgorithmshortestpathpointtolayer.h @@ -0,0 +1,53 @@ +/*************************************************************************** + qgsalgorithmshortestpathpointtolayer.h + --------------------- + begin : JUly 2018 + copyright : (C) 2018 by Alexander Bruy + email : alexander dot bruy at gmail dot com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSALGORITHMSHORTESTPATHPOINTTOLAYER_H +#define QGSALGORITHMSHORTESTPATHPOINTTOLAYER_H + +#define SIP_NO_FILE + +#include "qgis.h" +#include "qgsalgorithmnetworkanalysisbase.h" + +///@cond PRIVATE + +/** + * Native shortest path (point to layer) algorithm. + */ +class QgsShortestPathPointToLayerAlgorithm : public QgsNetworkAnalysisAlgorithmBase +{ + + public: + + QgsShortestPathPointToLayerAlgorithm() = default; + void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override; + QString name() const override; + QString displayName() const override; + QStringList tags() const override; + QString shortHelpString() const override; + QgsShortestPathPointToLayerAlgorithm *createInstance() const override SIP_FACTORY; + + protected: + + QVariantMap processAlgorithm( const QVariantMap ¶meters, + QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override; + +}; + +///@endcond PRIVATE + +#endif // QGSALGORITHMSHORTESTPATHPOINTTOLAYER_H diff --git a/src/analysis/processing/qgsalgorithmshortestpathpointtopoint.cpp b/src/analysis/processing/qgsalgorithmshortestpathpointtopoint.cpp new file mode 100644 index 00000000000..e3d5e1792e7 --- /dev/null +++ b/src/analysis/processing/qgsalgorithmshortestpathpointtopoint.cpp @@ -0,0 +1,121 @@ +/*************************************************************************** + qgsalgorithmshortestpathpointtopoint.cpp + --------------------- + begin : July 2018 + copyright : (C) 2018 by Alexander Bruy + email : alexander dot bruy at gmail dot com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "qgsalgorithmshortestpathpointtopoint.h" + +#include "qgsgraphanalyzer.h" + +///@cond PRIVATE + +QString QgsShortestPathPointToPointAlgorithm::name() const +{ + return QStringLiteral( "shortestpathpointtopoint" ); +} + +QString QgsShortestPathPointToPointAlgorithm::displayName() const +{ + return QObject::tr( "Shortest path (point to point)" ); +} + +QStringList QgsShortestPathPointToPointAlgorithm::tags() const +{ + return QObject::tr( "network,path,shortest,fastest" ).split( ',' ); +} + +QString QgsShortestPathPointToPointAlgorithm::shortHelpString() const +{ + return QObject::tr( "This algorithm computes optimal (shortest or fastest) route between given start and end points." ); +} + +QgsShortestPathPointToPointAlgorithm *QgsShortestPathPointToPointAlgorithm::createInstance() const +{ + return new QgsShortestPathPointToPointAlgorithm(); +} + +void QgsShortestPathPointToPointAlgorithm::initAlgorithm( const QVariantMap & ) +{ + addCommonParams(); + addParameter( new QgsProcessingParameterPoint( QStringLiteral( "START_POINT" ), QObject::tr( "Start point" ) ) ); + addParameter( new QgsProcessingParameterPoint( QStringLiteral( "END_POINT" ), QObject::tr( "End point" ) ) ); + + addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Shortest path" ), QgsProcessing::TypeVectorLine ) ); + addOutput( new QgsProcessingOutputNumber( QStringLiteral( "TRAVEL_COST" ), QObject::tr( "Travel cost" ) ) ); +} + +QVariantMap QgsShortestPathPointToPointAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) +{ + loadCommonParams( parameters, context, feedback ); + + QgsFields fields; + fields.append( QgsField( QStringLiteral( "start" ), QVariant::String ) ); + fields.append( QgsField( QStringLiteral( "end" ), QVariant::String ) ); + fields.append( QgsField( QStringLiteral( "cost" ), QVariant::Double ) ); + + QString dest; + std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, fields, QgsWkbTypes::LineString, mNetwork->sourceCrs() ) ); + if ( !sink ) + throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) ); + + QgsPointXY startPoint = parameterAsPoint( parameters, QStringLiteral( "START_POINT" ), context, mNetwork->sourceCrs() ); + QgsPointXY endPoint = parameterAsPoint( parameters, QStringLiteral( "END_POINT" ), context, mNetwork->sourceCrs() ); + + feedback->pushInfo( QObject::tr( "Building graph…" ) ); + QVector< QgsPointXY > points; + points << startPoint << endPoint; + QVector< QgsPointXY > snappedPoints; + mDirector->makeGraph( mBuilder.get(), points, snappedPoints, feedback ); + + feedback->pushInfo( QObject::tr( "Calculating shortest path…" ) ); + QgsGraph *graph = mBuilder->graph(); + int idxStart = graph->findVertex( snappedPoints[0] ); + int idxEnd = graph->findVertex( snappedPoints[1] ); + + QVector< int > tree; + QVector< double > costs; + QgsGraphAnalyzer::dijkstra( graph, idxStart, 0, &tree, &costs ); + + if ( tree.at( idxEnd ) == -1 ) + { + throw QgsProcessingException( QObject::tr( "There is no route from start point to end point." ) ); + } + + QVector route; + route.push_front( graph->vertex( idxEnd ).point() ); + double cost = costs.at( idxEnd ); + while ( idxEnd != idxStart ) + { + idxEnd = graph->edge( tree.at( idxEnd ) ).fromVertex(); + route.push_front( graph->vertex( idxEnd ).point() ); + } + + feedback->pushInfo( QObject::tr( "Writing results…" ) ); + QgsGeometry geom = QgsGeometry::fromPolylineXY( route ); + QgsFeature feat; + feat.setFields( fields ); + QgsAttributes attributes; + attributes << startPoint.toString() << endPoint.toString() << cost / mMultiplier; + feat.setGeometry( geom ); + feat.setAttributes( attributes ); + sink->addFeature( feat, QgsFeatureSink::FastInsert ); + + QVariantMap outputs; + outputs.insert( QStringLiteral( "OUTPUT" ), dest ); + outputs.insert( QStringLiteral( "TRAVEL_COST" ), cost / mMultiplier ); + return outputs; +} + +///@endcond diff --git a/src/analysis/processing/qgsalgorithmshortestpathpointtopoint.h b/src/analysis/processing/qgsalgorithmshortestpathpointtopoint.h new file mode 100644 index 00000000000..8c525c730fe --- /dev/null +++ b/src/analysis/processing/qgsalgorithmshortestpathpointtopoint.h @@ -0,0 +1,53 @@ +/*************************************************************************** + qgsalgorithmshortestpathpointtopoint.h + --------------------- + begin : JUly 2018 + copyright : (C) 2018 by Alexander Bruy + email : alexander dot bruy at gmail dot com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSALGORITHMSHORTESTPATHPOINTTOPOINT_H +#define QGSALGORITHMSHORTESTPATHPOINTTOPOINT_H + +#define SIP_NO_FILE + +#include "qgis.h" +#include "qgsalgorithmnetworkanalysisbase.h" + +///@cond PRIVATE + +/** + * Native shortest path (point to point) algorithm. + */ +class QgsShortestPathPointToPointAlgorithm : public QgsNetworkAnalysisAlgorithmBase +{ + + public: + + QgsShortestPathPointToPointAlgorithm() = default; + void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override; + QString name() const override; + QString displayName() const override; + QStringList tags() const override; + QString shortHelpString() const override; + QgsShortestPathPointToPointAlgorithm *createInstance() const override SIP_FACTORY; + + protected: + + QVariantMap processAlgorithm( const QVariantMap ¶meters, + QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override; + +}; + +///@endcond PRIVATE + +#endif // QGSALGORITHMSHORTESTPATHPOINTTOPOINT_H diff --git a/src/analysis/processing/qgsnativealgorithms.cpp b/src/analysis/processing/qgsnativealgorithms.cpp index 084aa9747e8..f784bae5bb1 100644 --- a/src/analysis/processing/qgsnativealgorithms.cpp +++ b/src/analysis/processing/qgsnativealgorithms.cpp @@ -74,6 +74,9 @@ #include "qgsalgorithmrotate.h" #include "qgsalgorithmsaveselectedfeatures.h" #include "qgsalgorithmsegmentize.h" +#include "qgsalgorithmshortestpathlayertopoint.h" +#include "qgsalgorithmshortestpathpointtolayer.h" +#include "qgsalgorithmshortestpathpointtopoint.h" #include "qgsalgorithmsimplify.h" #include "qgsalgorithmsmooth.h" #include "qgsalgorithmsnaptogrid.h" @@ -196,6 +199,9 @@ void QgsNativeAlgorithms::loadAlgorithms() addAlgorithm( new QgsSegmentizeByMaximumAngleAlgorithm() ); addAlgorithm( new QgsSegmentizeByMaximumDistanceAlgorithm() ); addAlgorithm( new QgsSelectByLocationAlgorithm() ); + addAlgorithm( new QgsShortestPathLayerToPointAlgorithm() ); + addAlgorithm( new QgsShortestPathPointToLayerAlgorithm() ); + addAlgorithm( new QgsShortestPathPointToPointAlgorithm() ); addAlgorithm( new QgsSimplifyAlgorithm() ); addAlgorithm( new QgsSmoothAlgorithm() ); addAlgorithm( new QgsSnapToGridAlgorithm() );