QGIS API Documentation 3.43.0-Master (e01d6d7c4c0)
qgsalgorithmshortestpathpointtopoint.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsalgorithmshortestpathpointtopoint.cpp
3 ---------------------
4 begin : July 2018
5 copyright : (C) 2018 by Alexander Bruy
6 email : alexander dot bruy at gmail dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
19
20#include "qgsgraphanalyzer.h"
21
23
24QString QgsShortestPathPointToPointAlgorithm::name() const
25{
26 return QStringLiteral( "shortestpathpointtopoint" );
27}
28
29QString QgsShortestPathPointToPointAlgorithm::displayName() const
30{
31 return QObject::tr( "Shortest path (point to point)" );
32}
33
34QStringList QgsShortestPathPointToPointAlgorithm::tags() const
35{
36 return QObject::tr( "network,path,shortest,fastest" ).split( ',' );
37}
38
39QString QgsShortestPathPointToPointAlgorithm::shortHelpString() const
40{
41 return QObject::tr( "This algorithm computes optimal (shortest or fastest) route between given start and end points." );
42}
43
44QString QgsShortestPathPointToPointAlgorithm::shortDescription() const
45{
46 return QObject::tr( "Computes optimal (shortest or fastest) route between given start and end points." );
47}
48
49QgsShortestPathPointToPointAlgorithm *QgsShortestPathPointToPointAlgorithm::createInstance() const
50{
51 return new QgsShortestPathPointToPointAlgorithm();
52}
53
54void QgsShortestPathPointToPointAlgorithm::initAlgorithm( const QVariantMap & )
55{
56 addCommonParams();
57 addParameter( new QgsProcessingParameterPoint( QStringLiteral( "START_POINT" ), QObject::tr( "Start point" ) ) );
58 addParameter( new QgsProcessingParameterPoint( QStringLiteral( "END_POINT" ), QObject::tr( "End point" ) ) );
59
60 addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Shortest path" ), Qgis::ProcessingSourceType::VectorLine ) );
61
62 std::unique_ptr<QgsProcessingParameterNumber> maxEndPointDistanceFromNetwork = std::make_unique<QgsProcessingParameterDistance>( QStringLiteral( "POINT_TOLERANCE" ), QObject::tr( "Maximum point distance from network" ), QVariant(), QStringLiteral( "INPUT" ), true, 0 );
63 maxEndPointDistanceFromNetwork->setFlags( maxEndPointDistanceFromNetwork->flags() | Qgis::ProcessingParameterFlag::Advanced );
64 maxEndPointDistanceFromNetwork->setHelp( QObject::tr( "Specifies an optional limit on the distance from the start and end points to the network layer. If either point is further from the network than this distance an error will be raised." ) );
65 addParameter( maxEndPointDistanceFromNetwork.release() );
66
67 addOutput( new QgsProcessingOutputNumber( QStringLiteral( "TRAVEL_COST" ), QObject::tr( "Travel cost" ) ) );
68}
69
70QVariantMap QgsShortestPathPointToPointAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
71{
72 loadCommonParams( parameters, context, feedback );
73
74 QgsFields fields;
75 fields.append( QgsField( QStringLiteral( "start" ), QMetaType::Type::QString ) );
76 fields.append( QgsField( QStringLiteral( "end" ), QMetaType::Type::QString ) );
77 fields.append( QgsField( QStringLiteral( "cost" ), QMetaType::Type::Double ) );
78
79 QString dest;
80 std::unique_ptr<QgsFeatureSink> sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, fields, Qgis::WkbType::LineString, mNetwork->sourceCrs() ) );
81 if ( !sink )
82 throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
83
84 const QgsPointXY startPoint = parameterAsPoint( parameters, QStringLiteral( "START_POINT" ), context, mNetwork->sourceCrs() );
85 const QgsPointXY endPoint = parameterAsPoint( parameters, QStringLiteral( "END_POINT" ), context, mNetwork->sourceCrs() );
86
87 feedback->pushInfo( QObject::tr( "Building graph…" ) );
88 QVector<QgsPointXY> snappedPoints;
89 mDirector->makeGraph( mBuilder.get(), { startPoint, endPoint }, snappedPoints, feedback );
90 const QgsPointXY snappedStartPoint = snappedPoints[0];
91 const QgsPointXY snappedEndPoint = snappedPoints[1];
92
93 // check distance for the snapped start/end points
94 if ( parameters.value( QStringLiteral( "POINT_TOLERANCE" ) ).isValid() )
95 {
96 const double pointDistanceThreshold = parameterAsDouble( parameters, QStringLiteral( "POINT_TOLERANCE" ), context );
97
98 double distanceStartPointToNetwork = 0;
99 try
100 {
101 distanceStartPointToNetwork = mBuilder->distanceArea()->measureLine( startPoint, snappedStartPoint );
102 }
103 catch ( QgsCsException & )
104 {
105 throw QgsProcessingException( QObject::tr( "An error occurred while calculating length" ) );
106 }
107
108 if ( distanceStartPointToNetwork > pointDistanceThreshold )
109 {
110 throw QgsProcessingException( QObject::tr( "Start point is too far from the network layer (%1, maximum permitted is %2)" ).arg( distanceStartPointToNetwork ).arg( pointDistanceThreshold ) );
111 }
112
113 double distanceEndPointToNetwork = 0;
114 try
115 {
116 distanceEndPointToNetwork = mBuilder->distanceArea()->measureLine( endPoint, snappedEndPoint );
117 }
118 catch ( QgsCsException & )
119 {
120 throw QgsProcessingException( QObject::tr( "An error occurred while calculating length" ) );
121 }
122
123 if ( distanceEndPointToNetwork > pointDistanceThreshold )
124 {
125 throw QgsProcessingException( QObject::tr( "End point is too far from the network layer (%1, maximum permitted is %2)" ).arg( distanceEndPointToNetwork ).arg( pointDistanceThreshold ) );
126 }
127 }
128
129 feedback->pushInfo( QObject::tr( "Calculating shortest path…" ) );
130 std::unique_ptr<QgsGraph> graph( mBuilder->takeGraph() );
131
132 const int idxStart = graph->findVertex( snappedStartPoint );
133 int idxEnd = graph->findVertex( snappedEndPoint );
134
135 QVector<int> tree;
136 QVector<double> costs;
137 QgsGraphAnalyzer::dijkstra( graph.get(), idxStart, 0, &tree, &costs );
138
139 if ( tree.at( idxEnd ) == -1 )
140 {
141 throw QgsProcessingException( QObject::tr( "There is no route from start point to end point." ) );
142 }
143
144 QVector<QgsPointXY> route;
145 route.push_front( graph->vertex( idxEnd ).point() );
146 const double cost = costs.at( idxEnd );
147 while ( idxEnd != idxStart )
148 {
149 idxEnd = graph->edge( tree.at( idxEnd ) ).fromVertex();
150 route.push_front( graph->vertex( idxEnd ).point() );
151 }
152
153 feedback->pushInfo( QObject::tr( "Writing results…" ) );
154 const QgsGeometry geom = QgsGeometry::fromPolylineXY( route );
155 QgsFeature feat;
156 feat.setFields( fields );
157 QgsAttributes attributes;
158 attributes << startPoint.toString() << endPoint.toString() << cost / mMultiplier;
159 feat.setGeometry( geom );
160 feat.setAttributes( attributes );
161 if ( !sink->addFeature( feat, QgsFeatureSink::FastInsert ) )
162 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, QStringLiteral( "OUTPUT" ) ) );
163
164 sink->finalize();
165
166 QVariantMap outputs;
167 outputs.insert( QStringLiteral( "OUTPUT" ), dest );
168 outputs.insert( QStringLiteral( "TRAVEL_COST" ), cost / mMultiplier );
169 return outputs;
170}
171
@ VectorLine
Vector line layers.
@ LineString
LineString.
@ Advanced
Parameter is an advanced parameter which should be hidden from users by default.
A vector of attributes.
Custom exception class for Coordinate Reference System related exceptions.
@ FastInsert
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:58
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
void setFields(const QgsFields &fields, bool initAttributes=false)
Assigns a field map with the feature to allow attribute access by attribute name.
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:53
Container of fields for a vector layer.
Definition qgsfields.h:46
bool append(const QgsField &field, Qgis::FieldOrigin origin=Qgis::FieldOrigin::Provider, int originIndex=-1)
Appends a field.
Definition qgsfields.cpp:70
A geometry is the spatial representation of a feature.
static QgsGeometry fromPolylineXY(const QgsPolylineXY &polyline)
Creates a new LineString geometry from a list of QgsPointXY points.
static void dijkstra(const QgsGraph *source, int startVertexIdx, int criterionNum, QVector< int > *resultTree=nullptr, QVector< double > *resultCost=nullptr)
Solve shortest path problem using Dijkstra algorithm.
Represents a 2D point.
Definition qgspointxy.h:60
QString toString(int precision=-1) const
Returns a string representation of the point (x, y) with a preset precision.
Contains information about the context in which a processing algorithm is executed.
Custom exception class for processing related exceptions.
Base class for providing feedback from a processing algorithm.
virtual void pushInfo(const QString &info)
Pushes a general informational message from the algorithm.
A numeric output for processing algorithms.
A feature sink output for processing algorithms.
A point parameter for processing algorithms.