[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