]> granicus.if.org Git - postgis/commitdiff
Implement ST_GetFaceEdges (sql/mm topology function) [RT-SIGTA]
authorSandro Santilli <strk@keybit.net>
Tue, 3 May 2011 13:32:41 +0000 (13:32 +0000)
committerSandro Santilli <strk@keybit.net>
Tue, 3 May 2011 13:32:41 +0000 (13:32 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@7081 b70326c6-7e19-0410-871a-916f4a2858ee

topology/sql/sqlmm.sql
topology/test/Makefile
topology/test/regress/st_getfaceedges.sql [new file with mode: 0644]
topology/test/regress/st_getfaceedges_expected [new file with mode: 0644]
topology/topology.sql.in.c

index 929bdf5ffc988ea5abc19c910e87a007131d1cb2..94b076f8a1c1a6da4861d269cb18900bd04631cc 100644 (file)
@@ -37,27 +37,66 @@ CREATE TYPE topology.GetFaceEdges_ReturnType AS (
 --
 --
 -- 
-CREATE OR REPLACE FUNCTION topology.ST_GetFaceEdges(varchar, integer)
-       RETURNS setof topology.GetFaceEdges_ReturnType
+CREATE OR REPLACE FUNCTION topology.ST_GetFaceEdges(toponame varchar, face_id integer)
+  RETURNS SETOF topology.GetFaceEdges_ReturnType
 AS
 $$
 DECLARE
-       atopology ALIAS FOR $1;
-       aface ALIAS FOR $2;
-       rec RECORD;
+  rec RECORD;
+  bounds geometry;
+  retrec topology.GetFaceEdges_ReturnType;
+  n int;
 BEGIN
-       --
-       -- Atopology and aface are required
-       -- 
-       IF atopology IS NULL OR aface IS NULL THEN
-               RAISE EXCEPTION
-                'SQL/MM Spatial exception - null argument';
-       END IF;
-
-       RAISE EXCEPTION
-                'ST_GetFaceEdges: not implemented yet';
-
-
+  --
+  -- toponame and face_id are required
+  -- 
+  IF toponame IS NULL OR face_id IS NULL THEN
+    RAISE EXCEPTION 'SQL/MM Spatial exception - null argument';
+  END IF;
+
+  n := 1;
+
+  -- Construct the face geometry, then for each polygon:
+  FOR rec IN SELECT (ST_DumpRings((ST_Dump(ST_ForceRHR(
+    topology.ST_GetFaceGeometry(toponame, face_id)))).geom)).*
+  LOOP -- {
+
+    -- Contents of a directed face are the list of edges
+    -- that cover the specific ring
+    bounds = ST_Boundary(rec.geom);
+
+    FOR rec IN EXECUTE
+      'SELECT e.*, ST_Line_Locate_Point('
+      || quote_literal(bounds::text)
+      || ', ST_Line_Interpolate_Point(e.geom, 0.2)) as pos'
+      || ', ST_Line_Locate_Point('
+      || quote_literal(bounds::text)
+      || ', ST_Line_Interpolate_Point(e.geom, 0.8)) as pos2 FROM '
+      || quote_ident(toponame)
+      || '.edge e WHERE ( e.left_face = ' || face_id
+      || ' OR e.right_face = ' || face_id
+      || ') AND ST_Covers('
+      || quote_literal(bounds::text)
+      || ', e.geom) ORDER BY pos DESC'
+    LOOP
+
+      retrec.sequence = n;
+      retrec.edge = rec.edge_id;
+
+      -- if this edge goes in same direction to the
+      --       ring bounds, make it with negative orientation
+      IF rec.pos2 > rec.pos THEN -- edge goes in same direction
+        retrec.edge = -retrec.edge;
+      END IF;
+
+      RETURN NEXT retrec;
+
+      n = n+1;
+
+    END LOOP;
+  END LOOP; -- }
+
+  RETURN;
 END
 $$
 LANGUAGE 'plpgsql' VOLATILE;
index 04cf8620cf4d264858b9d918b8d830cfffb20b62..946c0d8fe6550e0a1e13198fc20019c6b841f352 100644 (file)
@@ -29,6 +29,7 @@ TESTS = regress/legacy_validate.sql regress/legacy_predicate.sql \
        regress/addface2.5d.sql \
        regress/polygonize.sql \
        regress/st_getfacegeometry.sql \
+       regress/st_getfaceedges.sql \
        regress/topoelement.sql \
        regress/topoelementarray_agg.sql \
        regress/topo2.5d.sql \
diff --git a/topology/test/regress/st_getfaceedges.sql b/topology/test/regress/st_getfaceedges.sql
new file mode 100644 (file)
index 0000000..408eda5
--- /dev/null
@@ -0,0 +1,24 @@
+set client_min_messages to ERROR;
+
+SELECT topology.CreateTopology('tt') > 0;
+
+SELECT 'E'||topology.AddEdge('tt', 'LINESTRING(2 2, 2  8)');        -- 1
+SELECT 'E'||topology.AddEdge('tt', 'LINESTRING(2  8,  8  8)');      -- 2
+SELECT 'E'||topology.AddEdge('tt', 'LINESTRING(8  8,  8 2, 2 2)');  -- 3
+SELECT 'E'||topology.AddEdge('tt', 'LINESTRING(0 0, 0 10, 10 10)'); -- 4
+SELECT 'E'||topology.AddEdge('tt', 'LINESTRING(0 0, 10 0)');        -- 5
+SELECT 'E'||topology.AddEdge('tt', 'LINESTRING(10 10, 10 5)');      -- 6
+SELECT 'E'||topology.AddEdge('tt', 'LINESTRING(10 0, 10 5)');       -- 7
+
+SELECT 'F' ||
+  topology.AddFace('tt',
+    'POLYGON((0 0, 10 0, 10 10, 0 10, 0 0),(2 2, 2 8, 8 8, 8 2, 2 2))');
+SELECT 'F' ||
+  topology.AddFace('tt',
+    'POLYGON((2 2, 2 8, 8 8, 8 2, 2 2))');
+
+SELECT 'F1', (topology.ST_GetFaceEdges('tt', 1)).*;
+SELECT 'F2', (topology.ST_GetFaceEdges('tt', 2)).*;
+
+
+SELECT topology.DropTopology('tt');
diff --git a/topology/test/regress/st_getfaceedges_expected b/topology/test/regress/st_getfaceedges_expected
new file mode 100644 (file)
index 0000000..05a5109
--- /dev/null
@@ -0,0 +1,21 @@
+t
+E1
+E2
+E3
+E4
+E5
+E6
+E7
+F1
+F2
+F1|1|7
+F1|2|-6
+F1|3|-4
+F1|4|5
+F1|5|1
+F1|6|2
+F1|7|3
+F2|1|-3
+F2|2|-2
+F2|3|-1
+Topology 'tt' dropped
index d2a596e4ad820a64b767a81cc024a91bd574ba5d..17529d9ecca356fd013568dcf8e542abf8d29d2f 100644 (file)
 --     Being working on. TODO: continue
 --  
 --   ST_GetFaceEdges
---     Unimplemented (C seems appropriate)
+--     Complete
 --  
 --   ST_GetFaceGeometry
 --     Implemented using polygonize()