[postgis-users] Updated cleangeometry function
Paul Pfeiffer
nightdrift at gmail.com
Wed Jan 15 20:42:29 PST 2014
I have been having problems with the clean geometry function referenced at
http://trac.osgeo.org/postgis/wiki/UsersWikiCleanPolygons returning null
geometries. So I have fixed the script and I'm providing it below if anyone
else wants to test it and let me know I could update the wiki.
(Requires Postgres v9 +)
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--
-- $Id: cleanGeometry.sql 2014-01-16 Paul Pfeiffer
--
-- cleanGeometry - remove self- and ring-selfintersections from
-- input Polygon geometries
--
-- Copyright 2014 Paul Pfeiffer
-- Version 2.0
-- contact: nightdrift at gmail dot com
--
-- modified from cleanGeometry.sql 2008-04-24 from http://www.kappasys.ch
--
-- This is free software; you can redistribute and/or modify it under
-- the terms of the GNU General Public Licence. See the COPYING file.
-- This software is without any warrenty and you use it at your own risk
--
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CREATE OR REPLACE FUNCTION cleangeometry(geom "public"."geometry")
RETURNS "public"."geometry" AS
$BODY$
DECLARE
inGeom ALIAS for $1;
outGeom geometry;
tmpLinestring geometry;
sqlString text;
BEGIN
outGeom := NULL;
-- Clean Polygons --
IF (ST_GeometryType(inGeom) = 'ST_Polygon' OR ST_GeometryType(inGeom) =
'ST_MultiPolygon') THEN
-- Check if it needs fixing
IF NOT ST_IsValid(inGeom) THEN
sqlString := '
-- separate multipolygon into 1 polygon per row
WITH split_multi (geom, poly) AS (
SELECT
(ST_Dump($1)).geom,
(ST_Dump($1)).path[1] -- polygon number
),
-- break each polygon into linestrings
split_line (geom, poly, line) AS (
SELECT
ST_Boundary((ST_DumpRings(geom)).geom),
poly,
(ST_DumpRings(geom)).path[1] -- line number
FROM split_multi
),
-- get the linestrings that make up the exterior of each
polygon
line_exterior (geom, poly) AS (
SELECT
geom,
poly
FROM split_line
WHERE line = 0
),
-- get an array of all the linestrings that make up the
interior of each polygon
line_interior (geom, poly) AS (
SELECT
array_agg(geom ORDER BY line),
poly
FROM split_line
WHERE line > 0
GROUP BY poly
),
-- use MakePolygon to rebuild the polygons
poly_geom (geom, poly) AS (
SELECT
CASE WHEN line_interior.geom IS NULL
THEN
ST_Buffer(ST_MakePolygon(line_exterior.geom), 0)
ELSE
ST_Buffer(ST_MakePolygon(line_exterior.geom, line_interior.geom), 0)
END,
line_exterior.poly
FROM line_exterior
LEFT JOIN line_interior USING (poly)
)
';
IF (ST_GeometryType(inGeom) = 'ST_Polygon') THEN
sqlString := sqlString || '
SELECT geom
FROM poly_geom
';
ELSE
sqlString := sqlString || '
, -- if its a multipolygon combine the polygons back
together
multi_geom (geom) AS (
SELECT
ST_Multi(ST_Collect(geom ORDER BY poly))
FROM poly_geom
)
SELECT geom
FROM multi_geom
';
END IF;
EXECUTE sqlString INTO outGeom USING inGeom;
RETURN outGeom;
ELSE
RETURN inGeom;
END IF;
-- Clean Lines --
ELSIF (ST_GeometryType(inGeom) = 'ST_Linestring') THEN
outGeom := ST_Union(ST_Multi(inGeom), ST_PointN(inGeom, 1));
RETURN outGeom;
ELSIF (ST_GeometryType(inGeom) = 'ST_MultiLinestring') THEN
outGeom := ST_Multi(ST_Union(ST_Multi(inGeom), ST_PointN(inGeom,
1)));
RETURN outGeom;
ELSE
RAISE NOTICE 'The input type % is not
supported',ST_GeometryType(inGeom);
RETURN inGeom;
END IF;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE COST 100
;
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osgeo.org/pipermail/postgis-users/attachments/20140116/659a4495/attachment.html>
More information about the postgis-users
mailing list