]> granicus.if.org Git - postgis/commitdiff
Fix ST_ModEdgeHeal and ST_NewEdgeHeal for doubly connected edges
authorSandro Santilli <strk@keybit.net>
Fri, 17 Aug 2012 17:18:41 +0000 (17:18 +0000)
committerSandro Santilli <strk@keybit.net>
Fri, 17 Aug 2012 17:18:41 +0000 (17:18 +0000)
Includes testcases, closes #1955

git-svn-id: http://svn.osgeo.org/postgis/trunk@10189 b70326c6-7e19-0410-871a-916f4a2858ee

topology/sql/sqlmm.sql.in.c
topology/test/regress/st_modedgeheal.sql
topology/test/regress/st_modedgeheal_expected
topology/test/regress/st_newedgeheal.sql
topology/test/regress/st_newedgeheal_expected

index b6d0b3110366415f4c62d284cc79082f790ac118..0176de6b5480d6d65d19f0bfb7ee7d336f8a4c4e 100644 (file)
@@ -166,6 +166,7 @@ DECLARE
   e2rec RECORD;
   rec RECORD;
   newedgeid int;
+  connectededges int[];
   commonnode int;
   caseno int;
   topoid int;
@@ -228,31 +229,56 @@ BEGIN
   END IF;
 
   -- Find common node
+
   IF e1rec.end_node = e2rec.start_node THEN
     commonnode = e1rec.end_node;
     caseno = 1;
   ELSIF e1rec.end_node = e2rec.end_node THEN
     commonnode = e1rec.end_node;
     caseno = 2;
-  ELSIF e1rec.start_node = e2rec.start_node THEN
-    commonnode = e1rec.start_node;
-    caseno = 3;
-  ELSIF e1rec.start_node = e2rec.end_node THEN
-    commonnode = e1rec.start_node;
-    caseno = 4;
-  ELSE
-    RAISE EXCEPTION 'SQL/MM Spatial exception - non-connected edges';
   END IF;
 
   -- Check if any other edge is connected to the common node
-  FOR rec IN EXECUTE 'SELECT edge_id FROM ' || quote_ident(toponame)
-    || '.edge_data WHERE ( edge_id != ' || e1id
-    || ' AND edge_id != ' || e2id || ') AND ( start_node = '
-    || commonnode || ' OR end_node = ' || commonnode || ' )'
-  LOOP
-    RAISE EXCEPTION
-      'SQL/MM Spatial exception - other edges connected (ie: %)', rec.edge_id;
-  END LOOP;
+  IF commonnode IS NOT NULL THEN
+    FOR rec IN EXECUTE 'SELECT edge_id FROM ' || quote_ident(toponame)
+      || '.edge_data WHERE ( edge_id != ' || e1id
+      || ' AND edge_id != ' || e2id || ') AND ( start_node = '
+      || commonnode || ' OR end_node = ' || commonnode || ' )'
+    LOOP
+      commonnode := NULL;
+      connectededges = connectededges || rec.edge_id;
+    END LOOP;
+  END IF;
+
+  IF commonnode IS NULL THEN
+    IF e1rec.start_node = e2rec.start_node THEN
+      commonnode = e1rec.start_node;
+      caseno = 3;
+    ELSIF e1rec.start_node = e2rec.end_node THEN
+      commonnode = e1rec.start_node;
+      caseno = 4;
+    END IF;
+
+    -- Check if any other edge is connected to the common node
+    IF commonnode IS NOT NULL THEN
+      FOR rec IN EXECUTE 'SELECT edge_id FROM ' || quote_ident(toponame)
+        || '.edge_data WHERE ( edge_id != ' || e1id
+        || ' AND edge_id != ' || e2id || ') AND ( start_node = '
+        || commonnode || ' OR end_node = ' || commonnode || ' )'
+      LOOP
+        commonnode := NULL;
+        connectededges = connectededges || rec.edge_id;
+      END LOOP;
+    END IF;
+  END IF;
+
+  IF commonnode IS NULL THEN
+    IF connectededges IS NOT NULL THEN
+      RAISE EXCEPTION 'SQL/MM Spatial exception - other edges connected (%)', array_to_string(connectededges, ',');
+    ELSE
+      RAISE EXCEPTION 'SQL/MM Spatial exception - non-connected edges';
+    END IF;
+  END IF;
 
   -- NOT IN THE SPECS:
   -- check if any topo_geom is defined only by one of the
