25using namespace Qt::StringLiterals;
29QString QgsServiceAreaFromPointAlgorithm::name()
const
31 return u
"serviceareafrompoint"_s;
34QString QgsServiceAreaFromPointAlgorithm::displayName()
const
36 return QObject::tr(
"Service area (from point)" );
39QStringList QgsServiceAreaFromPointAlgorithm::tags()
const
41 return QObject::tr(
"network,service,area,shortest,fastest" ).split(
',' );
44QString QgsServiceAreaFromPointAlgorithm::shortHelpString()
const
46 return QObject::tr(
"This algorithm creates a new vector layer with all the edges or parts of edges "
47 "of a network line layer that can be reached within a distance or a time, "
48 "starting from a point feature. The distance and the time (both referred to "
49 "as \"travel cost\") must be specified respectively in the network layer "
50 "units or in hours." );
53QString QgsServiceAreaFromPointAlgorithm::shortDescription()
const
55 return QObject::tr(
"Creates a vector layer with all the edges or parts of edges "
56 "of a network line layer that can be reached within a distance or a time, "
57 "starting from a point feature." );
60QgsServiceAreaFromPointAlgorithm *QgsServiceAreaFromPointAlgorithm::createInstance()
const
62 return new QgsServiceAreaFromPointAlgorithm();
65void QgsServiceAreaFromPointAlgorithm::initAlgorithm(
const QVariantMap & )
70 auto travelCost = std::make_unique<QgsProcessingParameterNumber>( u
"TRAVEL_COST"_s, QObject::tr(
"Travel cost (distance for 'Shortest', time for 'Fastest')" ),
Qgis::ProcessingNumberParameterType::Double, 0,
true, 0 );
72 addParameter( travelCost.release() );
76 std::unique_ptr<QgsProcessingParameterNumber> maxPointDistanceFromNetwork = std::make_unique<QgsProcessingParameterDistance>( u
"POINT_TOLERANCE"_s, QObject::tr(
"Maximum point distance from network" ), QVariant(), u
"INPUT"_s,
true, 0 );
78 maxPointDistanceFromNetwork->setHelp( QObject::tr(
"Specifies an optional limit on the distance from the point to the network layer. If the point is further from the network than this distance an error will be raised." ) );
79 addParameter( maxPointDistanceFromNetwork.release() );
81 auto includeBounds = std::make_unique<QgsProcessingParameterBoolean>( u
"INCLUDE_BOUNDS"_s, QObject::tr(
"Include upper/lower bound points" ),
false,
true );
83 addParameter( includeBounds.release() );
85 auto outputLines = std::make_unique<QgsProcessingParameterFeatureSink>( u
"OUTPUT_LINES"_s, QObject::tr(
"Service area (lines)" ),
Qgis::ProcessingSourceType::VectorLine, QVariant(),
true );
86 outputLines->setCreateByDefault(
true );
87 addParameter( outputLines.release() );
89 auto outputPoints = std::make_unique<QgsProcessingParameterFeatureSink>( u
"OUTPUT"_s, QObject::tr(
"Service area (boundary nodes)" ),
Qgis::ProcessingSourceType::VectorPoint, QVariant(),
true );
90 outputPoints->setCreateByDefault(
false );
91 addParameter( outputPoints.release() );
96 loadCommonParams( parameters, context, feedback );
98 const QgsPointXY startPoint = parameterAsPoint( parameters, u
"START_POINT"_s, context, mNetwork->sourceCrs() );
101 const bool useOldTravelCost = parameters.value( u
"TRAVEL_COST"_s ).isValid();
102 double travelCost = parameterAsDouble( parameters, useOldTravelCost ? u
"TRAVEL_COST"_s : u
"TRAVEL_COST2"_s, context );
104 const int strategy = parameterAsInt( parameters, u
"STRATEGY"_s, context );
105 if ( strategy && !useOldTravelCost )
106 travelCost *= mMultiplier;
108 bool includeBounds =
true;
109 if ( parameters.contains( u
"INCLUDE_BOUNDS"_s ) )
111 includeBounds = parameterAsBool( parameters, u
"INCLUDE_BOUNDS"_s, context );
114 feedback->
pushInfo( QObject::tr(
"Building graph…" ) );
115 QVector<QgsPointXY> snappedPoints;
116 mDirector->makeGraph( mBuilder.get(), { startPoint }, snappedPoints, feedback );
117 const QgsPointXY snappedStartPoint = snappedPoints[0];
120 if ( parameters.value( u
"POINT_TOLERANCE"_s ).isValid() )
122 const double pointDistanceThreshold = parameterAsDouble( parameters, u
"POINT_TOLERANCE"_s, context );
124 double distancePointToNetwork = 0;
127 distancePointToNetwork = mBuilder->distanceArea()->measureLine( startPoint, snappedStartPoint );
135 if ( distancePointToNetwork > pointDistanceThreshold )
137 throw QgsProcessingException( QObject::tr(
"Point is too far from the network layer (%1, maximum permitted is %2)" ).arg( distancePointToNetwork ).arg( pointDistanceThreshold ) );
141 feedback->
pushInfo( QObject::tr(
"Calculating service area…" ) );
142 std::unique_ptr<QgsGraph> graph( mBuilder->takeGraph() );
143 const int idxStart = graph->findVertex( snappedStartPoint );
146 QVector<double> costs;
153 int inboundEdgeIndex;
154 double startVertexCost, endVertexCost;
158 for (
int i = 0; i < costs.size(); i++ )
160 inboundEdgeIndex = tree.at( i );
161 if ( inboundEdgeIndex == -1 && i != idxStart )
167 startVertexCost = costs.at( i );
168 if ( startVertexCost > travelCost )
174 vertices.insert( i );
175 edgeStart = graph->vertex( i ).point();
178 const QList<int> outgoingEdges = graph->vertex( i ).outgoingEdges();
179 for (
const int edgeId : outgoingEdges )
181 edge = graph->edge( edgeId );
182 endVertexCost = startVertexCost + edge.
cost( 0 ).toDouble();
183 edgeEnd = graph->vertex( edge.
toVertex() ).point();
184 if ( endVertexCost <= travelCost )
195 points.push_back( interpolatedEndPoint );
196 lines.push_back(
QgsPolylineXY() << edgeStart << interpolatedEndPoint );
202 QList<int> verticesList = qgis::setToList( vertices );
203 points.reserve( verticesList.size() );
204 std::sort( verticesList.begin(), verticesList.end() );
205 for (
const int v : verticesList )
207 points.push_back( graph->vertex( v ).point() );
210 feedback->
pushInfo( QObject::tr(
"Writing results…" ) );
216 fields.
append(
QgsField( u
"start"_s, QMetaType::Type::QString ) );
221 QString pointsSinkId;
222 std::unique_ptr<QgsFeatureSink> pointsSink( parameterAsSink( parameters, u
"OUTPUT"_s, context, pointsSinkId, fields,
Qgis::WkbType::MultiPoint, mNetwork->sourceCrs() ) );
226 outputs.insert( u
"OUTPUT"_s, pointsSinkId );
240 for (
int i = 0; i < costs.size(); i++ )
242 if ( costs.at( i ) > travelCost && tree.at( i ) != -1 )
244 vertexId = graph->edge( tree.at( i ) ).fromVertex();
245 if ( costs.at( vertexId ) <= travelCost )
247 nodes.push_back( i );
252 upperBoundary.reserve( nodes.size() );
253 lowerBoundary.reserve( nodes.size() );
254 for (
const int i : nodes )
256 upperBoundary.push_back( graph->vertex( graph->edge( tree.at( i ) ).toVertex() ).point() );
257 lowerBoundary.push_back( graph->vertex( graph->edge( tree.at( i ) ).fromVertex() ).point() );
274 pointsSink->finalize();
278 std::unique_ptr<QgsFeatureSink> linesSink( parameterAsSink( parameters, u
"OUTPUT_LINES"_s, context, linesSinkId, fields,
Qgis::WkbType::MultiLineString, mNetwork->sourceCrs() ) );
282 outputs.insert( u
"OUTPUT_LINES"_s, linesSinkId );
288 linesSink->finalize();
@ VectorPoint
Vector point layers.
@ VectorLine
Vector line layers.
@ MultiLineString
MultiLineString.
@ Hidden
Parameter is hidden and should not be shown to users.
@ Advanced
Parameter is an advanced parameter which should be hidden from users by default.
@ Double
Double/float values.
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...
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.
Container of fields for a vector layer.
bool append(const QgsField &field, Qgis::FieldOrigin origin=Qgis::FieldOrigin::Provider, int originIndex=-1)
Appends a field.
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).
A geometry is the spatial representation of a feature.
static QgsGeometry fromMultiPolylineXY(const QgsMultiPolylineXY &multiline)
Creates a new geometry from a QgsMultiPolylineXY object.
static QgsGeometry fromMultiPointXY(const QgsMultiPointXY &multipoint)
Creates a new geometry from a QgsMultiPointXY object.
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 an edge in a graph.
int toVertex() const
Returns the index of the vertex at the end of this edge.
QVariant cost(int strategyIndex) const
Returns edge cost calculated using specified strategy.
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 parameter for processing algorithms.
A point parameter for processing algorithms.
QVector< QgsPolylineXY > QgsMultiPolylineXY
A collection of QgsPolylines that share a common collection of attributes.
QVector< QgsPointXY > QgsMultiPointXY
A collection of QgsPoints that share a common collection of attributes.
QVector< QgsPointXY > QgsPolylineXY
Polyline as represented as a vector of two-dimensional points.