25QString QgsServiceAreaFromLayerAlgorithm::name()
const
27 return QStringLiteral(
"serviceareafromlayer" );
30QString QgsServiceAreaFromLayerAlgorithm::displayName()
const
32 return QObject::tr(
"Service area (from layer)" );
35QStringList QgsServiceAreaFromLayerAlgorithm::tags()
const
37 return QObject::tr(
"network,service,area,shortest,fastest" ).split(
',' );
40QString QgsServiceAreaFromLayerAlgorithm::shortHelpString()
const
42 return QObject::tr(
"This algorithm creates a new vector with all the edges or parts of "
43 "edges of a network line layer that can be reached within a distance "
44 "or a time, starting from features of a point layer. The distance and "
45 "the time (both referred to as \"travel cost\") must be specified "
46 "respectively in the network layer units or in hours." );
49QgsServiceAreaFromLayerAlgorithm *QgsServiceAreaFromLayerAlgorithm::createInstance()
const
51 return new QgsServiceAreaFromLayerAlgorithm();
54void QgsServiceAreaFromLayerAlgorithm::initAlgorithm(
const QVariantMap & )
59 std::unique_ptr< QgsProcessingParameterNumber > travelCost = std::make_unique< QgsProcessingParameterNumber >( QStringLiteral(
"TRAVEL_COST" ), QObject::tr(
"Travel cost (distance for 'Shortest', time for 'Fastest')" ),
Qgis::ProcessingNumberParameterType::Double, 0,
true, 0 );
61 addParameter( travelCost.release() );
63 addParameter(
new QgsProcessingParameterNumber( QStringLiteral(
"TRAVEL_COST2" ), QObject::tr(
"Travel cost (distance for 'Shortest', time for 'Fastest')" ),
66 std::unique_ptr< QgsProcessingParameterBoolean > includeBounds = std::make_unique< QgsProcessingParameterBoolean >( QStringLiteral(
"INCLUDE_BOUNDS" ), QObject::tr(
"Include upper/lower bound points" ),
false,
true );
68 addParameter( includeBounds.release() );
70 std::unique_ptr< QgsProcessingParameterNumber > maxPointDistanceFromNetwork = std::make_unique < QgsProcessingParameterDistance >( QStringLiteral(
"POINT_TOLERANCE" ), QObject::tr(
"Maximum point distance from network" ), QVariant(), QStringLiteral(
"INPUT" ),
true, 0 );
72 maxPointDistanceFromNetwork->setHelp( QObject::tr(
"Specifies an optional limit on the distance from the points to the network layer. If a point is further from the network than this distance it will be treated as non-routable." ) );
73 addParameter( maxPointDistanceFromNetwork.release() );
75 std::unique_ptr< QgsProcessingParameterFeatureSink > outputLines = std::make_unique< QgsProcessingParameterFeatureSink >( QStringLiteral(
"OUTPUT_LINES" ), QObject::tr(
"Service area (lines)" ),
77 outputLines->setCreateByDefault(
true );
78 addParameter( outputLines.release() );
80 std::unique_ptr< QgsProcessingParameterFeatureSink > outputPoints = std::make_unique< QgsProcessingParameterFeatureSink >( QStringLiteral(
"OUTPUT" ), QObject::tr(
"Service area (boundary nodes)" ),
82 outputPoints->setCreateByDefault(
false );
83 addParameter( outputPoints.release() );
85 std::unique_ptr< QgsProcessingParameterFeatureSink > outputNonRoutable = std::make_unique< QgsProcessingParameterFeatureSink >( QStringLiteral(
"OUTPUT_NON_ROUTABLE" ), QObject::tr(
"Non-routable features" ),
87 outputNonRoutable->setHelp( QObject::tr(
"An optional output which will be used to store any input features which could not be routed (e.g. those which are too far from the network layer)." ) );
88 outputNonRoutable->setCreateByDefault(
false );
89 addParameter( outputNonRoutable.release() );
94 loadCommonParams( parameters, context, feedback );
96 std::unique_ptr< QgsFeatureSource > startPoints( parameterAsSource( parameters, QStringLiteral(
"START_POINTS" ), context ) );
101 const bool useOldTravelCost = parameters.value( QStringLiteral(
"TRAVEL_COST" ) ).isValid();
102 double travelCost = parameterAsDouble( parameters, useOldTravelCost ? QStringLiteral(
"TRAVEL_COST" ) : QStringLiteral(
"TRAVEL_COST2" ), context );
104 int strategy = parameterAsInt( parameters, QStringLiteral(
"STRATEGY" ), context );
105 if ( strategy && !useOldTravelCost )
106 travelCost *= mMultiplier;
108 bool includeBounds =
true;
109 if ( parameters.contains( QStringLiteral(
"INCLUDE_BOUNDS" ) ) )
111 includeBounds = parameterAsBool( parameters, QStringLiteral(
"INCLUDE_BOUNDS" ), context );
114 QVector< QgsPointXY > points;
115 QHash< int, QgsAttributes > sourceAttributes;
116 loadPoints( startPoints.get(), points, sourceAttributes, context, feedback );
118 feedback->
pushInfo( QObject::tr(
"Building graph…" ) );
119 QVector< QgsPointXY > snappedPoints;
120 mDirector->makeGraph( mBuilder.get(), points, snappedPoints, feedback );
122 feedback->
pushInfo( QObject::tr(
"Calculating service areas…" ) );
123 std::unique_ptr< QgsGraph > graph( mBuilder->takeGraph() );
125 QgsFields fields = startPoints->fields();
126 fields.
append(
QgsField( QStringLiteral(
"type" ), QMetaType::Type::QString ) );
127 fields.
append(
QgsField( QStringLiteral(
"start" ), QMetaType::Type::QString ) );
129 QString pointsSinkId;
130 std::unique_ptr< QgsFeatureSink > pointsSink( parameterAsSink( parameters, QStringLiteral(
"OUTPUT" ), context, pointsSinkId, fields,
134 std::unique_ptr< QgsFeatureSink > linesSink( parameterAsSink( parameters, QStringLiteral(
"OUTPUT_LINES" ), context, linesSinkId, fields,
137 QString nonRoutableSinkId;
138 std::unique_ptr< QgsFeatureSink > nonRoutableSink( parameterAsSink( parameters, QStringLiteral(
"OUTPUT_NON_ROUTABLE" ), context, nonRoutableSinkId, startPoints->fields(),
141 const double pointDistanceThreshold = parameters.value( QStringLiteral(
"POINT_TOLERANCE" ) ).isValid() ? parameterAsDouble( parameters, QStringLiteral(
"POINT_TOLERANCE" ), context ) : -1;
145 QVector< double > costs;
147 int inboundEdgeIndex;
148 double startVertexCost, endVertexCost;
155 const double step = snappedPoints.size() > 0 ? 100.0 / snappedPoints.size() : 1;
156 for (
int i = 0; i < snappedPoints.size(); i++ )
163 const QgsPointXY snappedPoint = snappedPoints.at( i );
164 const QgsPointXY originalPoint = points.at( i );
166 if ( pointDistanceThreshold >= 0 )
168 const double distancePointToNetwork = mBuilder->distanceArea()->measureLine( originalPoint, snappedPoint );
169 if ( distancePointToNetwork > pointDistanceThreshold )
171 feedback->
pushWarning( QObject::tr(
"Point is too far from the network layer (%1, maximum permitted is %2)" ).arg( distancePointToNetwork ).arg( pointDistanceThreshold ) );
172 if ( nonRoutableSink )
175 attributes = sourceAttributes.value( i + 1 );
178 throw QgsProcessingException( writeFeatureError( nonRoutableSink.get(), parameters, QStringLiteral(
"OUTPUT_NON_ROUTABLE" ) ) );
186 const QString originalPointString = originalPoint.
toString();
188 idxStart = graph->findVertex( snappedPoint );
194 QSet< int > vertices;
196 for (
int j = 0; j < costs.size(); j++ )
198 inboundEdgeIndex = tree.at( j );
200 if ( inboundEdgeIndex == -1 && j != idxStart )
206 startVertexCost = costs.at( j );
207 if ( startVertexCost > travelCost )
213 vertices.insert( j );
214 startPoint = graph->vertex( j ).point();
217 const QList< int > outgoingEdges = graph->vertex( j ).outgoingEdges() ;
218 for (
int edgeId : outgoingEdges )
220 edge = graph->edge( edgeId );
221 endVertexCost = startVertexCost + edge.
cost( 0 ).toDouble();
222 endPoint = graph->vertex( edge.
toVertex() ).point();
223 if ( endVertexCost <= travelCost )
227 lines.push_back(
QgsPolylineXY() << startPoint << endPoint );
233 endPoint.
x(), endPoint.
y(), endVertexCost, travelCost );
235 areaPoints.push_back( interpolatedEndPoint );
236 lines.push_back(
QgsPolylineXY() << startPoint << interpolatedEndPoint );
242 QList< int > verticesList = qgis::setToList( vertices );
243 areaPoints.reserve( verticesList.size() );
244 std::sort( verticesList.begin(), verticesList.end() );
245 for (
int v : verticesList )
247 areaPoints.push_back( graph->vertex( v ).point() );
254 attributes = sourceAttributes.value( i + 1 );
255 attributes << QStringLiteral(
"within" ) << originalPointString;
258 throw QgsProcessingException( writeFeatureError( pointsSink.get(), parameters, QStringLiteral(
"OUTPUT" ) ) );
263 QVector< int > nodes;
264 nodes.reserve( costs.size() );
267 for (
int v = 0; v < costs.size(); v++ )
269 if ( costs.at( v ) > travelCost && tree.at( v ) != -1 )
271 vertexId = graph->edge( tree.at( v ) ).fromVertex();
272 if ( costs.at( vertexId ) <= travelCost )
274 nodes.push_back( v );
279 upperBoundary.reserve( nodes.size() );
280 lowerBoundary.reserve( nodes.size() );
281 for (
int n : std::as_const( nodes ) )
283 upperBoundary.push_back( graph->vertex( graph->edge( tree.at( n ) ).toVertex() ).point() );
284 lowerBoundary.push_back( graph->vertex( graph->edge( tree.at( n ) ).fromVertex() ).point() );
291 attributes = sourceAttributes.value( i + 1 );
292 attributes << QStringLiteral(
"upper" ) << originalPointString;
295 throw QgsProcessingException( writeFeatureError( pointsSink.get(), parameters, QStringLiteral(
"OUTPUT" ) ) );
298 attributes = sourceAttributes.value( i + 1 );
299 attributes << QStringLiteral(
"lower" ) << originalPointString;
302 throw QgsProcessingException( writeFeatureError( pointsSink.get(), parameters, QStringLiteral(
"OUTPUT" ) ) );
310 attributes = sourceAttributes.value( i + 1 );
311 attributes << QStringLiteral(
"lines" ) << originalPointString;
314 throw QgsProcessingException( writeFeatureError( linesSink.get(), parameters, QStringLiteral(
"OUTPUT_LINES" ) ) );
323 outputs.insert( QStringLiteral(
"OUTPUT" ), pointsSinkId );
327 outputs.insert( QStringLiteral(
"OUTPUT_LINES" ), linesSinkId );
329 if ( nonRoutableSink )
331 outputs.insert( QStringLiteral(
"OUTPUT_NON_ROUTABLE" ), nonRoutableSinkId );
@ 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.
@ 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 setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
bool isCanceled() const
Tells whether the operation has been canceled already.
void setProgress(double progress)
Sets the current progress for the feedback object.
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 QgsGeometry fromPointXY(const QgsPointXY &point)
Creates a new geometry from a QgsPointXY 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.
This class implements a graph edge.
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.
A class to represent a 2D point.
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.
virtual void pushWarning(const QString &warning)
Pushes a warning informational message from the algorithm.
An input feature source (such as vector layers) parameter for processing algorithms.
A numeric 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.