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 layer 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." );
 
   49QString QgsServiceAreaFromLayerAlgorithm::shortDescription()
 const 
   51  return QObject::tr( 
"Creates a vector layer with all the edges or parts of " 
   52                      "edges of a network line layer that can be reached within a distance " 
   53                      "or a time, starting from features of a point layer." );
 
   56QgsServiceAreaFromLayerAlgorithm *QgsServiceAreaFromLayerAlgorithm::createInstance()
 const 
   58  return new QgsServiceAreaFromLayerAlgorithm();
 
   61void QgsServiceAreaFromLayerAlgorithm::initAlgorithm( 
const QVariantMap & )
 
   66  auto travelCost = std::make_unique<QgsProcessingParameterNumber>( QStringLiteral( 
"TRAVEL_COST" ), QObject::tr( 
"Travel cost (distance for 'Shortest', time for 'Fastest')" ), 
Qgis::ProcessingNumberParameterType::Double, 0, 
true, 0 );
 
   68  addParameter( std::move( travelCost ) );
 
   70  auto travelCost2 = std::make_unique<QgsProcessingParameterNumber>( QStringLiteral( 
"TRAVEL_COST2" ), QObject::tr( 
"Travel cost (distance for 'Shortest', time for 'Fastest')" ), 
Qgis::ProcessingNumberParameterType::Double, 0, 
false, 0 );
 
   71  travelCost2->setIsDynamic( 
true );
 
   73  travelCost2->setDynamicLayerParameterName( QStringLiteral( 
"START_POINTS" ) );
 
   74  addParameter( std::move( travelCost2 ) );
 
   76  auto includeBounds = std::make_unique<QgsProcessingParameterBoolean>( QStringLiteral( 
"INCLUDE_BOUNDS" ), QObject::tr( 
"Include upper/lower bound points" ), 
false, 
true );
 
   78  addParameter( includeBounds.release() );
 
   80  std::unique_ptr<QgsProcessingParameterNumber> maxPointDistanceFromNetwork = std::make_unique<QgsProcessingParameterDistance>( QStringLiteral( 
"POINT_TOLERANCE" ), QObject::tr( 
"Maximum point distance from network" ), QVariant(), QStringLiteral( 
"INPUT" ), 
true, 0 );
 
   82  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." ) );
 
   83  addParameter( maxPointDistanceFromNetwork.release() );
 
   85  auto outputLines = std::make_unique<QgsProcessingParameterFeatureSink>( QStringLiteral( 
"OUTPUT_LINES" ), 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>( QStringLiteral( 
"OUTPUT" ), QObject::tr( 
"Service area (boundary nodes)" ), 
Qgis::ProcessingSourceType::VectorPoint, QVariant(), 
true );
 
   90  outputPoints->setCreateByDefault( 
false );
 
   91  addParameter( outputPoints.release() );
 
   93  auto outputNonRoutable = std::make_unique<QgsProcessingParameterFeatureSink>( QStringLiteral( 
"OUTPUT_NON_ROUTABLE" ), QObject::tr( 
"Non-routable features" ), 
Qgis::ProcessingSourceType::VectorPoint, QVariant(), 
true );
 
   94  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)." ) );
 
   95  outputNonRoutable->setCreateByDefault( 
false );
 
   96  addParameter( outputNonRoutable.release() );
 
  101  loadCommonParams( parameters, context, feedback );
 
  103  std::unique_ptr<QgsProcessingFeatureSource> startPoints( parameterAsSource( parameters, QStringLiteral( 
"START_POINTS" ), context ) );
 
  108  const bool useOldTravelCost = parameters.value( QStringLiteral( 
"TRAVEL_COST" ) ).isValid();
 
  109  const double defaultTravelCost = parameterAsDouble( parameters, useOldTravelCost ? QStringLiteral( 
"TRAVEL_COST" ) : QStringLiteral( 
"TRAVEL_COST2" ), context );
 
  112  QgsExpressionContext expressionContext = createExpressionContext( parameters, context, startPoints.get() );
 
  114  if ( dynamicTravelCost )
 
  116    travelCostProperty = parameters.
value( QStringLiteral( 
"TRAVEL_COST2" ) ).value<
QgsProperty>();
 
  119  const int strategy = parameterAsInt( parameters, QStringLiteral( 
"STRATEGY" ), context );
 
  120  const double multiplier = ( strategy && !useOldTravelCost ) ? mMultiplier : 1;
 
  122  bool includeBounds = 
