From 3d4a54a77a28e25b728cfb3cba6e10f3b19af8a6 Mon Sep 17 00:00:00 2001 From: Kevin Neufeld Date: Mon, 16 Nov 2009 19:47:33 +0000 Subject: [PATCH] Ticket #76. - added a modified version of a plpgsql implementation for ST_DumpPoints() proposed by Maxime van Noppen. - added regression tests git-svn-id: http://svn.osgeo.org/postgis/trunk@4836 b70326c6-7e19-0410-871a-916f4a2858ee --- postgis/postgis.sql.in.c | 94 ++++++++++++++++++++++++++++++++ regress/Makefile.in | 3 +- regress/dumppoints.sql | 104 ++++++++++++++++++++++++++++++++++++ regress/dumppoints_expected | 62 +++++++++++++++++++++ 4 files changed, 262 insertions(+), 1 deletion(-) create mode 100644 regress/dumppoints.sql create mode 100644 regress/dumppoints_expected diff --git a/postgis/postgis.sql.in.c b/postgis/postgis.sql.in.c index 8ec0daa01..bec08194b 100644 --- a/postgis/postgis.sql.in.c +++ b/postgis/postgis.sql.in.c @@ -1921,6 +1921,100 @@ CREATE OR REPLACE FUNCTION ST_DumpRings(geometry) AS 'MODULE_PATHNAME', 'LWGEOM_dump_rings' LANGUAGE 'C' IMMUTABLE STRICT; +----------------------------------------------------------------------- +-- ST_DumpPoints() +----------------------------------------------------------------------- +-- This function mimicks that of ST_Dump for collections, but this function +-- that returns a path and all the points that make up a particular geometry. +-- This current implementation in plpgsql does not scale very well at all. +-- and should be ported to C at some point. +-- Availability: 1.5.0 +CREATE OR REPLACE FUNCTION ST_DumpPoints(the_geom geometry, cur_path integer[]) RETURNS SETOF geometry_dump AS $$ +DECLARE + tmp geometry_dump; + tmp2 geometry_dump; + nb_points integer; + nb_geom integer; + i integer; + j integer; + g geometry; + +BEGIN + + RAISE DEBUG '%,%', cur_path, ST_GeometryType(the_geom); + + -- Special case (MULTI* OR GEOMETRYCOLLECTION) : iterate and return the DumpPoints of the geometries + SELECT ST_NumGeometries(the_geom) INTO nb_geom; + + IF (nb_geom IS NOT NULL) THEN + + i = 1; + FOR tmp2 IN SELECT (ST_Dump(the_geom)).* LOOP + + FOR tmp IN SELECT * FROM ST_DumpPoints(tmp2.geom, cur_path || tmp2.path) LOOP + RETURN NEXT tmp; + END LOOP; + i = i + 1; + + END LOOP; + + RETURN; + END IF; + + + -- Special case (POLYGON) : return the points of the rings of a polygon + IF (ST_GeometryType(the_geom) = 'ST_Polygon') THEN + + FOR tmp IN SELECT * FROM ST_DumpPoints(ST_ExteriorRing(the_geom), cur_path || ARRAY[1]) LOOP + RETURN NEXT tmp; + END LOOP; + + j := ST_NumInteriorRings(the_geom); + FOR i IN 1..j LOOP + FOR tmp IN SELECT * FROM ST_DumpPoints(ST_InteriorRingN(the_geom, i), cur_path || ARRAY[i+1]) LOOP + RETURN NEXT tmp; + END LOOP; + END LOOP; + + RETURN; + END IF; + + + -- Special case (POINT) : return the point + IF (ST_GeometryType(the_geom) = 'ST_Point') THEN + + tmp.path = cur_path || ARRAY[1]; + tmp.geom = the_geom; + + RETURN NEXT tmp; + RETURN; + + END IF; + + + -- Use ST_NumPoints rather than ST_NPoints to have a NULL value if the_geom isn't + -- a LINESTRING or CIRCULARSTRING. + SELECT ST_NumPoints(the_geom) INTO nb_points; + + -- This should never happen + IF (nb_points IS NULL) THEN + RAISE EXCEPTION 'Unexpected error while dumping geometry %', ST_AsText(the_geom); + END IF; + + FOR i IN 1..nb_points LOOP + tmp.path = cur_path || ARRAY[i]; + tmp.geom := ST_PointN(the_geom, i); + RETURN NEXT tmp; + END LOOP; + +END +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION ST_DumpPoints(geometry) RETURNS SETOF geometry_dump AS $$ + SELECT * FROM ST_DumpPoints($1, NULL); +$$ LANGUAGE SQL; + + ------------------------------------------------------------------------ -- diff --git a/regress/Makefile.in b/regress/Makefile.in index 6f20291fe..de2c466a9 100644 --- a/regress/Makefile.in +++ b/regress/Makefile.in @@ -60,7 +60,8 @@ TESTS = \ kml \ regress_ogc \ regress_bdpoly \ - regress_proj + regress_proj \ + dumppoints # Covers/CoveredBy only if GEOS >= 3.0 ifeq ($(shell expr $(POSTGIS_GEOS_VERSION) ">=" 30),1) diff --git a/regress/dumppoints.sql b/regress/dumppoints.sql new file mode 100644 index 000000000..1fb46b06b --- /dev/null +++ b/regress/dumppoints.sql @@ -0,0 +1,104 @@ +SELECT path, ST_AsText(geom) +FROM ( + SELECT (ST_DumpPoints(g.geom)).* + FROM + (SELECT + 'POINT (0 9)'::geometry AS geom + ) AS g + ) j; + +SELECT path, ST_AsText(geom) +FROM ( + SELECT (ST_DumpPoints(g.geom)).* + FROM + (SELECT + 'LINESTRING ( + 0 0, + 0 9, + 9 9, + 9 0, + 0 0 + )'::geometry AS geom + ) AS g + ) j; + +SELECT path, ST_AsText(geom) +FROM ( + SELECT (ST_DumpPoints(g.geom)).* + FROM + (SELECT + 'POLYGON (( + 0 0, + 0 9, + 9 9, + 9 0, + 0 0 + ))'::geometry AS geom + ) AS g + ) j; + + +SELECT path, ST_AsText(geom) +FROM ( + SELECT (ST_DumpPoints(g.geom)).* + FROM + (SELECT + 'POLYGON (( + 0 0, + 0 9, + 9 9, + 9 0, + 0 0 + ), ( + 1 1, + 1 3, + 3 2, + 1 1 + ), ( + 7 6, + 6 8, + 8 8, + 7 6 + ))'::geometry AS geom + ) AS g + ) j; + +SELECT path, ST_AsText(geom) +FROM ( + SELECT (ST_DumpPoints(g.geom)).* + FROM + (SELECT + 'MULTIPOLYGON ((( + 0 0, + 0 3, + 4 3, + 4 0, + 0 0 + )), (( + 2 4, + 1 6, + 4 5, + 2 4 + ), ( + 7 6, + 6 8, + 8 8, + 7 6 + )))'::geometry AS geom + ) AS g + ) j; + +SELECT path, ST_AsText(geom) +FROM ( + SELECT (ST_DumpPoints(g.geom)).* + FROM + (SELECT + 'GEOMETRYCOLLECTION( + POINT(99 98), + LINESTRING(1 1, 3 3), + POLYGON((0 0, 0 1, 1 1, 0 0)), + POLYGON((0 0, 0 9, 9 9, 9 0, 0 0), (5 5, 5 6, 6 6, 5 5)), + MULTIPOLYGON(((0 0, 0 9, 9 9, 9 0, 0 0), (5 5, 5 6, 6 6, 5 5))) + )'::geometry AS geom + ) AS g + ) j; diff --git a/regress/dumppoints_expected b/regress/dumppoints_expected new file mode 100644 index 000000000..9a24895d0 --- /dev/null +++ b/regress/dumppoints_expected @@ -0,0 +1,62 @@ +{1}|POINT(0 9) +{1}|POINT(0 0) +{2}|POINT(0 9) +{3}|POINT(9 9) +{4}|POINT(9 0) +{5}|POINT(0 0) +{1,1}|POINT(0 0) +{1,2}|POINT(0 9) +{1,3}|POINT(9 9) +{1,4}|POINT(9 0) +{1,5}|POINT(0 0) +{1,1}|POINT(0 0) +{1,2}|POINT(0 9) +{1,3}|POINT(9 9) +{1,4}|POINT(9 0) +{1,5}|POINT(0 0) +{2,1}|POINT(1 1) +{2,2}|POINT(1 3) +{2,3}|POINT(3 2) +{2,4}|POINT(1 1) +{3,1}|POINT(7 6) +{3,2}|POINT(6 8) +{3,3}|POINT(8 8) +{3,4}|POINT(7 6) +{1,1,1}|POINT(0 0) +{1,1,2}|POINT(0 3) +{1,1,3}|POINT(4 3) +{1,1,4}|POINT(4 0) +{1,1,5}|POINT(0 0) +{2,1,1}|POINT(2 4) +{2,1,2}|POINT(1 6) +{2,1,3}|POINT(4 5) +{2,1,4}|POINT(2 4) +{2,2,1}|POINT(7 6) +{2,2,2}|POINT(6 8) +{2,2,3}|POINT(8 8) +{2,2,4}|POINT(7 6) +{1,1}|POINT(99 98) +{2,1}|POINT(1 1) +{2,2}|POINT(3 3) +{3,1,1}|POINT(0 0) +{3,1,2}|POINT(0 1) +{3,1,3}|POINT(1 1) +{3,1,4}|POINT(0 0) +{4,1,1}|POINT(0 0) +{4,1,2}|POINT(0 9) +{4,1,3}|POINT(9 9) +{4,1,4}|POINT(9 0) +{4,1,5}|POINT(0 0) +{4,2,1}|POINT(5 5) +{4,2,2}|POINT(5 6) +{4,2,3}|POINT(6 6) +{4,2,4}|POINT(5 5) +{5,1,1,1}|POINT(0 0) +{5,1,1,2}|POINT(0 9) +{5,1,1,3}|POINT(9 9) +{5,1,1,4}|POINT(9 0) +{5,1,1,5}|POINT(0 0) +{5,1,2,1}|POINT(5 5) +{5,1,2,2}|POINT(5 6) +{5,1,2,3}|POINT(6 6) +{5,1,2,4}|POINT(5 5) -- 2.50.1