]> granicus.if.org Git - postgis/commitdiff
Ticket #76.
authorKevin Neufeld <kneufeld.ca@gmail.com>
Mon, 16 Nov 2009 19:47:33 +0000 (19:47 +0000)
committerKevin Neufeld <kneufeld.ca@gmail.com>
Mon, 16 Nov 2009 19:47:33 +0000 (19:47 +0000)
- 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
regress/Makefile.in
regress/dumppoints.sql [new file with mode: 0644]
regress/dumppoints_expected [new file with mode: 0644]

index 8ec0daa01147ee06269c01fb708129fe35aad8a6..bec08194b278b739918e89a1c7961a4d0fbc96e3 100644 (file)
@@ -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;
+
+
 ------------------------------------------------------------------------
 
 --
index 6f20291fec5446354cec743a4cc9782a8874b6bc..de2c466a9fc5b73873ae0c96d58770ecc43a0846 100644 (file)
@@ -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 (file)
index 0000000..1fb46b0
--- /dev/null
@@ -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 (file)
index 0000000..9a24895
--- /dev/null
@@ -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)