@@ -454,6 +480,7 @@ DECLARE
   e1rec RECORD;
   e2rec RECORD;
   rec RECORD;
+  connectededges int[];
   commonnode int;
   caseno int;
   topoid int;
@@ -516,31 +543,56 @@ BEGIN
   END IF;
 
   -- Find common node
+
   IF e1rec.end_node = e2rec.start_node THEN
     commonnode = e1rec.end_node;
     caseno = 1;
   ELSIF e1rec.end_node = e2rec.end_node THEN
     commonnode = e1rec.end_node;
     caseno = 2;
-  ELSIF e1rec.start_node = e2rec.start_node THEN
-    commonnode = e1rec.start_node;
-    caseno = 3;
-  ELSIF e1rec.start_node = e2rec.end_node THEN
-    commonnode = e1rec.start_node;
-    caseno = 4;
-  ELSE
-    RAISE EXCEPTION 'SQL/MM Spatial exception - non-connected edges';
   END IF;
 
   -- Check if any other edge is connected to the common node
-  FOR rec IN EXECUTE 'SELECT edge_id FROM ' || quote_ident(toponame)
-    || '.edge_data WHERE ( edge_id != ' || e1id
-    || ' AND edge_id != ' || e2id || ') AND ( start_node = '
-    || commonnode || ' OR end_node = ' || commonnode || ' )'
-  LOOP
-    RAISE EXCEPTION
-      'SQL/MM Spatial exception - other edges connected (ie: %)', rec.edge_id;
-  END LOOP;
+  IF commonnode IS NOT NULL THEN
+    FOR rec IN EXECUTE 'SELECT edge_id FROM ' || quote_ident(toponame)
+      || '.edge_data WHERE ( edge_id != ' || e1id
+      || ' AND edge_id != ' || e2id || ') AND ( start_node = '
+      || commonnode || ' OR end_node = ' || commonnode || ' )'
+    LOOP
+      commonnode := NULL;
+      connectededges = connectededges || rec.edge_id;
+    END LOOP;
+  END IF;
+
+  IF commonnode IS NULL THEN
+    IF e1rec.start_node = e2rec.start_node THEN
+      commonnode = e1rec.start_node;
+      caseno = 3;
+    ELSIF e1rec.start_node = e2rec.end_node THEN
+      commonnode = e1rec.start_node;
+      caseno = 4;
+    END IF;
+
+    -- Check if any other edge is connected to the common node
+    IF commonnode IS NOT NULL THEN
+      FOR rec IN EXECUTE 'SELECT edge_id FROM ' || quote_ident(toponame)
+        || '.edge_data WHERE ( edge_id != ' || e1id
+        || ' AND edge_id != ' || e2id || ') AND ( start_node = '
+        || commonnode || ' OR end_node = ' || commonnode || ' )'
+      LOOP
+        commonnode := NULL;
+        connectededges = connectededges || rec.edge_id;
+      END LOOP;
+    END IF;
+  END IF;
+
+  IF commonnode IS NULL THEN
+    IF connectededges IS NOT NULL THEN
+      RAISE EXCEPTION 'SQL/MM Spatial exception - other edges connected (%)', array_to_string(connectededges, ',');
+    ELSE
+      RAISE EXCEPTION 'SQL/MM Spatial exception - non-connected edges';
+    END IF;
+  END IF;
 
   -- NOT IN THE SPECS:
   -- check if any topo_geom is defined only by one of the
index 2d4038b277e8aa60d738aa8654b65e482dcf944f..1e39f2351366528cedba972e3b934b84729ca4ea 100644 (file)
@@ -115,6 +115,51 @@ SELECT topology.DropTopology('t');
 -------------------------------------------------------------------------
 -------------------------------------------------------------------------
 
