25 QString QgsServiceAreaFromLayerAlgorithm::name()
const
27 return QStringLiteral(
"serviceareafromlayer" );
30 QString QgsServiceAreaFromLayerAlgorithm::displayName()
const
32 return QObject::tr(
"Service area (from layer)" );
35 QStringList QgsServiceAreaFromLayerAlgorithm::tags()
const
37 return QObject::tr(
"network,service,area,shortest,fastest" ).split(
',' );
40 QString 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." );
49 QgsServiceAreaFromLayerAlgorithm *QgsServiceAreaFromLayerAlgorithm::createInstance()
const
51 return new QgsServiceAreaFromLayerAlgorithm();
54 void 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')" ),
QgsProcessingParameterNumber::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< QgsProcessingParameterFeatureSink > outputLines = std::make_unique< QgsProcessingParameterFeatureSink >( QStringLiteral(
"OUTPUT_LINES" ), QObject::tr(
"Service area (lines)" ),
72 outputLines->setCreateByDefault(
true );
73 addParameter( outputLines.release() );
75 std::unique_ptr< QgsProcessingParameterFeatureSink > outputPoints = std::make_unique< QgsProcessingParameterFeatureSink >( QStringLiteral(
"OUTPUT" ), QObject::tr(
"Service area (boundary nodes)" ),
77 outputPoints->setCreateByDefault(
false );
78 addParameter( outputPoints.release() );
83 loadCommonParams( parameters, context, feedback );
85 std::unique_ptr< QgsFeatureSource > startPoints( parameterAsSource( parameters, QStringLiteral(
"START_POINTS" ), context ) );
90 const bool useOldTravelCost = parameters.value( QStringLiteral(
"TRAVEL_COST" ) ).isValid();
91 double travelCost = parameterAsDouble( parameters, useOldTravelCost ? QStringLiteral(
"TRAVEL_COST" ) : QStringLiteral(
"TRAVEL_COST2" ), context );
93 int strategy = parameterAsInt( parameters, QStringLiteral(
"STRATEGY" ), context );
94 if ( strategy && !useOldTravelCost )
95 travelCost *= mMultiplier;
97 bool includeBounds =
true;
98 if ( parameters.contains( QStringLiteral(
"INCLUDE_BOUNDS" ) ) )
100 includeBounds = parameterAsBool( parameters, QStringLiteral(
"INCLUDE_BOUNDS" ), context );
103 QVector< QgsPointXY > points;
104 QHash< int, QgsAttributes > sourceAttributes;
105 loadPoints( startPoints.get(), points, sourceAttributes, context, feedback );
107 feedback->
pushInfo( QObject::tr(
"Building graph…" ) );
108 QVector< QgsPointXY > snappedPoints;
109 mDirector->makeGraph( mBuilder.get(), points, snappedPoints, feedback );
111 feedback->
pushInfo( QObject::tr(
"Calculating service areas…" ) );
112 std::unique_ptr< QgsGraph > graph( mBuilder->takeGraph() );
114 QgsFields fields = startPoints->fields();
115 fields.
append(
QgsField( QStringLiteral(
"type" ), QVariant::String ) );
116 fields.
append(
QgsField( QStringLiteral(
"start" ), QVariant::String ) );
118 QString pointsSinkId;
119 std::unique_ptr< QgsFeatureSink > pointsSink( parameterAsSink( parameters, QStringLiteral(
"OUTPUT" ), context, pointsSinkId, fields,
123 std::unique_ptr< QgsFeatureSink > linesSink( parameterAsSink( parameters, QStringLiteral(
"OUTPUT_LINES" ), context, linesSinkId, fields,
129 QVector< double > costs;
131 int inboundEdgeIndex;
132 double startVertexCost, endVertexCost;
139 const double step = snappedPoints.size() > 0 ? 100.0 / snappedPoints.size() : 1;
140 for (
int i = 0; i < snappedPoints.size(); i++ )
147 idxStart = graph->findVertex( snappedPoints.at( i ) );
148 origPoint = points.at( i ).toString();
154 QSet< int > vertices;
156 for (
int j = 0; j < costs.size(); j++ )
158 inboundEdgeIndex = tree.at( j );
160 if ( inboundEdgeIndex == -1 && j != idxStart )
166 startVertexCost = costs.at( j );
167 if ( startVertexCost > travelCost )
173 vertices.insert( j );
174 startPoint = graph->vertex( j ).point();
177 const QList< int > outgoingEdges = graph->vertex( j ).outgoingEdges() ;
178 for (
int edgeId : outgoingEdges )
180 edge = graph->edge( edgeId );
181 endVertexCost = startVertexCost + edge.
cost( 0 ).toDouble();
182 endPoint = graph->vertex( edge.
toVertex() ).point();
183 if ( endVertexCost <= travelCost )
187 lines.push_back(
QgsPolylineXY() << startPoint << endPoint );
193 endPoint.
x(), endPoint.
y(), endVertexCost, travelCost );
195 areaPoints.push_back( interpolatedEndPoint );
196 lines.push_back(
QgsPolylineXY() << startPoint << interpolatedEndPoint );
202 QList< int > verticesList = qgis::setToList( vertices );
203 areaPoints.reserve( verticesList.size() );
204 std::sort( verticesList.begin(), verticesList.end() );
205 for (
int v : verticesList )
207 areaPoints.push_back( graph->vertex( v ).point() );
214 attributes = sourceAttributes.value( i + 1 );
215 attributes << QStringLiteral(
"within" ) << origPoint;
218 throw QgsProcessingException( writeFeatureError( pointsSink.get(), parameters, QStringLiteral(
"OUTPUT" ) ) );
223 QVector< int > nodes;
224 nodes.reserve( costs.size() );
227 for (
int v = 0; v < costs.size(); v++ )
229 if ( costs.at( v ) > travelCost && tree.at( v ) != -1 )
231 vertexId = graph->edge( tree.at( v ) ).fromVertex();
232 if ( costs.at( vertexId ) <= travelCost )
234 nodes.push_back( v );
239 upperBoundary.reserve( nodes.size() );
240 lowerBoundary.reserve( nodes.size() );
241 for (
int n : std::as_const( nodes ) )
243 upperBoundary.push_back( graph->vertex( graph->edge( tree.at( n ) ).toVertex() ).point() );
244 lowerBoundary.push_back( graph->vertex( graph->edge( tree.at( n ) ).fromVertex() ).point() );
251 attributes = sourceAttributes.value( i + 1 );
252 attributes << QStringLiteral(
"upper" ) << origPoint;
255 throw QgsProcessingException( writeFeatureError( pointsSink.get(), parameters, QStringLiteral(
"OUTPUT" ) ) );
258 attributes = sourceAttributes.value( i + 1 );
259 attributes << QStringLiteral(
"lower" ) << origPoint;
262 throw QgsProcessingException( writeFeatureError( pointsSink.get(), parameters, QStringLiteral(
"OUTPUT" ) ) );
270 attributes = sourceAttributes.value( i + 1 );
271 attributes << QStringLiteral(
"lines" ) << origPoint;
274 throw QgsProcessingException( writeFeatureError( linesSink.get(), parameters, QStringLiteral(
"OUTPUT_LINES" ) ) );
283 outputs.insert( QStringLiteral(
"OUTPUT" ), pointsSinkId );
287 outputs.insert( QStringLiteral(
"OUTPUT_LINES" ), linesSinkId );