]> granicus.if.org Git - postgis/commitdiff
Implement and regress-test TopoGeo_addPolygon
authorSandro Santilli <strk@keybit.net>
Tue, 3 Jan 2012 23:17:42 +0000 (23:17 +0000)
committerSandro Santilli <strk@keybit.net>
Tue, 3 Jan 2012 23:17:42 +0000 (23:17 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@8663 b70326c6-7e19-0410-871a-916f4a2858ee

topology/sql/populate.sql
topology/test/Makefile
topology/test/regress/topogeo_addpolygon.sql [new file with mode: 0644]
topology/test/regress/topogeo_addpolygon_expected [new file with mode: 0644]

index 6d0e6c1bab480569595a30b71d686f95b5706a1e..a4930165e9cea0a932bd9335f856108c5e0b59dc 100644 (file)
@@ -750,6 +750,7 @@ BEGIN
     set2 := ST_Intersection(snapped, set1);
     RAISE DEBUG 'Intersection: %', ST_AsText(set2);
     noded := ST_Union(noded, set2);
+    -- TODO: linemerge ?
   END IF;
 
   -- 3. For each (now-noded) segment, insert an edge
@@ -813,14 +814,45 @@ CREATE OR REPLACE FUNCTION topology.TopoGeo_AddPolygon(atopology varchar, apoly
        RETURNS SETOF int AS
 $$
 DECLARE
+  boundary GEOMETRY;
+  fgeom GEOMETRY;
+  rec RECORD;
+  edges INTEGER[];
+  sql TEXT;
 BEGIN
 
   -- 0. Check arguments
-  IF geometrytype(aline) != 'POLYGON' THEN
-    RAISE EXCEPTION 'Invalid geometry type (%) passed to TopoGeo_AddPolygon, expected POLYGON', geometrytype(aline);
+  IF geometrytype(apoly) != 'POLYGON' THEN
+    RAISE EXCEPTION 'Invalid geometry type (%) passed to TopoGeo_AddPolygon, expected POLYGON', geometrytype(apoly);
   END IF;
 
-       RAISE EXCEPTION 'TopoGeo_AddPolygon not implemented yet';
+  -- 1. Extract boundary
+  boundary := ST_Boundary(apoly);
+  RAISE DEBUG 'Boundary: %', ST_AsText(boundary);
+
+  -- 2. Add boundaries as edges
+  FOR rec IN SELECT (ST_Dump(boundary)).geom LOOP
+    edges := array_cat(edges, array_agg(x)) FROM ( select topology.TopoGeo_addLinestring(atopology, rec.geom, tolerance) as x ) as foo;
+    RAISE DEBUG 'New edges: %', edges;
+  END LOOP;
+
+  -- 3. Find faces covered by input polygon
+  --    NOTE: potential snapping changed polygon edges
+  sql := 'SELECT DISTINCT f.face_id FROM ' || quote_ident(atopology)
+    || '.face f WHERE f.mbr && '
+    || quote_literal(apoly::text)
+    || '::geometry';
+  RAISE DEBUG '%', sql;
+  FOR rec IN EXECUTE sql LOOP
+    -- check for actual containment
+    fgeom := ST_PointOnSurface(ST_GetFaceGeometry(atopology, rec.face_id));
+    IF NOT ST_Covers(apoly, fgeom) THEN
+      RAISE DEBUG 'Face % not covered by input polygon', rec.face_id;
+      CONTINUE;
+    END IF;
+    RETURN NEXT rec.face_id;
+  END LOOP;
+
 END
 $$
 LANGUAGE 'plpgsql';
index 787d7569f6ba5e049db9a96d0fa44f993709db5b..fc2867eefd73b9e5a1ded8a389000956d4c29cb6 100644 (file)
@@ -42,8 +42,9 @@ TESTS = regress/legacy_validate.sql regress/legacy_predicate.sql \
        regress/st_remedgemodface.sql \
        regress/topoelement.sql \
        regress/topoelementarray_agg.sql \
-       regress/topogeo_addpoint.sql \
        regress/topogeo_addlinestring \
+       regress/topogeo_addpoint.sql \
+       regress/topogeo_addpolygon.sql \
        regress/topogeometry_type.sql \
        regress/topo2.5d.sql \
        regress/totopogeom.sql \
diff --git a/topology/test/regress/topogeo_addpolygon.sql b/topology/test/regress/topogeo_addpolygon.sql
new file mode 100644 (file)
index 0000000..4e415e9
--- /dev/null
@@ -0,0 +1,112 @@
+\set VERBOSITY terse
+set client_min_messages to ERROR;
+
+\i load_topology.sql
+
+-- Save max node,edge and face ids
+select 'node'::text as what, max(node_id) INTO city_data.limits FROM city_data.node;
+INSERT INTO city_data.limits select 'edge'::text as what, max(edge_id) FROM city_data.edge;
+INSERT INTO city_data.limits select 'face'::text as what, max(face_id) FROM city_data.face;
+SELECT 'max',* from city_data.limits;
+
+-- Check changes since last saving, save more
+-- {
+CREATE OR REPLACE FUNCTION check_changes()
+RETURNS TABLE (o text)
+AS $$
+DECLARE
+  rec RECORD;
+  sql text;
+BEGIN
+  -- Check effect on nodes
+  sql := 'SELECT n.node_id, ''N|'' || n.node_id || ''|'' ||
+        COALESCE(n.containing_face::text,'''') || ''|'' ||
+        ST_AsText(ST_SnapToGrid(n.geom, 0.2))::text as xx
+       FROM city_data.node n WHERE n.node_id > (
+               SELECT max FROM city_data.limits WHERE what = ''node''::text )
+               ORDER BY n.node_id';
+
+  FOR rec IN EXECUTE sql LOOP
+    o := rec.xx;
+    RETURN NEXT;
+  END LOOP;
+  
+  -- Check effect on edges 
+  sql := '
+  WITH node_limits AS ( SELECT max FROM city_data.limits WHERE what = ''node''::text ),
+       edge_limits AS ( SELECT max FROM city_data.limits WHERE what = ''edge''::text )
+  SELECT ''E|'' || e.edge_id || ''|sn'' || e.start_node || ''|en'' || e.end_node :: text as xx
+   FROM city_data.edge e, node_limits nl, edge_limits el
+   WHERE e.start_node > nl.max
+      OR e.end_node > nl.max
+      OR e.edge_id > el.max
+  ORDER BY e.edge_id;
+  ';
+
+  FOR rec IN EXECUTE sql LOOP
+    o := rec.xx;
+    RETURN NEXT;
+  END LOOP;
+
+  -- Check effect on faces
+  sql := '
+  WITH face_limits AS ( SELECT max FROM city_data.limits WHERE what = ''face''::text )
+  SELECT ''F|'' || f.face_id ::text as xx
+   FROM city_data.face f, face_limits fl
+   WHERE f.face_id > fl.max
+  ORDER BY f.face_id;
+  ';
+
+  FOR rec IN EXECUTE sql LOOP
+    o := rec.xx;
+    RETURN NEXT;
+  END LOOP;
+
+  UPDATE city_data.limits SET max = (SELECT max(n.node_id) FROM city_data.node n) WHERE what = 'node';
+  UPDATE city_data.limits SET max = (SELECT max(e.edge_id) FROM city_data.edge e) WHERE what = 'edge';
+  UPDATE city_data.limits SET max = (SELECT max(f.face_id) FROM city_data.face f) WHERE what = 'face';
+
+END;
+$$ LANGUAGE 'plpgsql';
+-- }
+
+
+-- Invalid calls
+SELECT 'invalid', TopoGeo_addPolygon('city_data', 'MULTILINESTRING((36 26, 38 30))');
+SELECT 'invalid', TopoGeo_addPolygon('city_data', 'POINT(36 26)');
+
+-- Isolated face in universal face
+SELECT 'iso_uni', TopoGeo_addPolygon('city_data', 'POLYGON((36 26, 38 30, 43 26, 36 26))');
+SELECT check_changes();
+
+-- Isolated face in universal face with hole
+SELECT 'iso_uni_hole', TopoGeo_addPolygon('city_data', 'POLYGON((9 28, 16 29, 16 23, 10 23, 9 28),(15 25, 13 27, 11 24, 15 25))');
+SELECT check_changes();
+
+-- Existing single face
+SELECT 'ex', TopoGeo_addPolygon('city_data', 'POLYGON((21 22,35 22,35 14,21 14,21 22))');
+SELECT check_changes();
+
+-- Union of existing faces
+SELECT 'ex_union', TopoGeo_addPolygon('city_data', 'POLYGON((9 14,21 14,35 14,35 6,21 6,9 6,9 14))') ORDER BY 2;
+SELECT check_changes();
+
+-- Half an existing face
+SELECT 'half', TopoGeo_addPolygon('city_data', 'POLYGON((21 14, 35 22, 35 14, 21 14))');
+SELECT check_changes();
+
+-- Split two existing faces
+SELECT 'split', TopoGeo_addPolygon('city_data', 'POLYGON((21 14, 21 22, 35 14, 21 14))') ORDER BY 2;
+SELECT check_changes();
+
+-- Union of existing face, with hole
+SELECT 'ex_hole', TopoGeo_addPolygon('city_data', 'POLYGON((9 22,47 22,47 6,9 6,9 22),(21 14,28 18,35 14,21 14))') ORDER BY 2;
+SELECT check_changes();
+
+-- Union of existing face, with hole and a tolerance
+SELECT 'ex_hole_snap', TopoGeo_addPolygon('city_data', 'POLYGON((9 22,35 22.5, 47 22,47 6,9 6,9 22),(21 14,28 17.5,35 14,21 14))', 1) ORDER BY 2;
+SELECT check_changes();
+
+DROP FUNCTION check_changes();
+SELECT DropTopology('city_data');
+
diff --git a/topology/test/regress/topogeo_addpolygon_expected b/topology/test/regress/topogeo_addpolygon_expected
new file mode 100644 (file)
index 0000000..40a37a8
--- /dev/null
@@ -0,0 +1,54 @@
+BEGIN
+t
+9
+22
+26
+COMMIT
+max|node|22
+max|edge|26
+max|face|9
+ERROR:  Invalid geometry type (MULTILINESTRING) passed to TopoGeo_AddPolygon, expected POLYGON
+ERROR:  Invalid geometry type (POINT) passed to TopoGeo_AddPolygon, expected POLYGON
+iso_uni|10
+N|23||POINT(36 26)
+E|27|sn23|en23
+F|10
+iso_uni_hole|11
+N|24||POINT(9 28)
+N|25||POINT(15 25)
+E|28|sn24|en24
+E|29|sn25|en25
+F|11
+F|12
+ex|4
+ex_union|6
+ex_union|7
+half|4
+E|30|sn14|en18
+F|13
+split|4
+split|13
+N|26||POINT(28 18)
+E|30|sn14|en26
+E|31|sn26|en18
+E|32|sn17|en26
+E|33|sn26|en13
+F|14
+F|15
+ex_hole|3
+ex_hole|5
+ex_hole|6
+ex_hole|7
+ex_hole|8
+ex_hole|13
+ex_hole|14
+ex_hole|15
+ex_hole_snap|3
+ex_hole_snap|5
+ex_hole_snap|6
+ex_hole_snap|7
+ex_hole_snap|8
+ex_hole_snap|13
+ex_hole_snap|14
+ex_hole_snap|15
+Topology 'city_data' dropped