true; 
 
  123  if ( parameters.contains( QStringLiteral( 
"INCLUDE_BOUNDS" ) ) )
 
  125    includeBounds = parameterAsBool( parameters, QStringLiteral( 
"INCLUDE_BOUNDS" ), context );
 
  128  QVector<QgsPointXY> points;
 
  129  QHash<int, QgsFeature> sourceFeatures;
 
  130  loadPoints( startPoints.get(), &points, 
nullptr, context, feedback, &sourceFeatures );
 
  132  feedback->
pushInfo( QObject::tr( 
"Building graph…" ) );
 
  133  QVector<QgsPointXY> snappedPoints;
 
  134  mDirector->makeGraph( mBuilder.get(), points, snappedPoints, feedback );
 
  136  feedback->
pushInfo( QObject::tr( 
"Calculating service areas…" ) );
 
  137  std::unique_ptr<QgsGraph> graph( mBuilder->takeGraph() );
 
  140  newFields.
append( 
QgsField( QStringLiteral( 
"type" ), QMetaType::Type::QString ) );
 
  141  newFields.
append( 
QgsField( QStringLiteral( 
"start" ), QMetaType::Type::QString ) );
 
  144  QString pointsSinkId;
 
  145  std::unique_ptr<QgsFeatureSink> pointsSink( parameterAsSink( parameters, QStringLiteral( 
"OUTPUT" ), context, pointsSinkId, fields, 
Qgis::WkbType::MultiPoint, mNetwork->sourceCrs() ) );
 
  148  std::unique_ptr<QgsFeatureSink> linesSink( parameterAsSink( parameters, QStringLiteral( 
"OUTPUT_LINES" ), context, linesSinkId, fields, 
Qgis::WkbType::MultiLineString, mNetwork->sourceCrs() ) );
 
  150  QString nonRoutableSinkId;
 
  151  std::unique_ptr<QgsFeatureSink> nonRoutableSink( parameterAsSink( parameters, QStringLiteral( 
"OUTPUT_NON_ROUTABLE" ), context, nonRoutableSinkId, startPoints->fields(), 
Qgis::WkbType::Point, mNetwork->sourceCrs() ) );
 
  153  const double pointDistanceThreshold = parameters.value( QStringLiteral( 
"POINT_TOLERANCE" ) ).isValid() ? parameterAsDouble( parameters, QStringLiteral( 
"POINT_TOLERANCE" ), context ) : -1;
 
  157  QVector<double> costs;
 
  159  int inboundEdgeIndex;
 
  160  double startVertexCost, endVertexCost;
 
  167  const double step = snappedPoints.size() > 0 ? 100.0 / snappedPoints.size() : 1;
 
  168  for ( 
int i = 0; i < snappedPoints.size(); i++ )
 
  175    double travelCost = defaultTravelCost;
 
  176    if ( dynamicTravelCost )
 
  178      expressionContext.
setFeature( sourceFeatures.value( i + 1 ) );
 
  179      travelCost = travelCostProperty.
valueAsDouble( expressionContext, travelCost );
 
  181    travelCost *= multiplier;
 
  183    const QgsPointXY snappedPoint = snappedPoints.at( i );
 
  184    const QgsPointXY originalPoint = points.at( i );
 
  186    if ( pointDistanceThreshold >= 0 )
 
  188      double distancePointToNetwork = 0;
 
  191        distancePointToNetwork = mBuilder->distanceArea()->measureLine( originalPoint, snappedPoint );
 
  198      if ( distancePointToNetwork > pointDistanceThreshold )
 
  200        feedback->
pushWarning( QObject::tr( 
"Point is too far from the network layer (%1, maximum permitted is %2)" ).arg( distancePointToNetwork ).arg( pointDistanceThreshold ) );
 
  201        if ( nonRoutableSink )
 
  204          attributes = sourceFeatures.value( i + 1 ).attributes();
 
  207            throw QgsProcessingException( writeFeatureError( nonRoutableSink.get(), parameters, QStringLiteral( 
"OUTPUT_NON_ROUTABLE" ) ) );
 
  215    const QString originalPointString = originalPoint.
toString();
 
  217    idxStart = graph->findVertex( snappedPoint );
 
  225    for ( 
int j = 0; j < costs.size(); j++ )
 
  227      inboundEdgeIndex = tree.at( j );
 
  229      if ( inboundEdgeIndex == -1 && j != idxStart )
 
  235      startVertexCost = costs.at( j );
 
  236      if ( startVertexCost > travelCost )
 
  242      vertices.insert( j );
 
  243      startPoint = graph->vertex( j ).point();
 
  246      const QList<int> outgoingEdges = graph->vertex( j ).outgoingEdges();
 
  247      for ( 
int edgeId : outgoingEdges )
 
  249        edge = graph->edge( edgeId );
 
  250        endVertexCost = startVertexCost + edge.
