Search code examples
postgresqlgispostgisopenstreetmaprecursive-query

Recursive PostGIS query


I am trying to transform all the roundabouts in a city into simple intersections/crossroads (o -> +). As I am using OpenStreetMap for the initial topology, some roundabouts are not a circle but just the segments of the circle (Ex: https://www.openstreetmap.org/#map=18/43.34516/-8.41536).

In practice the problem is that I need the centroid of each roundabout and I get it almost in all cases but sometimes I get several centroids for the same roundabout (centroids of the arches, no the full roundabout).

I have achieved this:

select f.osm_id as fid, (select ST_CENTROID(ST_Buffer(ST_UNION(way),1)) as r_geom
                      from planet_osm_line d 
                      where st_intersects(f.way, d.way) and junction = 'roundabout') as rotonda 
from planet_osm_line f 
where junction like 'roundabout';

But this does not resolve the problem, it only reduces it. I am not getting the full circle, just bigger segments of it.

So I guess I need a recursive query in order to do this until the number of geometries retrieved remains the same (the full circle). Any ideas about how to build this query?


Solution

  • I was looking for something like this (hope it helps others in need):

    create table no_roundabouts as 
    with recursive roundabout(geom) as (--Recursive function to build closed circled roundabouts even with roundabouts mapped as differents arches.
      SELECT ST_TRANSFORM(way,3857)
      FROM planet_osm_line ways --Get all segments tagged as 'roundabout'
      WHERE ways.junction = 'roundabout'
    UNION ALL
      SELECT ST_TRANSFORM(ST_UNION(ways.way, roundabout.geom),3857)
      FROM roundabout, planet_osm_line ways -- Compose segments building greater arches of the roundabout until we have the full circle (My_segment + a touching segment that is no contained in my segment)
      WHERE ways.junction = 'roundabout' and ST_INTERSECTS(roundabout.geom, ways.way) and not ST_CONTAINS(roundabout.geom, ways.way)
    )
    SELECT * FROM roundabout;
    
    alter table no_roundabouts add column id bigserial; -- Add id to each line
    delete from no_roundabouts a -- Delete repeated roundabouts generated during recursion
    where exists (select geom from no_roundabouts b where ST_CONTAINS(b.geom, a.geom) and b.id > a.id);
    
    --select count(*) from no_roundabouts WHERE ST_IsClosed(geom) = false;
    update no_roundabouts set geom = ST_LINEMERGE(geom) where ST_ISCLOSED(geom) is false --Force closed roundabouts
    
    -- Query replacing roundabouts with crossroads (linking each way in and out with the centroid of the roundabout)
    SELECT ST_TRANSFORM(ST_ADDPOINT(y.way, ST_CENTROID(x.geom), 0),4326) 
    FROM no_roundabouts x JOIN planet_osm_line y ON ST_INTERSECTS(y.way, x.geom) 
    WHERE y.highway is not null and ST_INTERSECTS(x.geom, st_pointn(y.way,1)) and ST_CONTAINS(x.geom, y.way) = false
    UNION
    SELECT ST_TRANSFORM(ST_ADDPOINT(y.way, ST_CENTROID(x.geom), -1),4326) 
    FROM no_roundabouts x JOIN planet_osm_line y ON ST_INTERSECTS(y.way, x.geom) 
    WHERE y.highway is not null and ST_INTERSECTS(x.geom, ST_POINTN(y.way,-1)) and ST_CONTAINS(x.geom, y.way) = false;