QGIS API Documentation 4.3.0-Master (2b7e6c9893e)
Loading...
Searching...
No Matches
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
22#include <QString>
23
24using namespace Qt::StringLiterals;
25
27
28QString QgsShortestPathPointToPointAlgorithm::name() const
29{
30 return u"shortestpathpointtopoint"_s;
31}
32
33QString QgsShortestPathPointToPointAlgorithm::displayName() const
34{
35 return QObject::tr( "Shortest path (point to point)" );
36}
37
38QStringList QgsShortestPathPointToPointAlgorithm::tags() const
39{
40 return QObject::tr( "network,path,shortest,fastest" ).split( ',' );
41}
42
43QString QgsShortestPathPointToPointAlgorithm::shortHelpString() const
44{
45 return QObject::tr( "This algorithm computes optimal (shortest or fastest) route between given start and end points." );
46}
47
48QString QgsShortestPathPointToPointAlgorithm::shortDescription() const
49{
50 return QObject::tr( "Computes optimal (shortest or fastest) route between given start and end points." );
51}
52
53QgsShortestPathPointToPointAlgorithm *QgsShortestPathPointToPointAlgorithm::createInstance() const
54{
55 return new QgsShortestPathPointToPointAlgorithm();
56}
57
58void QgsShortestPathPointToPointAlgorithm::initAlgorithm( const QVariantMap & )
59{
60 addCommonParams();
61 addParameter( new QgsProcessingParameterPoint( u"START_POINT"_s, QObject::tr( "Start point" ) ) );
62 addParameter( new QgsProcessingParameterPoint( u"END_POINT"_s, QObject::tr( "End point" ) ) );
63
64 addParameter( new QgsProcessingParameterFeatureSink( u"OUTPUT"_s, QObject::tr( "Shortest path" ), Qgis::ProcessingSourceType::VectorLine ) );
65
66 std::unique_ptr<QgsProcessingParameterNumber> maxEndPointDistanceFromNetwork
67 = std::make_unique<QgsProcessingParameterDistance>( u"POINT_TOLERANCE"_s, QObject::tr( "Maximum point distance from network" ), QVariant(), u"INPUT"_s, true, 0 );
68 maxEndPointDistanceFromNetwork->setFlags( maxEndPointDistanceFromNetwork->flags() | Qgis::ProcessingParameterFlag::Advanced );
69 maxEndPointDistanceFromNetwork->setHelp(
70 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." )
71 );
72 addParameter( maxEndPointDistanceFromNetwork.release() );
73
74 addOutput( new QgsProcessingOutputNumber( u"TRAVEL_COST"_s, QObject::tr( "Travel cost" ) ) );
75}
76
77QVariantMap QgsShortestPathPointToPointAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
78{
79 QGS_MARK_ALGORITHM_SOURCE
80
81 loadCommonParams( parameters, context, feedback );
82
83 QgsFields fields;
84 fields.append( QgsField( u"start"_s, QMetaType::Type::QString ) );
85 fields.append( QgsField( u"end"_s, QMetaType::Type::QString ) );
86 fields.append( QgsField( u"cost"_s, QMetaType::Type::Double ) );
87
88 QString dest;
89 std::unique_ptr<QgsFeatureSink> sink( parameterAsSink( parameters, u"OUTPUT"_s, context, dest, fields, Qgis::WkbType::LineString, mNetwork->sourceCrs() ) );
90 if ( !sink )
91 throw QgsProcessingException( invalidSinkError( parameters, u"OUTPUT"_s ) );
92
93 const QgsPointXY startPoint = parameterAsPoint( parameters, u"START_POINT"_s, context, mNetwork->sourceCrs() );
94 const QgsPointXY endPoint = parameterAsPoint( parameters, u"END_POINT"_s, context, mNetwork->sourceCrs() );
95
96 feedback->pushInfo( QObject::tr( "Building graph…" ) );
97 QVector<QgsPointXY> snappedPoints;
98 mDirector->makeGraph( mBuilder.get(), { startPoint, endPoint }, snappedPoints, feedback );
99 const QgsPointXY snappedStartPoint = snappedPoints[0];
100 const QgsPointXY snappedEndPoint = snappedPoints[1];
101
102 // check distance for the snapped start/end points
103 if ( parameters.value( u"POINT_TOLERANCE"_s ).isValid() )
104 {
105 const double pointDistanceThreshold = parameterAsDouble( parameters, u"POINT_TOLERANCE"_s, context );
106
107 double distanceStartPointToNetwork = 0;
108 try
109 {
110 distanceStartPointToNetwork = mBuilder->distanceArea()->measureLine( startPoint, snappedStartPoint );
111 }
112 catch ( QgsCsException & )
113 {
114 throw QgsProcessingException( QObject::tr( "An error occurred while calculating length" ) );
115 }
116
117 if ( distanceStartPointToNetwork > pointDistanceThreshold )
118 {
119 throw QgsProcessingException( QObject::tr( "Start point is too far from the network layer (%1, maximum permitted is %2)" ).arg( distanceStartPointToNetwork ).arg( pointDistanceThreshold ) );
120 }
121
122 double distanceEndPointToNetwork = 0;
123 try
124 {
125 distanceEndPointToNetwork = mBuilder->distanceArea()->measureLine( endPoint, snappedEndPoint );
126 }
127 catch ( QgsCsException & )
128 {
129 throw QgsProcessingException( QObject::tr( "An error occurred while calculating length" ) );
130 }
131
132 if ( distanceEndPointToNetwork > pointDistanceThreshold )
133 {
134 throw QgsProcessingException( QObject::tr( "End point is too far from the network layer (%1, maximum permitted is %2)" ).arg( distanceEndPointToNetwork ).arg( pointDistanceThreshold ) );
135 }
136 }
137
138 feedback->pushInfo( QObject::tr( "Calculating shortest path…" ) );
139 std::unique_ptr<QgsGraph> graph( mBuilder->takeGraph() );
140
141 const int idxStart = graph->findVertex( snappedStartPoint );
142 int idxEnd = graph->findVertex( snappedEndPoint );
143
144 QVector<int> tree;
145 QVector<double> costs;
146 QgsGraphAnalyzer::dijkstra( graph.get(), idxStart, 0, &tree, &costs );
147
148 if ( tree.at( idxEnd ) == -1 )
149 {
150 throw QgsProcessingException( QObject::tr( "There is no route from start point to end point." ) );
151 }
152
153 QVector<QgsPointXY> route;
154 route.push_front( graph->vertex( idxEnd ).point() );
155 const double cost = costs.at( idxEnd );
156 while ( idxEnd != idxStart )
157 {
158 idxEnd = graph->edge( tree.at( idxEnd ) ).fromVertex();
159 route.push_front( graph->vertex( idxEnd ).point() );
160 }
161
162 feedback->pushInfo( QObject::tr( "Writing results…" ) );
163 const QgsGeometry geom = QgsGeometry::fromPolylineXY( route );
164 QgsFeature feat;
165 feat.setFields( fields );
166 QgsAttributes attributes;
167 attributes << startPoint.toString() << endPoint.toString() << cost / mMultiplier;
168 feat.setGeometry( geom );
169 feat.setAttributes( attributes );
170 if ( !sink->addFeature( feat, QgsFeatureSink::FastInsert ) )
171 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, u"OUTPUT"_s ) );
172 else
173 feedback->featureAddedToSink( u"OUTPUT"_s );
174
175 sink->finalize();
176 feedback->featureSinkFinalized( u"OUTPUT"_s );
177
178 QVariantMap outputs;
179 outputs.insert( u"OUTPUT"_s, dest );
180 outputs.insert( u"TRAVEL_COST"_s, cost / mMultiplier );
181 return outputs;
182}
183
@ VectorLine
Vector line layers.
Definition qgis.h:3753
@ LineString
LineString.
Definition qgis.h:297
@ Advanced
Parameter is an advanced parameter which should be hidden from users by default.
Definition qgis.h:3984
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:60
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:56
Container of fields for a vector layer.
Definition qgsfields.h:45
bool append(const QgsField &field, Qgis::FieldOrigin origin=Qgis::FieldOrigin::Provider, int originIndex=-1)
Appends a field.
Definition qgsfields.cpp:75
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:62
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.
void featureAddedToSink(const QString &output)
Reports that a feature was added to the the sink associated with the specified algorithm output.
virtual void pushInfo(const QString &info)
Pushes a general informational message from the algorithm.
void featureSinkFinalized(const QString &output)
Reports that a feature sink has been finalized.
A numeric output for processing algorithms.
A feature sink output for processing algorithms.
A point parameter for processing algorithms.