I have a shapefile from OSM which contains all the roads within a city. Larger roads (like dual-carriageways) seem to have 2 parallel lines. I'd like to collapse / combine those into 1 line so I can export and render them nicely in an external 3D application (2 overlapping roads will be complicated and will look weird in 3D).

How can I achieve this with either QGIS or PostGIS?

I am not worried about a slight loss of accuracy (within a few metres) and would like the resulting, single line to be between (ideally the centre of) the current, parallel lines.

Here is an example of the dual road lines that I want to combine.

enter image description here


3 Answers 3


ESRI has a collapse dual carriageway to centerline tool. You can get a cheap version for use with OSM. Otherwise you could select features and save as a new layer. Delete selected from layer you used for export. Buffer feature within range of one side of the carriageway that includes the second lane. Merge shapefile with original, connect up any broken topology.

If you can code and/or script you could average a centerline between lanes on a node by seg by node matching and output a centerline programaticaly and then programaticaly delete selected features used for the production process, check and fix broken topology, and you're done.

I found a arcpy code sample I am including, how to find the link is below in comments.

attributed to ESRI ARCGis Help

# Name: CollapseDualLinesToCenterline_Example.py
# Description: Creates street centerlines from a street casing coverage.
# Requirements: ArcInfo Workstation

# Import system modules
import arcpy
from arcpy import env

# Set environment settings
env.workspace = "C:/data"

# Set local variables
inCover = "streets"
outCover = "C:/output/centerlines"
maximumWidth = 50

# Execute CollapseDualLinesToCenterline
arcpy.CollapseDualLinesToCenterline_arc(inCover, outCover, maximumWidth, "")

You could try using Mike Migurski's Skeletron. It's an open source tool which he uses for such things as his Terrain map style.


Maybe it's not a very elegant solution and it's based on the method of answering question: https://gis.stackexchange.com/a/295348/120129.

It's one of the variants of solving your question, set up a geoinstrument (for me it's a road with the name "road_border" 11 m wide, type - line (MultiLineString)),

run a geoinstrument :-),

      tbla AS (SELECT id, ((ST_DumpPoints(geom)).geom) geom FROM road_border),
      tblb AS (SELECT (ST_Buffer((ST_Dump(geom)).geom, 0.0001)) geom FROM tbla),
      tblc AS (SELECT ST_Centroid(ST_UnaryUnion(Unnest(ST_ClusterWithin(geom, 0.0001)))) geom FROM tblb),
      tbld AS (SELECT ((ST_Dump(ST_DelaunayTriangles(ST_Collect(geom)))).geom) geom FROM tblc),
      tble AS (SELECT (ST_Boundary(geom)) geom FROM ST_Dump((SELECT ST_Polygonize(geom) geom FROM (SELECT ST_Union(geom) geom FROM
      (SELECT ST_ExteriorRing(geom) geom FROM tbld) AS lines) AS foo))),
      tblf AS (SELECT ST_MakeLine(p1, p2) geom FROM (SELECT ST_PointN(geom, generate_series(1, ST_NPoints(geom)-1)) p1,
      ST_PointN(geom, generate_series(2, ST_NPoints(geom))) p2 FROM tble) AS geom),
      tblg AS (SELECT ST_Buffer((ST_Dump(ST_Union(ST_Buffer(geom, 0.0005)))).geom, -0.0005) geom FROM road_border)
      SELECT ST_Intersection (a.geom, b.geom) geom FROM tblf a JOIN tblg b ON ST_Within(a.geom, b.geom);

and see the result.

This script is called - ST_RoadAxisFromDelaunayTriangulation.

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