From: Sandro Santilli Date: Tue, 3 May 2011 13:32:41 +0000 (+0000) Subject: Implement ST_GetFaceEdges (sql/mm topology function) [RT-SIGTA] X-Git-Tag: 2.0.0alpha1~1726 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ece190863a0aaa71121f0055ff6651f28896bd8c;p=postgis Implement ST_GetFaceEdges (sql/mm topology function) [RT-SIGTA] git-svn-id: http://svn.osgeo.org/postgis/trunk@7081 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/topology/sql/sqlmm.sql b/topology/sql/sqlmm.sql index 929bdf5ff..94b076f8a 100644 --- a/topology/sql/sqlmm.sql +++ b/topology/sql/sqlmm.sql @@ -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; diff --git a/topology/test/Makefile b/topology/test/Makefile index 04cf8620c..946c0d8fe 100644 --- a/topology/test/Makefile +++ b/topology/test/Makefile @@ -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 index 000000000..408eda5be --- /dev/null +++ b/topology/test/regress/st_getfaceedges.sql @@ -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 index 000000000..05a5109eb --- /dev/null +++ b/topology/test/regress/st_getfaceedges_expected @@ -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 diff --git a/topology/topology.sql.in.c b/topology/topology.sql.in.c index d2a596e4a..17529d9ec 100644 --- a/topology/topology.sql.in.c +++ b/topology/topology.sql.in.c @@ -155,7 +155,7 @@ -- Being working on. TODO: continue -- -- ST_GetFaceEdges --- Unimplemented (C seems appropriate) +-- Complete -- -- ST_GetFaceGeometry -- Implemented using polygonize()