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..3abdec82603 100644
--- a/python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py
+++ b/python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py
@@ -127,7 +127,7 @@ from .SetVectorStyle import SetVectorStyle
from .SetZValue import SetZValue
from .ShortestPathLayerToPoint import ShortestPathLayerToPoint
from .ShortestPathPointToLayer import ShortestPathPointToLayer
-from .ShortestPathPointToPoint import ShortestPathPointToPoint
+#from .ShortestPathPointToPoint import ShortestPathPointToPoint
from .SingleSidedBuffer import SingleSidedBuffer
from .Slope import Slope
from .SnapGeometries import SnapGeometriesToLayer
@@ -241,7 +241,7 @@ class QgisAlgorithmProvider(QgsProcessingProvider):
SetZValue(),
ShortestPathLayerToPoint(),
ShortestPathPointToLayer(),
- ShortestPathPointToPoint(),
+ #ShortestPathPointToPoint(),
SingleSidedBuffer(),
Slope(),
SnapGeometriesToLayer(),
diff --git a/python/plugins/processing/algs/qgis/ShortestPathPointToPoint.py b/python/plugins/processing/algs/qgis/ShortestPathPointToPoint.py
index b86bddbc864..d33bd815c1c 100644
--- a/python/plugins/processing/algs/qgis/ShortestPathPointToPoint.py
+++ b/python/plugins/processing/algs/qgis/ShortestPathPointToPoint.py
@@ -219,13 +219,21 @@ class ShortestPathPointToPoint(QgisAlgorithm):
tolerance)
feedback.pushInfo(QCoreApplication.translate('ShortestPathPointToPoint', 'Building graph…'))
snappedPoints = director.makeGraph(builder, [startPoint, endPoint], feedback)
+ feedback.pushInfo('Start point {}'.format(startPoint.toString()))
+ feedback.pushInfo('Snap start: {}'.format(snappedPoints[0].toString()))
+ feedback.pushInfo('End point {}'.format(endPoint.toString()))
+ feedback.pushInfo('Snap end: {}'.format(snappedPoints[1].toString()))
feedback.pushInfo(QCoreApplication.translate('ShortestPathPointToPoint', 'Calculating shortest path…'))
graph = builder.graph()
idxStart = graph.findVertex(snappedPoints[0])
idxEnd = graph.findVertex(snappedPoints[1])
+ feedback.pushInfo('Start idx {}'.format(idxStart))
+ feedback.pushInfo('End idx {}'.format(idxEnd))
tree, costs = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
+ feedback.pushInfo('Tree size {}'.format(len(tree)))
+ feedback.pushInfo('End node {}'.format(tree[idxEnd]))
if tree[idxEnd] == -1:
raise QgsProcessingException(
self.tr('There is no route from start point to end point.'))
diff --git a/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml b/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml
index d043870663f..66a4b406e08 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
@@ -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..c19cb95014e 100755
--- a/src/analysis/CMakeLists.txt
+++ b/src/analysis/CMakeLists.txt
@@ -77,6 +77,7 @@ SET(QGIS_ANALYSIS_SRCS
processing/qgsalgorithmrotate.cpp
processing/qgsalgorithmsaveselectedfeatures.cpp
processing/qgsalgorithmsegmentize.cpp
+ processing/qgsalgorithmshortestpathpointtopoint.cpp
processing/qgsalgorithmsimplify.cpp
processing/qgsalgorithmsmooth.cpp
processing/qgsalgorithmsnaptogrid.cpp
diff --git a/src/analysis/processing/qgsalgorithmshortestpathpointtopoint.cpp b/src/analysis/processing/qgsalgorithmshortestpathpointtopoint.cpp
new file mode 100644
index 00000000000..13d36ead96d
--- /dev/null
+++ b/src/analysis/processing/qgsalgorithmshortestpathpointtopoint.cpp
@@ -0,0 +1,215 @@
+/***************************************************************************
+ 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 "qgsgraph.h"
+#include "qgsgraphbuilder.h"
+#include "qgsgraphanalyzer.h"
+#include "qgsvectorlayerdirector.h"
+#include "qgsnetworkspeedstrategy.h"
+#include "qgsnetworkdistancestrategy.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::group() const
+{
+ return QObject::tr( "Network analysis" );
+}
+
+QString QgsShortestPathPointToPointAlgorithm::groupId() const
+{
+ return QStringLiteral( "networkanalysis" );
+}
+
+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 & )
+{
+ addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Vector layer representing network" ), QList< int >() << QgsProcessing::TypeVectorLine ) );
+ addParameter( new QgsProcessingParameterPoint( QStringLiteral( "START_POINT" ), QObject::tr( "Start point" ) ) );
+ addParameter( new QgsProcessingParameterPoint( QStringLiteral( "END_POINT" ), QObject::tr( "End point" ) ) );
+ 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() );
+
+ 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 )
+{
+ std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
+ if ( !source )
+ throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
+
+ 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, source->sourceCrs() ) );
+ if ( !sink )
+ throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
+
+ QgsPointXY startPoint = parameterAsPoint( parameters, QStringLiteral( "START_POINT" ), context, source->sourceCrs() );
+ QgsPointXY endPoint = parameterAsPoint( parameters, QStringLiteral( "END_POINT" ), context, source->sourceCrs() );
+ 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 directionIndex = -1;
+ if ( !directionFieldName.isEmpty() )
+ {
+ directionIndex = source->fields().lookupField( directionFieldName );
+ }
+
+ int speedIndex = -1;
+ if ( !speedFieldName.isEmpty() )
+ {
+ speedIndex = source->fields().lookupField( speedFieldName );
+ }
+
+ QgsVectorLayerDirector *director = new QgsVectorLayerDirector( source.get(), directionIndex, forwardValue, backwardValue, bothValue, defaultDirection );
+
+ QgsUnitTypes::DistanceUnit distanceUnits = context.project()->crs().mapUnits();
+ double multiplier = QgsUnitTypes::fromUnitToUnitFactor( distanceUnits, QgsUnitTypes::DistanceMeters );
+
+ if ( strategy )
+ {
+ director->addStrategy( new QgsNetworkSpeedStrategy( speedIndex, defaultSpeed, multiplier * 1000.0 / 3600.0 ) );
+ multiplier = 3600;
+ }
+ else
+ {
+ director->addStrategy( new QgsNetworkDistanceStrategy() );
+ }
+
+ QgsGraphBuilder builder( source->sourceCrs(), true, tolerance );
+
+ feedback->pushInfo( QObject::tr( "Building graph…" ) );
+ QVector< QgsPointXY > points;
+ points << startPoint << endPoint;
+ QVector< QgsPointXY > snappedPoints;
+ director->makeGraph( &builder, points, snappedPoints, feedback );
+
+ feedback->pushInfo( QObject::tr( "Calculating shortest path…" ) );
+ QgsGraph *graph = builder.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 / multiplier;
+ feat.setGeometry( geom );
+ feat.setAttributes( attributes );
+ sink->addFeature( feat, QgsFeatureSink::FastInsert );
+
+ QVariantMap outputs;
+ outputs.insert( QStringLiteral( "OUTPUT" ), dest );
+ outputs.insert( QStringLiteral( "TRAVEL_COST" ), cost / multiplier );
+ return outputs;
+}
+
+///@endcond
diff --git a/src/analysis/processing/qgsalgorithmshortestpathpointtopoint.h b/src/analysis/processing/qgsalgorithmshortestpathpointtopoint.h
new file mode 100644
index 00000000000..8bf1b4d857f
--- /dev/null
+++ b/src/analysis/processing/qgsalgorithmshortestpathpointtopoint.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+ 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 "qgsprocessingalgorithm.h"
+
+///@cond PRIVATE
+
+/**
+ * Native shortest path (point to point) algorithm.
+ */
+class QgsShortestPathPointToPointAlgorithm : public QgsProcessingAlgorithm
+{
+
+ public:
+
+ QgsShortestPathPointToPointAlgorithm() = default;
+ void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
+ QIcon icon() const override { return QgsApplication::getThemeIcon( QStringLiteral( "/algorithms/mAlgorithmNetworkAnalysis.svg" ) ); }
+ QString svgIconPath() const override { return QgsApplication::iconPath( QStringLiteral( "/algorithms/mAlgorithmNetworkAnalysis.svg" ) ); }
+ QString name() const override;
+ QString displayName() const override;
+ QStringList tags() const override;
+ QString group() const override;
+ QString groupId() 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..03ad2f98f61 100644
--- a/src/analysis/processing/qgsnativealgorithms.cpp
+++ b/src/analysis/processing/qgsnativealgorithms.cpp
@@ -74,6 +74,7 @@
#include "qgsalgorithmrotate.h"
#include "qgsalgorithmsaveselectedfeatures.h"
#include "qgsalgorithmsegmentize.h"
+#include "qgsalgorithmshortestpathpointtopoint.h"
#include "qgsalgorithmsimplify.h"
#include "qgsalgorithmsmooth.h"
#include "qgsalgorithmsnaptogrid.h"
@@ -196,6 +197,7 @@ void QgsNativeAlgorithms::loadAlgorithms()
addAlgorithm( new QgsSegmentizeByMaximumAngleAlgorithm() );
addAlgorithm( new QgsSegmentizeByMaximumDistanceAlgorithm() );
addAlgorithm( new QgsSelectByLocationAlgorithm() );
+ addAlgorithm( new QgsShortestPathPointToPointAlgorithm() );
addAlgorithm( new QgsSimplifyAlgorithm() );
addAlgorithm( new QgsSmoothAlgorithm() );
addAlgorithm( new QgsSnapToGridAlgorithm() );