11

I've seen a lot of questions involving splitting a line with the help of a point layer.

I want to split a line into fractions of its length.

For example, I have a line 400 meters long, I want to split it into four lines of 100 meters long each.

There is the grass module v.split, but I get an error message when I start it from the qgis toolbox :

*"TypeError: object of type 'NoneType' has no len()"*

So I'm not sure if I get it to work if this would be a solution.

Taras
  • 32,823
  • 4
  • 66
  • 137
Gilles
  • 395
  • 3
  • 12

2 Answers2

10

The v.split.length function from GRASS should do exactly what you want by splitting the line into equal segments defined by the user without the need for a point layer. Here's a simple example of a straight line (it also works on non-straight and multiple lines):

Simple line

I added a column to calculate its length using $length in the expression:

Line attribute

Using the v.split.length function from GRASS via the Processing Toolbox, I chose to split the line into 25m segments which should make a total of 4 parts:

v.split.length function

I then updated the Length column of the output layer and used the same command as above to re-calculate the length:

Attribute result

Not sure why you are receiving the error, could you share your line layer for people to test?

Joseph
  • 75,746
  • 7
  • 171
  • 282
  • Hello, thanks for your answer. It is working. It's not splitting the line in fractions of the lenght though, as I still have to calculate the number of segments from the measured length, but it's a good workaround. Thank you. – Gilles Oct 22 '14 at 15:31
  • Apologies for not giving you a definitive answer but I'm glad it's a workaround atleast. Most welcome buddy! – Joseph Oct 23 '14 at 11:43
  • 2
    If the "Maximum segment length" is set to 25 why did you get 4 segment longer than 25 (25.465) and not 5 segment (4 of 25 and one of 1.86 or 5 of 20,372 if the tool output equal length) ? – J.R Oct 23 '19 at 12:00
  • 1
    @J.R - That's a good question to ask 5 years ago :). I don't have an answer to that, perhaps it was a bug in the tool considering it would have been an old QGIS version. Also, as it was in my early days of learning GIS, I should have used another CRS when measuring accurate distances in meters! – Joseph Oct 23 '19 at 12:08
  • 1
    @Joseph, I think you would choose PyQGIS today, do not you? =) – Taras Oct 23 '19 at 12:14
  • 1
    @Taras - I would be more inclined, yes :) – Joseph Oct 23 '19 at 12:22
2

Tested on QGIS 2.18 and QGIS 3.4

Let's assume there is a polyline layer called "lines".

input

I can suggest using a "Virtual Layer" through Layer > Add Layer > Add/Edit Virtual Layer...


There are possible several cases:


Case 1. Splitting the line into equal segments, basically equal length which is defined by the user.

With the following Query, it is possible to achieve the result. To increase/decrease the segment length, please adjust the 1000 AS step_length in -- configurations.

-- generate series
WITH RECURSIVE generate_sections(id, sec) AS (
SELECT conf.start + 1, conf.start
FROM conf
UNION ALL
SELECT id + conf.step, sec + conf.step_length/conf.length_line
FROM generate_sections, conf
WHERE sec + conf.step_length/conf.length_line <= 1
),

-- configurations
conf AS (
SELECT
0.0 AS start,
1.0 AS step,
1000 AS step_length,
ST_Length(l.geometry) AS length_line
FROM lines AS l
)

-- query
SELECT gs.id AS id,
        ROUND(ST_Length(ST_Line_Substring(l.geometry, start + sec, sec + conf.step_length/conf.length_line)),0) AS seg_length,
        ST_Line_Substring(l.geometry, start + sec, sec + conf.step_length/conf.length_line) AS geom
FROM generate_sections AS gs, lines AS l, conf
GROUP BY gs.id

The output Virtual Layer will look as following

output_1

Note: If 'delta' (e.g. the last shortest segment) should not be included, then insert WHERE sec_length >= step_length in -- query, see below

-- query
SELECT gs.id AS id,
        ROUND(ST_Length(ST_Line_Substring(l.geometry, start + sec, sec + conf.step_length/conf.length_line)),0) AS seg_length,
        ST_Line_Substring(l.geometry, start + sec, sec + conf.step_length/conf.length_line) AS geom
FROM generate_sections AS gs, lines AS l, conf
WHERE seg_length >= step_length
GROUP BY gs.id

Case 2. Splitting the line into a certain number of segments

With the following Query, it is possible to achieve the result. To increase/decrease the number of segments, please adjust the 8 AS sections in -- configurations.

-- generate series
WITH RECURSIVE generate_sections(id, sec) AS (
SELECT conf.start + 1, conf.start
FROM conf
UNION ALL
SELECT id + conf.step, sec + conf.step
FROM generate_sections, conf
WHERE sec + conf.step < conf.sections
),

-- configurations
conf AS (
SELECT
8 AS sections,
0.0 AS start,
1.0 AS step
)

-- query
SELECT gs.id AS id,
    ST_Line_Substring(l.geometry, conf.start + sec/conf.sections, sec/conf.sections + step/conf.sections) AS geom,
    ROUND(ST_Length(ST_Line_Substring(l.geometry, conf.start + sec/conf.sections, sec/conf.sections + step/conf.sections)),2) AS seg_length
FROM generate_sections AS gs, lines AS l, conf
WHERE start + step < sections
GROUP BY gs.id

The output Virtual Layer will look as following

output_2

Taras
  • 32,823
  • 4
  • 66
  • 137