I have two line layers (roads and contours in this example) and I would like to split the roads layer every time it crosses/intersects a feature on the contour layer. I can't seem to find a tool that does this, as the intersect tool is expecting a polygon for at least one of the layers. It also appears that GRASS' v.clean only works on a single layer. It seems like a simple task, but I'm at a loss!

EDIT (per comments below): Trying to get this to work in PostGIS now, and having some very strange results. If I do a subset of my dataset (one road, one contour that crosses it), and use the following SQL, I get the expected result, with the road split where the contour crosses it:

insert into "road_split"
select 
(ST_Dump(st_split(r.geom,c.geom))).geom
from "road" r, "contour" c

However, if I do the exact same thing with the complete dataset, no roads are split. What am I doing wrong here?

I should note that all features in both the road and contour table are LINESTRINGS.

  • The correct GRASS GIS command is v.overlay (two vector maps) and not v.clean (for cleaning one vector map) – gene May 27 '14 at 17:00
  • gene; unfortunately, v.overlay is expecting an area for one fo the layers as well. As per the manual: "v.overlay allows the user to overlay two vector maps. Features in ainput can be lines or areas and are cut with areas in binput." – Darren Cope May 27 '14 at 17:50
  • Sorry, and this is easy to do in Python with PyQGIS or Shapely – gene May 27 '14 at 17:53
  • Care to expand on that with a possible solution? – Darren Cope May 27 '14 at 18:00
  • 1
    No: I'm trying to do this using open source software. – Darren Cope Feb 3 '15 at 12:57
up vote 5 down vote accepted

I would do the job with OpenJUMP and the Noder tool.

Open your line layers into OpenJUMP

enter image description here

Combine the layers for further processing

enter image description here

This tool will transform all the attributes from the source layers and add a new attribute "LAYER". That will be useful later.

enter image description here

Next use the Noder tool from the menu "Tools - Edit Geometry - Noder.."

enter image description here

Lines will be noded and split. A few split roads selected as a proof.

enter image description here

Finally you can extract the contours and roads back to their own layers by utilizing the LAYER attribute. OpenJUMP has an "Extract Layer by Attribute" tool in the Edit menu for this purpose.

enter image description here

  • Good solution!.. – SIslam Feb 5 '15 at 8:39
  • Thank you! This is the only solution that actually works so far! I would still love feedback on how to get it working in PostGIS, but this does the trick for now! – Darren Cope Mar 2 '15 at 20:27

Note that as of QGIS 2.8, there's a new tool in Processing Toolbox called "Split lines with lines" that does exactly this task and works beautifully.

  • Is there now a tool to split polygons with lines? I'd like to split polygons along the lines in a separate polyline layer. – blackthorn Aug 20 '15 at 9:49
  • Yes, you want the "Split selected features with selected line from another layer" tool on the toolbar. It may be better to ask this as a new question as it's unrelated to this one. – Darren Cope Aug 24 '15 at 12:30
  • Processing (menu item at the top) > Toolbox > QGIS geoalgorithms > Vector overlay tools > Split lines with lines – Henrik Feb 17 '17 at 12:03

You can use Python with shapely , with PyQGIS or directly with OpenJump GIS or PostGIS as mnt.biker says.

With Python:

1) the first solution is to find the intersections of the lines and then break the input coords into parts (look at cut.py or Get the vertices on a LineString either side of a Point with shapely) -> not very easy...

2) a more direct solution is to use the union operations (combinewith PyQGIS) : the method will split all self-intersection geometries ([geos-devel] split self-intersecting LineString into non-intersecting lines)

Example with shapely and Fiona (similar with PyQGIS)

enter image description here

import fiona
# open the line shapefile and transform to shapely geometry
file = fiona.open('line.shp')
from shapely.geometry import shape
line = shape(file.next()['geometry'])
# open the contours shapefile and transform to MultLineString shapely geometry
Multi = MultiLineString([shape(lin['geometry']) for lin in fiona.open('contours.shp')])
# now you can use the `union`, `cascaded_union`or `unary_union`of shapely
result = unary_union([line, Multi])

and save the resulting shapefile with Fiona.

enter image description here

If you want to save only the line that needs to be cut, look at Code for splitting a line with another line

And you can use a spatial index with the module Rtree to speed things up.

3) but the most comprehensive solution is to compute the Topological Planar Graph of the combined layers.

it can be drawn on the plane in such a way that its edges intersect only at their endpoints. In other words, it can be drawn in such a way that no edges cross each other

I have a Python class to do it but I will use here OpenJump:

Whith OpenJump GIS and Planar Graph command

1) you load the shapefiles and compute the union (combined layer):

enter image description here

2) you compute the Planar Graph

enter image description here

3) and you have the nodes, the faces and the arcs (edges) of the Graph as as the result , all with the corresponding attribute values preserved.

enter image description here

Whith PostGIS (version 2.00 and up) (mnt.biker answer)

The result are the same

New

In OpenJUMP use Combine Layers("Rassemblez les couches" in French) and not Union

enter image description here

  • gene; as per my above comment, the Union in OpenJump is not working as expected (in fact it is doing nothing.) I also noticed that there are multiple Union commands (which is bizarre). Can you walk me through that step? How is Tools>Analysis>Union/Dissolve/Merge command different than Tools>Geometry Functions>Union (Function)? Neither of these seem to make sense based on any "Union" command I have used in other software. – Darren Cope May 29 '14 at 11:58
  • see above in New – gene May 29 '14 at 17:33
  • Thanks! I am not familiar enough with Python to try your first solution just yet. The OpenJump solution somewhat works, but leaves all of the data in one layer, with no attributes present to separate them back out into the original layers. Any thoughts on how to do this? – Darren Cope Jun 13 '14 at 16:39
  • You may consider to make another question about the union tools in OpenJUMP. Documentation is not the strongest feature in OpenJUMP. – user30184 Feb 3 '15 at 15:52

My answer doesn't involve QGIS, but if you're stuck you can always put your layers into PostGIS and use ST_Split. Like this:

SELECT ST_Split(r.the_geom, c.the_geom) FROM roads r, contours c 
  • Thanks! I was able to mess around with this a bit, and found it didn't quite work. I had the error "Splitting a Line by a MultiLineString is unsupported." After some further research, it seems that ST_LineMerge may solve the problem, so I tried: 'SELECT ST_Split(r.geometry, c.geometry) FROM (SELECT ST_LineMerge(geom) from contour AS linemergec) c, (SELECT ST_LineMerge(geom) from roads AS linemerger) r' - but now I'm getting the error: "cannot cast type record to topogeometry ^ DETAIL: Cannot cast type geometry to integer in column 1" – Darren Cope Jun 13 '14 at 16:31
  • After some more work, I was able to import the data using the DB Manager Plugin, and checked off "Create Single Part Geometries instead of multi-part" and it seems to work! – Darren Cope Jun 13 '14 at 18:36
  • After viewing the results, it in fact does not appear to work. It simply output my original roads. What am I doing wrong here? SELECT ST_AsText(ST_Split(r.geom, c.geom)) as geom FROM roads r, contour c – Darren Cope Jun 13 '14 at 19:31
  • This is bizarre. I just tried the exact same syntax with a single subset (one road, one contour) and it worked exactly as expected. When I run it on the larger database, it doesn't work! – Darren Cope Jun 13 '14 at 19:55
  • problem is that your line table has some multilines, fix them to lines using st_linemerge or if that does not work you need to use ST_dump – simplexio Feb 2 '15 at 14:31

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.