# Distance matrix along line layer

I have a point layer which represent transport stops. Each stops have an id and the transport line id.

I would like to have calculated the distance between every stops on the same transport line (closest one is enough). In the example attached, I would like the distance between Stop B1 and Stop B2, the distance between stop B2 and stop B3 etc.

Is this possible within QGIS? With distance matrix?

• I don't think you can do it with a matrix distance. matrix distance is just a table that give feature by feature the distance between one another. I know how to solve your issue with Postgres/postgis and St_lineInterpolate / St_length. For a plain Qgis solution, you can split your road by your points and keep the length of each part (it's what you want). Commented Sep 9, 2021 at 11:59
• The distance to previous and next stop as atribute to each point is what I am looking for yes @BERA Commented Sep 9, 2021 at 12:54
• I have 7600 bus stops and 140 lines. I would rather prefer a unique way to do it rather than split the work in 140 parts... @Maximilienjaffrès Commented Sep 9, 2021 at 12:54

To calculate the distance between two points along a line geometry, you can use QGIS expressions based on the following functions (see below how to combine these elements). Points not even have to be exactly on the line, it works even if the point is slightly away: it then automatically takes the nearest point on the line.

Let's suppose you have (change the names accordingly in the expression below if using other names):

1. A line layer called `line` with an attribute `line_id`.
2. A point layer calles `stops` with an attribute `id` (that numbers the points in the correct sequence: from the first to the next etc.) and another attribute `on_line` (indicating on what line the point lies). If you don't have such a field, see below (edit 3).

On the point layer, calculate the length from each point to the next one with this expression (e.g. using Field calculator to create a new attribute). To get the previous point, replace `+1` at the end of line 10 with `-1`.

``````length(
line_substring(
geometry (get_feature ('line','line_id', on_line)),
line_locate_point(
geometry (get_feature ('line','line_id', on_line)),
geometry (get_feature_by_id (@layer, id))
),
line_locate_point(
geometry (get_feature ('line','line_id', on_line)),
geometry (get_feature_by_id (@layer, id+1))
)
)
)
``````

Screenshot: the distance from each white point to the next one along the corresponding line is calcluated; the label of each points shows the distance to the next one on the same line: the yellow line shows one of the segments, the one that has a distance of 21.92. The last point in each line has no distance as there is no next point:

Edit 1

If you have your `id` field in the stop (point) layer in a string format as on your screenshot (like `Stop A1`, `Stop B22`, `Stop C15` etc.), use this expression to extract the digits to create an integer id-field:

``````regexp_substr ("id", '(\\d+)')
``````

Edit 2

As both your layers are in CRS `EPSG:4326`, the results are in degrees, not in meters. This does not make sense. There are two options to solve this: either reproject both layers to a CRS using meters as units (e.g. local UTM zone). Or use a slightly modified expressions that automatically handles this issue. Just replace `3857` in the second last line with the EPSG-code of the CRS you want to use:

``````length (
transform (
line_substring(
geometry (get_feature ('line','line_id', on_line)),
line_locate_point(
geometry (get_feature ('line','line_id', on_line)),
geometry (get_feature_by_id (@layer, id))
),
line_locate_point(
geometry (get_feature ('line','line_id', on_line)),
geometry (get_feature_by_id (@layer, id+1))
)
)
,@layer_crs,
'EPSG:3857'
))
``````

Edit 3

It even works if you donf't have a field `on_line`. You can get this information as part of the expression with `overlay_nearest` In this case, replace `geometry (get_feature ('line','line_id', on_line))` with `array_first (overlay_nearest ('line', \$geometry))` - so the expression looks like:

``````length(
line_substring(
array_first (overlay_nearest ('line', \$geometry)),
line_locate_point(
array_first (overlay_nearest ('line', \$geometry)),
geometry (get_feature_by_id (@layer, id))
),
line_locate_point(
array_first (overlay_nearest ('line', \$geometry)),
geometry (get_feature_by_id (@layer, id+1))
)
)
)
``````
• hi, thank you for this complete tuto. As my stop_id field is a string text this do not work. I'am trying to extract a part of this field to try your method. Will keep you update Commented Sep 9, 2021 at 13:24
• You can create another field, e.g. using `\$id`: if the points were created in the right order, this should be enough. Commented Sep 9, 2021 at 13:25
• Adeed a way to extract the number out of your string - see bottom of the solution. Commented Sep 9, 2021 at 13:33
• I have already an id field with unique id (but not unique for each route, unique for the complete table tehrefore there is 7600 ids). I've tried with this field and could run the expression. But lengh result looks completely false. Got '0,0052051305248736303' as a result when expect around 500m (verified within QGIS with distance tool'. Maybe I've done something wrong. Commented Sep 9, 2021 at 14:03
• That's why it doesn't work: your results are in degrees, not meters. This does not make sense. I added a solution for this above, at the bottom, Edit 2 Commented Sep 9, 2021 at 14:17