QGIS API Documentation  3.12.1-București (121cc00ff0)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
qgsalgorithmserviceareafrompoint.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsalgorithmserviceareafrompoint.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 "qgsgeometryutils.h"
21 #include "qgsgraphanalyzer.h"
22 
24 
25 QString QgsServiceAreaFromPointAlgorithm::name() const
26 {
27  return QStringLiteral( "serviceareafrompoint" );
28 }
29 
30 QString QgsServiceAreaFromPointAlgorithm::displayName() const
31 {
32  return QObject::tr( "Service area (from point)" );
33 }
34 
35 QStringList QgsServiceAreaFromPointAlgorithm::tags() const
36 {
37  return QObject::tr( "network,service,area,shortest,fastest" ).split( ',' );
38 }
39 
40 QString QgsServiceAreaFromPointAlgorithm::shortHelpString() const
41 {
42  return QObject::tr( "This algorithm creates a new vector with all the edges or parts of edges of a network line layer that can be reached within a distance or a time, starting from a point feature. The distance and the time (both referred to as \"travel cost\") must be specified respectively in the network layer units or in seconds." );
43 }
44 
45 QgsServiceAreaFromPointAlgorithm *QgsServiceAreaFromPointAlgorithm::createInstance() const
46 {
47  return new QgsServiceAreaFromPointAlgorithm();
48 }
49 
50 void QgsServiceAreaFromPointAlgorithm::initAlgorithm( const QVariantMap & )
51 {
52  addCommonParams();
53  addParameter( new QgsProcessingParameterPoint( QStringLiteral( "START_POINT" ), QObject::tr( "Start point" ) ) );
54  addParameter( new QgsProcessingParameterNumber( QStringLiteral( "TRAVEL_COST" ), QObject::tr( "Travel cost (distance for 'Shortest', time for 'Fastest')" ),
55  QgsProcessingParameterNumber::Double, 0, false, 0 ) );
56 
57  std::unique_ptr< QgsProcessingParameterBoolean > includeBounds = qgis::make_unique< QgsProcessingParameterBoolean >( QStringLiteral( "INCLUDE_BOUNDS" ), QObject::tr( "Include upper/lower bound points" ), false, true );
58  includeBounds->setFlags( includeBounds->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
59  addParameter( includeBounds.release() );
60 
61  std::unique_ptr< QgsProcessingParameterFeatureSink > outputLines = qgis::make_unique< QgsProcessingParameterFeatureSink >( QStringLiteral( "OUTPUT_LINES" ), QObject::tr( "Service area (lines)" ),
62  QgsProcessing::TypeVectorLine, QVariant(), true );
63  outputLines->setCreateByDefault( true );
64  addParameter( outputLines.release() );
65 
66  std::unique_ptr< QgsProcessingParameterFeatureSink > outputPoints = qgis::make_unique< QgsProcessingParameterFeatureSink >( QStringLiteral( "OUTPUT" ), QObject::tr( "Service area (boundary nodes)" ),
67  QgsProcessing::TypeVectorPoint, QVariant(), true );
68  outputPoints->setCreateByDefault( false );
69  addParameter( outputPoints.release() );
70 }
71 
72 QVariantMap QgsServiceAreaFromPointAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
73 {
74  loadCommonParams( parameters, context, feedback );
75 
76  QgsPointXY startPoint = parameterAsPoint( parameters, QStringLiteral( "START_POINT" ), context, mNetwork->sourceCrs() );
77  double travelCost = parameterAsDouble( parameters, QStringLiteral( "TRAVEL_COST" ), context );
78 
79  bool includeBounds = true; // default to true to maintain 3.0 API
80  if ( parameters.contains( QStringLiteral( "INCLUDE_BOUNDS" ) ) )
81  {
82  includeBounds = parameterAsBool( parameters, QStringLiteral( "INCLUDE_BOUNDS" ), context );
83  }
84 
85  feedback->pushInfo( QObject::tr( "Building graph…" ) );
86  QVector< QgsPointXY > snappedPoints;
87  mDirector->makeGraph( mBuilder.get(), QVector< QgsPointXY >() << startPoint, snappedPoints, feedback );
88 
89  feedback->pushInfo( QObject::tr( "Calculating service area…" ) );
90  QgsGraph *graph = mBuilder->graph();
91  int idxStart = graph->findVertex( snappedPoints[0] );
92 
93  QVector< int > tree;
94  QVector< double > costs;
95  QgsGraphAnalyzer::dijkstra( graph, idxStart, 0, &tree, &costs );
96 
97  QgsMultiPointXY points;
98  QgsMultiPolylineXY lines;
99  QSet< int > vertices;
100 
101  int inboundEdgeIndex;
102  double startVertexCost, endVertexCost;
103  QgsPointXY edgeStart, edgeEnd;
104  QgsGraphEdge edge;
105 
106  for ( int i = 0; i < costs.size(); i++ )
107  {
108  inboundEdgeIndex = tree.at( i );
109  if ( inboundEdgeIndex == -1 && i != idxStart )
110  {
111  // unreachable vertex
112  continue;
113  }
114 
115  startVertexCost = costs.at( i );
116  if ( startVertexCost > travelCost )
117  {
118  // vertex is too expensive, discard
119  continue;
120  }
121 
122  vertices.insert( i );
123  edgeStart = graph->vertex( i ).point();
124 
125  // find all edges coming from this vertex
126  const QList< int > outgoingEdges = graph->vertex( i ).outgoingEdges() ;
127  for ( int edgeId : outgoingEdges )
128  {
129  edge = graph->edge( edgeId );
130  endVertexCost = startVertexCost + edge.cost( 0 ).toDouble();
131  edgeEnd = graph->vertex( edge.toVertex() ).point();
132  if ( endVertexCost <= travelCost )
133  {
134  // end vertex is cheap enough to include
135  vertices.insert( edge.toVertex() );
136  lines.push_back( QgsPolylineXY() << edgeStart << edgeEnd );
137  }
138  else
139  {
140  // travelCost sits somewhere on this edge, interpolate position
141  QgsPointXY interpolatedEndPoint = QgsGeometryUtils::interpolatePointOnLineByValue( edgeStart.x(), edgeStart.y(), startVertexCost,
142  edgeEnd.x(), edgeEnd.y(), endVertexCost, travelCost );
143 
144  points.push_back( interpolatedEndPoint );
145  lines.push_back( QgsPolylineXY() << edgeStart << interpolatedEndPoint );
146  }
147  } // edges
148  } // costs
149 
150  // convert to list and sort to maintain same order of points between algorithm runs
151  QList< int > verticesList = vertices.toList();
152  points.reserve( verticesList.size() );
153  std::sort( verticesList.begin(), verticesList.end() );
154  for ( int v : verticesList )
155  {
156  points.push_back( graph->vertex( v ).point() );
157  }
158 
159  feedback->pushInfo( QObject::tr( "Writing results…" ) );
160 
161  QVariantMap outputs;
162 
163  QgsFields fields;
164  fields.append( QgsField( QStringLiteral( "type" ), QVariant::String ) );
165  fields.append( QgsField( QStringLiteral( "start" ), QVariant::String ) );
166 
167  QgsFeature feat;
168  feat.setFields( fields );
169 
170  QString pointsSinkId;
171  std::unique_ptr< QgsFeatureSink > pointsSink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, pointsSinkId, fields,
172  QgsWkbTypes::MultiPoint, mNetwork->sourceCrs() ) );
173 
174  if ( pointsSink )
175  {
176  outputs.insert( QStringLiteral( "OUTPUT" ), pointsSinkId );
177 
178  QgsGeometry geomPoints = QgsGeometry::fromMultiPointXY( points );
179  feat.setGeometry( geomPoints );
180  feat.setAttributes( QgsAttributes() << QStringLiteral( "within" ) << startPoint.toString() );
181  pointsSink->addFeature( feat, QgsFeatureSink::FastInsert );
182 
183  if ( includeBounds )
184  {
185  QgsMultiPointXY upperBoundary, lowerBoundary;
186  QVector< int > nodes;
187 
188  int vertexId;
189  for ( int i = 0; i < costs.size(); i++ )
190  {
191  if ( costs.at( i ) > travelCost && tree.at( i ) != -1 )
192  {
193  vertexId = graph->edge( tree.at( i ) ).fromVertex();
194  if ( costs.at( vertexId ) <= travelCost )
195  {
196  nodes.push_back( i );
197  }
198  }
199  } // costs
200 
201  for ( int i : nodes )
202  {
203  upperBoundary.push_back( graph->vertex( graph->edge( tree.at( i ) ).toVertex() ).point() );
204  lowerBoundary.push_back( graph->vertex( graph->edge( tree.at( i ) ).fromVertex() ).point() );
205  } // nodes
206 
207  QgsGeometry geomUpper = QgsGeometry::fromMultiPointXY( upperBoundary );
208  QgsGeometry geomLower = QgsGeometry::fromMultiPointXY( lowerBoundary );
209 
210  feat.setGeometry( geomUpper );
211  feat.setAttributes( QgsAttributes() << QStringLiteral( "upper" ) << startPoint.toString() );
212  pointsSink->addFeature( feat, QgsFeatureSink::FastInsert );
213 
214  feat.setGeometry( geomLower );
215  feat.setAttributes( QgsAttributes() << QStringLiteral( "lower" ) << startPoint.toString() );
216  pointsSink->addFeature( feat, QgsFeatureSink::FastInsert );
217  } // includeBounds
218  }
219 
220  QString linesSinkId;
221  std::unique_ptr< QgsFeatureSink > linesSink( parameterAsSink( parameters, QStringLiteral( "OUTPUT_LINES" ), context, linesSinkId, fields,
222  QgsWkbTypes::MultiLineString, mNetwork->sourceCrs() ) );
223 
224  if ( linesSink )
225  {
226  outputs.insert( QStringLiteral( "OUTPUT_LINES" ), linesSinkId );
227  QgsGeometry geomLines = QgsGeometry::fromMultiPolylineXY( lines );
228  feat.setGeometry( geomLines );
229  feat.setAttributes( QgsAttributes() << QStringLiteral( "lines" ) << startPoint.toString() );
230  linesSink->addFeature( feat, QgsFeatureSink::FastInsert );
231  }
232 
233  return outputs;
234 }
235 
const QgsGraphEdge & edge(int idx) const
Returns edge at given index.
Definition: qgsgraph.cpp:50
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
Base class for providing feedback from a processing algorithm.
Parameter is an advanced parameter which should be hidden from users by default.
void setFields(const QgsFields &fields, bool initAttributes=false)
Assign a field map with the feature to allow attribute access by attribute name.
Definition: qgsfeature.cpp:162
double y
Definition: qgspointxy.h:48
A class to represent a 2D point.
Definition: qgspointxy.h:43
static QgsGeometry fromMultiPolylineXY(const QgsMultiPolylineXY &multiline)
Creates a new geometry from a QgsMultiPolylineXY object.
Container of fields for a vector layer.
Definition: qgsfields.h:42
QgsPointXY point() const
Returns point associated with graph vertex.
Definition: qgsgraph.cpp:114
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:122
void setAttributes(const QgsAttributes &attrs)
Sets the feature&#39;s attributes.
Definition: qgsfeature.cpp:127
QString toString(int precision=-1) const
Returns a string representation of the point (x, y) with a preset precision.
Definition: qgspointxy.cpp:51
QVector< QgsPointXY > QgsMultiPointXY
A collection of QgsPoints that share a common collection of attributes.
Definition: qgsgeometry.h:80
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
QVector< QgsPolylineXY > QgsMultiPolylineXY
A collection of QgsPolylines that share a common collection of attributes.
Definition: qgsgeometry.h:84
virtual void pushInfo(const QString &info)
Pushes a general informational message from the algorithm.
static QgsGeometry fromMultiPointXY(const QgsMultiPointXY &multipoint)
Creates a new geometry from a QgsMultiPointXY object.
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false) ...
Definition: qgsfields.cpp:59
QgsGraphEdgeIds outgoingEdges() const
Returns outgoing edge ids, i.e.
Definition: qgsgraph.cpp:109
int findVertex(const QgsPointXY &pt) const
Find vertex by associated point.
Definition: qgsgraph.cpp:65
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:49
A numeric parameter for processing algorithms.
QVariant cost(int strategyIndex) const
Returns edge cost calculated using specified strategy.
Definition: qgsgraph.cpp:78
Mathematical graph representation.
Definition: qgsgraph.h:141
double x
Definition: qgspointxy.h:47
QVector< QgsPointXY > QgsPolylineXY
Polyline as represented as a vector of two-dimensional points.
Definition: qgsgeometry.h:50
int toVertex() const
Returns the index of the vertex at the end of this edge.
Definition: qgsgraph.cpp:93
A point parameter for processing algorithms.
const QgsGraphVertex & vertex(int idx) const
Returns vertex at given index.
Definition: qgsgraph.cpp:45
Vector point layers.
Definition: qgsprocessing.h:48
Vector line layers.
Definition: qgsprocessing.h:49
void setGeometry(const QgsGeometry &geometry)
Set the feature&#39;s geometry.
Definition: qgsfeature.cpp:137
A vector of attributes.
Definition: qgsattributes.h:57
Contains information about the context in which a processing algorithm is executed.
static QgsPointXY interpolatePointOnLineByValue(double x1, double y1, double v1, double x2, double y2, double v2, double value)
Interpolates the position of a point along the line from (x1, y1) to (x2, y2).
This class implements a graph edge.
Definition: qgsgraph.h:43
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.