QGIS 3.22.9 – Storing Shortest Path Route Efficiently

qgisrouteshortest path

I used the shortest path tool in QGIS 3.22 to find the shortest route from the node "1000" to node "1004" in my project. The result is shown in red around my road layers (links) in the image below.

enter image description here

Is there a way to store somewhere or export in Excel the route (links crossed in the right order, i.e. providing a list of the successive Link_ID crossed using their Link_ID in red on the pic: 1,2,4,3) ?

I tried but could not find using QGIS tools. The end objective is to calculate traffic along roads (links) and displaying them as a traffic map.

Best Answer

Use this expression to get a comma separated list of LinkID values from the layer called network:

array_to_string (overlay_contains ('network', LinkID))

The expression, used here for visualization purpose as a dynamic label: enter image description here

Create a new field with Field calculator, copy the value from there and paste it to Excel or wherever you need the values. To get each value on a new row, add ,delimiter:= '\n' at the end of the expression above, before the last closing bracket )

enter image description here


Edit: in my case, the segments are ordered in the correct way. If this is not the case, as in the test data you shared, the approach is a bit more complex. The first line of the expression creates a variable with the name of your test layer - rename it accordingly (see below for explanation):

with_variable ('ly', 'test', -- replace here: name of your network layer
array_to_string(  -- step 8
    array_foreach (
        array_sort (  -- step 5
            array_foreach (
                overlay_contains (@ly, $id),  -- step 1
                line_locate_point (  -- step 3
                    $geometry, 
                    centroid (geometry (get_feature_by_id (@ly,@element))) --step 2
                ) || ',' || @element  -- step 4
            )
        ), 
        attribute (  -- step 7
            get_feature_by_id (
                @ly,
                regexp_replace (@element,'(.*,)','')  -- step 6
            ),
            'Link_ID'
        )
    )
))

enter image description here

Explanantion:

  1. Create an array of all the feature ids ($id) for each segment that is covered by the shortest path, using overlay_contains()

  2. Get the centroid of each covered segment with centroid()

  3. Get the distance each centroid is away from the start point of the shortest, along the shortest path line with line_locate_point() and by converting the $id value from step 1 to the feature's geometry with geometry()

  4. Add the features's id (the $id from the array in step 1) after this distance (concatenate with || and insert ',' as delimiter) by calling the @element inside an array_foreach() loop

    You get an array where each elements consist of two parts, separated by comma: distance from start point,$id (pseudocode)

  5. Sort the array with array_sort(). Like this, the shortest distance (corresponding to the first covered segment) is at the beginning

  6. Now get rid of the distance, keeping only the $id, the second part of each element in the array, using regexp_replace()

  7. You have now the $id values in the order the segments are covered. If you want to get an attribute value instead, access it, based on the feature id ($id) with attribute()

  8. Convert the array to a string with array_to_string()

Related Question