[postgis-users] Closing polylines
Mike Toews
mwtoews at gmail.com
Sat May 12 18:40:03 PDT 2012
On 12 May 2012 09:53, george wash <gws293 at hotmail.com> wrote:
> Hi, does anyone know of a function or algorithm which will help me in
> closing open multilinestrings (contours) (I am using Postgis 2.0, Win 7 64).
> My contours are made up of several segments, all multilinestrings, which
> sometime are closed but often are open at several places along the same
> contour height.
> I can close them when the are open at the edge of the map by using a section
> of the edge as the closing segment but the real problem is when the contours
> are inside the map, e.g. when the several segments making up the contour do
> not share common start or end points but have a gap between them.
> Any suggestions would be most welcome.
> Thank you
I use a custom function ST_ForceClosed to close anything that is not
closed, including LineStrings or MultiLineStrings. This function can
be added to any version of PostGIS:
CREATE OR REPLACE FUNCTION ST_ForceClosed(geom geometry)
RETURNS geometry AS
$BODY$BEGIN
IF ST_IsClosed(geom) THEN
RETURN geom;
ELSIF GeometryType(geom) = 'LINESTRING' THEN
SELECT ST_AddPoint(geom, ST_PointN(geom, 1)) INTO geom;
ELSIF GeometryType(geom) ~ '(MULTI|COLLECTION)' THEN
-- Deconstruct parts
WITH parts AS (
SELECT CASE
WHEN NOT ST_IsClosed(gd.geom) AND GeometryType(gd.geom) = 'LINESTRING'
THEN ST_AddPoint(gd.geom, ST_PointN(gd.geom, 1))
ELSE gd.geom END AS closed_geom
FROM ST_Dump(geom) AS gd
) -- Reconstitute parts
SELECT ST_Collect(closed_geom) INTO geom
FROM parts;
END IF;
IF NOT ST_IsClosed(geom) THEN
RAISE EXCEPTION 'Could not close geometry';
END IF;
RETURN geom;
END;$BODY$
LANGUAGE plpgsql IMMUTABLE COST 100;
-- And example use with a LineString:
WITH data AS (SELECT 'LINESTRING (190 370, 130 280, 177 205, 330 250,
290 330)'::geometry as linestr)
SELECT ST_IsClosed(linestr),
ST_ForceClosed(linestr),
ST_IsClosed(ST_ForceClosed(linestr))
FROM data;
-- Similar with MultiLineString:
WITH data AS (SELECT 'MULTILINESTRING ((190 280, 165 209, 205 186, 260
240, 220 280),
(170 320, 118 225, 150 120, 280 130, 310 250, 230 340))'::geometry as linestr)
SELECT GeometryType(linestr), ST_IsClosed(linestr),
ST_ForceClosed(linestr),
ST_IsClosed(ST_ForceClosed(linestr))
FROM data;
-Mike
More information about the postgis-users
mailing list