Building areas from lines
Built-in PostGIS functions ST_BuildArea and ST_Polygonize can be used to construct Polygons from linework. However the start/end points of all lines must touch each other to form the polygons. Also the linework needs to be properly noded at intersections, rather than just crossing each other.
A user-submitted function takes a collection of LINESTRING or a MULTILINESTRING geometry and returns a geometry:
CREATE OR REPLACE FUNCTION ST_BuildAreaLinework(linework geometry) RETURNS geometry AS $BODY$WITH data AS (SELECT * FROM ST_Dump(ST_UnaryUnion($1))) SELECT ST_SetSRID(ST_BuildArea(ST_Collect(geom)), ST_SRID($1)) FROM ( -- This is the noded linework, broken up where they cross each other SELECT (ST_Dump(ST_Union(geom))).geom FROM data ) t1, ( -- This is a [MULTI]POINT of any crossings or closures SELECT ST_Union(geom) AS pt FROM ( SELECT ST_Intersection(A.geom, B.geom) AS geom FROM data A, data B WHERE A.path[1] < B.path[1] AND ST_Intersects(A.geom, B.geom) UNION SELECT ST_StartPoint(geom) FROM data WHERE ST_IsClosed(geom) ) s ) t2 WHERE ST_Intersects(ST_StartPoint(geom), pt) AND ST_Intersects(ST_EndPoint(geom), pt);$BODY$ LANGUAGE sql IMMUTABLE;
For example:
SELECT ST_BuildAreaLinework('MULTILINESTRING((36 35,45 307),(30 290,390 280),(320 60,300 310),(20 60,320 60),(120 140,168 225),(140 220,220 150,120 170))');
Where the blue lines are the input linework, and the yellow polygon with a hole is the result.
A similar function could be used with ST_Polygonize
CREATE OR REPLACE FUNCTION ST_PolygonizeLinework(linework geometry) RETURNS geometry AS $BODY$WITH data AS (SELECT * FROM ST_Dump(ST_UnaryUnion($1))) SELECT ST_SetSRID(ST_Polygonize(geom), ST_SRID($1)) FROM ( -- This is the noded linework, broken up where they cross each other SELECT (ST_Dump(ST_Union(geom))).geom FROM data ) t1, ( -- This is a [MULTI]POINT of any crossings or closures SELECT ST_Union(geom) AS pt FROM ( SELECT ST_Intersection(A.geom, B.geom) AS geom FROM data A, data B WHERE A.path[1] < B.path[1] AND ST_Intersects(A.geom, B.geom) UNION SELECT ST_StartPoint(geom) FROM data WHERE ST_IsClosed(geom) ) s ) t2 WHERE ST_Intersects(ST_StartPoint(geom), pt) AND ST_Intersects(ST_EndPoint(geom), pt);$BODY$ LANGUAGE sql IMMUTABLE;
For example:
SELECT ST_PolygonizeLinework('MULTILINESTRING((50 40,50 230,300 230,270 60,40 60),(150 30,130 240),(191 155,240 190,250 150,190 170))');
Where the blue lines are the input linework, and the yellow polygons (GEOMETRYCOLLECTION(POLYGON((...)))
) are the result.
External links
- PostGIS: Tips for Power Users, by Paul Ramsey
- Building polygons from overlapping linestrings requiring intersection, by Simon Greener
Attachments (2)
-
BuildAreaLinework_example.png
(14.6 KB
) - added by 10 years ago.
example for ST_BuildAreaLinework
- PolygonizeLinework_example.png (10.6 KB ) - added by 10 years ago.
Download all attachments as: .zip