+-- Test edges sharing both endpoints
+-- See http://trac.osgeo.org/postgis/ticket/1955
+
+SELECT '#1955', topology.CreateTopology('t') > 1;
+
+SELECT '#1955.1', 'E'||topology.AddEdge('t', 'LINESTRING(0 0, 10 0, 10 10)');        -- 1
+SELECT '#1955.1', 'E'||topology.AddEdge('t', 'LINESTRING(0 0, 0 10, 10 10)'); ;      -- 2
+
+SELECT '#1955.1', count(node_id), 'start nodes' as label FROM t.node GROUP BY label; 
+
+-- Deletes second node. Not very predictable which one is removed
+SELECT '#1955.1', 'H:1,2', 'N' || topology.ST_ModEdgeHeal('t', 1, 2), 'deleted';
+
+SELECT '#1955.1', count(node_id), 'nodes left' as label FROM t.node GROUP BY label; 
+
+SELECT '#1955.2', 'E'||topology.AddEdge('t', 'LINESTRING(50 0, 60 0, 60 10)');        -- 3
+SELECT '#1955.2', 'E'||topology.AddEdge('t', 'LINESTRING(50 0, 50 10, 60 10)'); ;     -- 4
+SELECT '#1955.2', 'E'||topology.AddEdge('t', 'LINESTRING(60 10, 70 10)'); ;           -- 5
+
+SELECT '#1955.2', count(node_id), 'start nodes' as label FROM t.node GROUP BY label; 
+
+-- Only the start node can be deleted (50 0) because the other is shared by
+-- another edge 
+SELECT '#1955.2', 'H:3,4', 'N' || topology.ST_ModEdgeHeal('t', 3, 4), 'deleted';
+
+SELECT '#1955.2', count(node_id), 'nodes left' as label FROM t.node GROUP BY label; 
+
+SELECT '#1955.3', 'E'||topology.AddEdge('t', 'LINESTRING(80 0, 90 0, 90 10)');        -- 6
+SELECT '#1955.3', 'E'||topology.AddEdge('t', 'LINESTRING(80 0, 80 10, 90 10)'); ;     -- 7
+SELECT '#1955.3', 'E'||topology.AddEdge('t', 'LINESTRING(70 10, 80 0)'); ;            -- 8
+
+SELECT '#1955.3', count(node_id), 'start nodes' as label FROM t.node GROUP BY label; 
+
+-- Only the end node can be deleted (90 10) because the other is shared by
+-- another edge 
+SELECT '#1955.3', 'H:6,7', 'N' || topology.ST_ModEdgeHeal('t', 6, 7), 'deleted';
+
+SELECT '#1955.3', count(node_id), 'nodes left' as label FROM t.node GROUP BY label; 
+
+SELECT '#1955', topology.DropTopology('t');
+
+-------------------------------------------------------------------------
+-------------------------------------------------------------------------
+-------------------------------------------------------------------------
+
 -- TODO: test registered but unexistent topology
 -- TODO: test registered but corrupted topology
 --       (missing node, edge, relation...)
index c4f19564445125ede9250dfceac519fa8efb2673..94e5294e8c1c572e19e8539b49bfeff592c66984 100644 (file)
@@ -9,7 +9,7 @@ ERROR:  SQL/MM Spatial exception - null argument
 ERROR:  SQL/MM Spatial exception - null argument
 ERROR:  SQL/MM Spatial exception - invalid topology name
 ERROR:  SQL/MM Spatial exception - non-connected edges
-ERROR:  SQL/MM Spatial exception - other edges connected (ie: 19)
+ERROR:  SQL/MM Spatial exception - other edges connected (19,20)
 ERROR:  Edge 2 is closed, cannot heal to edge 3
 ERROR:  Edge 2 is closed, cannot heal to edge 3
 ERROR:  Cannot heal edge 25 with itself, try with another
@@ -120,3 +120,22 @@ ERROR:  SQL/MM Spatial exception - non-connected edges
 2|3
 3|-3
 Topology 't' dropped
+#1955|t
+#1955.1|E1
+#1955.1|E2
+#1955.1|2|start nodes
+#1955.1|H:1,2|N2|deleted
+#1955.1|1|nodes left
+#1955.2|E3
+#1955.2|E4
+#1955.2|E5
+#1955.2|4|start nodes
+#1955.2|H:3,4|N3|deleted
+#1955.2|3|nodes left
+#1955.3|E6
+#1955.3|E7
+#1955.3|E8
+#1955.3|5|start nodes
+#1955.3|H:6,7|N7|deleted
+#1955.3|4|nodes left
+#1955|Topology 't' dropped
index 641a347cc4db165aa0c1742a8c06f4932317a715..e3192205db58e24956aa55ed6332d222c0138d07 100644 (file)
@@ -115,6 +115,49 @@ SELECT topology.DropTopology('t');
 -------------------------------------------------------------------------
 -------------------------------------------------------------------------
 