cost( 0 ).toDouble();
 
  251        endPoint = graph->vertex( edge.
toVertex() ).point();
 
  252        if ( endVertexCost <= travelCost )
 
  256          lines.push_back( 
QgsPolylineXY() << startPoint << endPoint );
 
  263          areaPoints.push_back( interpolatedEndPoint );
 
  264          lines.push_back( 
QgsPolylineXY() << startPoint << interpolatedEndPoint );
 
  270    QList<int> verticesList = qgis::setToList( vertices );
 
  271    areaPoints.reserve( verticesList.size() );
 
  272    std::sort( verticesList.begin(), verticesList.end() );
 
  273    for ( 
int v : verticesList )
 
  275      areaPoints.push_back( graph->vertex( v ).point() );
 
  282      attributes = sourceFeatures.value( i + 1 ).attributes();
 
  283      attributes << QStringLiteral( 
"within" ) << originalPointString;
 
  286        throw QgsProcessingException( writeFeatureError( pointsSink.get(), parameters, QStringLiteral( 
"OUTPUT" ) ) );
 
  292        nodes.reserve( costs.size() );
 
  295        for ( 
int v = 0; v < costs.size(); v++ )
 
  297          if ( costs.at( v ) > travelCost && tree.at( v ) != -1 )
 
  299            vertexId = graph->edge( tree.at( v ) ).fromVertex();
 
  300            if ( costs.at( vertexId ) <= travelCost )
 
  302              nodes.push_back( v );
 
  307        upperBoundary.reserve( nodes.size() );
 
  308        lowerBoundary.reserve( nodes.size() );
 
  309        for ( 
int n : std::as_const( nodes ) )
 
  311          upperBoundary.push_back( graph->vertex( graph->edge( tree.at( n ) ).toVertex() ).point() );
 
  312          lowerBoundary.push_back( graph->vertex( graph->edge( tree.at( n ) ).fromVertex() ).point() );
 
  319        attributes = sourceFeatures.value( i + 1 ).attributes();
 
  320        attributes << QStringLiteral( 
"upper" ) << originalPointString;
 
  323          throw QgsProcessingException( writeFeatureError( pointsSink.get(), parameters, QStringLiteral( 
"OUTPUT" ) ) );
 
  326        attributes = sourceFeatures.value( i + 1 ).attributes();
 
  327        attributes << QStringLiteral( 
"lower" ) << originalPointString;
 
  330          throw QgsProcessingException( writeFeatureError( pointsSink.get(), parameters, QStringLiteral( 
"OUTPUT" ) ) );
 
  338      attributes = sourceFeatures.value( i + 1 ).attributes();
 
  339      attributes << QStringLiteral( 
"lines" ) << originalPointString;
 
  342        throw QgsProcessingException( writeFeatureError( linesSink.get(), parameters, QStringLiteral( 
"OUTPUT_LINES" ) ) );
 
  351    pointsSink->finalize();
 
  352    outputs.insert( QStringLiteral( 
"OUTPUT" ), pointsSinkId );
 
  356    linesSink->finalize();
 
  357    outputs.insert( QStringLiteral( 
"OUTPUT_LINES" ), linesSinkId );
 
  359  if ( nonRoutableSink )
 
  361    nonRoutableSink->finalize();
 
  362    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.
 
Custom exception class for Coordinate Reference System related exceptions.
 
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
 
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
 
@ 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.
 
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.
 
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.
 
static bool isDynamic(const QVariantMap ¶meters, const QString &name)
Returns true if the parameter with matching name is a dynamic parameter, and must be evaluated once f...
 
static QgsFields combineFields(const QgsFields &fieldsA, const QgsFields &fieldsB, const QString &fieldsBPrefix=QString())
Combines two field lists, avoiding duplicate field names (in a case-insensitive manner).
 
Definition for a property.
 
@ DoublePositive
Positive double value (including 0)
 
A store for object properties.
 
QVariant value(const QgsExpressionContext &context, const QVariant &defaultValue=QVariant(), bool *ok=nullptr) const
Calculates the current value of the property, including any transforms which are set for the property...
 
double valueAsDouble(const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property and interprets it as a double.
 
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.