[postgis-users] [Solved] Linemerge roads

Peter webwiz at pl.net
Sun May 22 16:32:14 PDT 2011


FTR here is my adopted solution to labeling a roading layer. Its long winded but works. As im just learning id welcome any improvements/suggestions.

Nb: the unique road 'id' in the dataset is called road_name_, and there are between 1 and lots of records per id, as the road surface changes or has oddities like small Ys, or Ps.

-- remove all those roads with no names to r2
create table r2 as
select gid,road_name_,name,road_highw,the_geom
from nzroads
where name is null and road_name_ is null

-- load the rest to r3
create table r3 as
select gid,road_name_,name,road_highw,road_surfa,the_geom
from nzroads
where not ( name is null and road_name_ is null)

-- take out oddities to r4  (20 or so)
create table r4 as
select gid,road_name_,name,road_highw,road_surfa,the_geom
from r3
where  name is null  or road_name_ is null or road_name_ <'1000000000000' or road_name_ ~* '[a-z]'

delete from r3
where  name is null  or road_name_ is null or road_name_ <'1000000000000' or road_name_ ~* '[a-z]'

-- multipart the multilinestrings from r3
create table r5 as
select
   row_number() over (order by road_name_)::int AS gid,
   count(gid) as nlines,
   road_name_,
   (st_collect(the_geom)) as the_geom
from r3
group by road_name_

-- then linemerge them so they can be labelled as one
create table r6 as
select
   row_number() over (order by road_name_)::int AS gid,
   road_name_,
   (st_linemerge(the_geom)) as the_geom
from r5

-- but first separate the resulting single and multis to r7 and r8
-- to save cpu on the much larger set of simple cases
create table r8 as
select
   row_number() over (order by road_name_)::int AS gid,
   road_name_,
  the_geom
from r6
where GeometryType("the_geom") = 'MULTILINESTRING'

create table r7 as
select
   row_number() over (order by road_name_)::int AS gid,
   road_name_,
  the_geom
from r6
where GeometryType("the_geom") = 'LINESTRING'

-- the multis are the trickiest
-- buffer to 1m, and merge by id
create table r9 as
select
   row_number() over (order by road_name_)::int AS gid,
   road_name_,
   ST_Buffer(the_geom, 1) as the_geom
from r8

--  then re-multipart so we can label the sep parts indepedantly
create table r10 as
select
   row_number() over (order by road_name_)::int AS gid,
   road_name_,
   (st_dump(the_geom)).geom as the_geom
from r9

-- label the resultant polys using pointonsurface, a close enough approximation to line mid point
create table r11 as
select
   row_number() over (order by road_name_)::int AS gid,
   road_name_,
   st_pointonsurface(the_geom) as the_geom
from r10

-- label the easier single linestring midpoints
create table r12 as
select
   row_number() over (order by road_name_)::int AS gid,
   road_name_,
   ST_Line_Interpolate_Point(the_geom,0.5) as the_geom
from r7

-- merge both sets of points, r11 and r12
create table r13 as
SELECT * FROM r11
UNION ALL
SELECT * FROM r12

-- join road names back in from r3
-- is there a way to do this join in one step?
create table r14 as
select distinct on (road_name_) * from r3
order by road_name_

create table  r15 as
SELECT r13.gid, r14.name, r14.road_name_, r14.road_highw, r14.road_surfa, r13.the_geom
FROM r13 LEFT JOIN r14   ON r14.road_name_ = r13.road_name_
order by r13.road_name_

Peter




More information about the postgis-users mailing list