+SELECT '#1955', topology.CreateTopology('t') > 1;
+
+SELECT '#1955.1', 'E'||topology.AddEdge('t', 'LINESTRING(0 0, 10 0, 10 10)');        -- 1
+SELECT '#1955.1', 'E'||topology.AddEdge('t', 'LINESTRING(0 0, 0 10, 10 10)'); ;      -- 2
+
+SELECT '#1955.1', count(node_id), 'start nodes' as label FROM t.node GROUP BY label; 
+
+-- Deletes second node. Not very predictable which one is removed
+SELECT '#1955.1', 'H:1,2', 'E' || topology.ST_NewEdgeHeal('t', 1, 2), 'created';
+
+SELECT '#1955.1', count(node_id), 'nodes left' as label FROM t.node GROUP BY label; 
+
+SELECT '#1955.2', 'E'||topology.AddEdge('t', 'LINESTRING(50 0, 60 0, 60 10)');        -- 4
+SELECT '#1955.2', 'E'||topology.AddEdge('t', 'LINESTRING(50 0, 50 10, 60 10)'); ;     -- 5
+SELECT '#1955.2', 'E'||topology.AddEdge('t', 'LINESTRING(60 10, 70 10)'); ;           -- 6
+
+SELECT '#1955.2', count(node_id), 'start nodes' as label FROM t.node GROUP BY label; 
+
+-- Only the start node can be deleted (50 0) because the other is shared by
+-- another edge 
+SELECT '#1955.2', 'H:4,5', 'E' || topology.ST_NewEdgeHeal('t', 4, 5), 'created';
+
+SELECT '#1955.2', count(node_id), 'nodes left' as label FROM t.node GROUP BY label; 
+
+SELECT '#1955.3', 'E'||topology.AddEdge('t', 'LINESTRING(80 0, 90 0, 90 10)');        -- 8
+SELECT '#1955.3', 'E'||topology.AddEdge('t', 'LINESTRING(80 0, 80 10, 90 10)'); ;     -- 9
+SELECT '#1955.3', 'E'||topology.AddEdge('t', 'LINESTRING(70 10, 80 0)'); ;            -- 10
+
+SELECT '#1955.3', count(node_id), 'start nodes' as label FROM t.node GROUP BY label; 
+
+-- Only the end node can be deleted (90 10) because the other is shared by
+-- another edge 
+SELECT '#1955.3', 'H:8,9', 'E' || topology.ST_NewEdgeHeal('t', 8, 9), 'created';
+
+SELECT '#1955.3', count(node_id), 'nodes left' as label FROM t.node GROUP BY label; 
+
+SELECT '#1955', topology.DropTopology('t');
+
+-------------------------------------------------------------------------
+-------------------------------------------------------------------------
+-------------------------------------------------------------------------
+
+
 -- TODO: test registered but unexistent topology
 -- TODO: test registered but corrupted topology
 --       (missing node, edge, relation...)
index 6593547d72c6a6f5451d668d811a8341bffe4230..09be659bca88b9988013bffe9956225bd4866ece 100644 (file)
@@ -9,7 +9,7 @@ ERROR:  SQL/MM Spatial exception - null argument
 ERROR:  SQL/MM Spatial exception - null argument
 ERROR:  SQL/MM Spatial exception - invalid topology name
 ERROR:  SQL/MM Spatial exception - non-connected edges
-ERROR:  SQL/MM Spatial exception - other edges connected (ie: 19)
+ERROR:  SQL/MM Spatial exception - other edges connected (19,20)
 ERROR:  Edge 2 is closed, cannot heal to edge 3
 ERROR:  Edge 2 is closed, cannot heal to edge 3
 ERROR:  Cannot heal edge 25 with itself, try with another
@@ -120,3 +120,22 @@ ERROR:  SQL/MM Spatial exception - non-connected edges
 2|5
 3|-5
 Topology 't' dropped
+#1955|t
+#1955.1|E1
+#1955.1|E2
+#1955.1|2|start nodes
+#1955.1|H:1,2|E3|created
+#1955.1|1|nodes left
+#1955.2|E4
+#1955.2|E5
+#1955.2|E6
+#1955.2|4|start nodes
+#1955.2|H:4,5|E7|created
+#1955.2|3|nodes left
+#1955.3|E8
+#1955.3|E9
+#1955.3|E10
+#1955.3|5|start nodes
+#1955.3|H:8,9|E11|created
+#1955.3|4|nodes left
+#1955|Topology 't' dropped