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 @@
+
+
+
+
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() );