]> granicus.if.org Git - postgis/commitdiff
Handle some (not all) cases of non-isomorphic edge changes (#1571)
authorSandro Santilli <strk@keybit.net>
Fri, 17 Feb 2012 13:46:33 +0000 (13:46 +0000)
committerSandro Santilli <strk@keybit.net>
Fri, 17 Feb 2012 13:46:33 +0000 (13:46 +0000)
The problem is much harder than it looks ...

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

topology/sql/sqlmm.sql.in.c
topology/test/regress/st_changeedgegeom.sql
topology/test/regress/st_changeedgegeom_expected

index 7f6eca0cf04199b765231744d52d5ecde90e9bd5..9ddeae6514bfd73b922c009b3b985c7722ca7f8a 100644 (file)
@@ -2528,21 +2528,18 @@ LANGUAGE 'plpgsql' VOLATILE;
 --
 -- Not in the specs:
 -- * Raise an exception if given a non-existent edge
+-- * Raise an exception if movement is not topologically isomorphic
 --
--- TODO: allow changing geometry of a closed edge (#982)
--- 
+-- }{
 CREATE OR REPLACE FUNCTION topology.ST_ChangeEdgeGeom(atopology varchar, anedge integer, acurve geometry)
   RETURNS TEXT AS
 $$
 DECLARE
-  aface INTEGER;
-  face GEOMETRY;
-  snodegeom GEOMETRY;
-  enodegeom GEOMETRY;
-  count INTEGER;
   rec RECORD;
-  edgeid INTEGER;
   oldedge RECORD;
+  range GEOMETRY; -- movement range
+  sql TEXT;
+  iscw BOOLEAN;
 BEGIN
 
   --
@@ -2595,13 +2592,30 @@ BEGIN
       'SQL/MM Spatial exception - start node not geometry start point.';
   END IF;
 
-  --
-  -- f) Check EndPoint consistency
-  --
-  IF NOT ST_Equals(ST_EndPoint(acurve), ST_EndPoint(oldedge.geom)) THEN
-    RAISE EXCEPTION
-      'SQL/MM Spatial exception - end node not geometry end point.';
-  END IF;
+  IF oldedge.start_node = oldedge.end_node THEN -- {
+
+    -- Not in the specs:
+    -- if the edge is closed, check we didn't change winding !
+    --       (should be part of isomorphism checking)
+    range := ST_MakePolygon(oldedge.geom);
+    iscw := ST_OrderingEquals(range, ST_ForceRHR(range));
+    range := ST_MakePolygon(acurve);
+    IF iscw != ST_OrderingEquals(range, ST_ForceRHR(range)) THEN
+      RAISE EXCEPTION 'Edge twist at node %',
+        ST_AsText(ST_StartPoint(oldedge.geom));
+    END IF;
+
+  ELSE -- }{
+
+    --
+    -- f) Check EndPoint consistency
+    --
+    IF NOT ST_Equals(ST_EndPoint(acurve), ST_EndPoint(oldedge.geom)) THEN
+      RAISE EXCEPTION
+        'SQL/MM Spatial exception - end node not geometry end point.';
+    END IF;
+
+  END IF; -- }
 
   --
   -- g) Check if curve crosses any node
@@ -2622,13 +2636,13 @@ BEGIN
   --
   -- h) Check if this geometry has any interaction with any existing edge
   --
-  FOR rec IN EXECUTE 'SELECT edge_id, ST_Relate(geom,' 
+  sql := 'SELECT edge_id, ST_Relate(geom,' 
     || quote_literal(acurve::text)
     || '::geometry, 2) as im FROM '
     || quote_ident(atopology)
     || '.edge_data WHERE edge_id != ' || anedge || ' AND geom && '
-    || quote_literal(acurve::text) || '::geometry'
-  LOOP
+    || quote_literal(acurve::text) || '::geometry';
+  FOR rec IN EXECUTE sql LOOP -- {
 
     --RAISE DEBUG 'IM=%',rec.im;
 
@@ -2652,7 +2666,29 @@ BEGIN
         'SQL/MM Spatial exception - geometry crosses an edge';
     END IF;
 
-  END LOOP;
+  END LOOP; -- }
+
+  --
+  -- Not in the specs:
+  -- Check topological isomorphism 
+  --
+  range := ST_MakeLine(oldedge.geom, ST_Reverse(acurve));
+  RAISE DEBUG 'Made line: %', ST_AsText(range);
+  range := ST_MakePolygon(range);
+  RAISE DEBUG 'Made poly: %', ST_AsText(range);
+  range := ST_CollectionExtract(ST_MakeValid(range), 3);
+  RAISE DEBUG 'Range motion: %', ST_AsText(range);
+  sql := 'SELECT node_id, geom FROM '
+    || quote_ident(atopology)
+    || '.node WHERE ST_Contains('
+    || quote_literal(range::text)
+    || '::geometry, geom) LIMIT 1';
+  RAISE DEBUG '%', sql;
+  FOR rec IN EXECUTE sql LOOP -- {
+    RAISE EXCEPTION 'Edge motion collision at %', ST_AsText(rec.geom);
+  END LOOP; -- }
+
+  --RAISE EXCEPTION 'Not doing it';
 
   --
   -- Update edge geometry
@@ -2661,13 +2697,6 @@ BEGIN
     || ' SET geom = ' || quote_literal(acurve::text) 
     || ' WHERE edge_id = ' || anedge;
 
-  --
-  -- TODO: Check if we need to update linking
-  -- We do if:
-  --   o edge is closed and we changed direction)
-  --   o edge moved to another face
-  -- 
-
   RETURN 'Edge ' || anedge || ' changed';
 
 END
index af05e42887536d5faf45b1ffec8d99f16e1e91bf..1dd157ec20760180a37d9c8e421e2eb87c703752 100644 (file)
@@ -37,6 +37,41 @@ SELECT 'T3', topology.ST_ChangeEdgeGeom('city_data', 5,
 SELECT 'T4', topology.ST_ChangeEdgeGeom('city_data', 26,
  'LINESTRING(4 31, 7 31, 4 34, 4 31)');
 
--- TODO: test reverse direction of closed edge
+-- Collisions on edge motion path is forbidden:
+-- get to include a whole isolated edge
+SELECT topology.ST_ChangeEdgeGeom('city_data', 26,
+ 'LINESTRING(4 31, 7 31, 15 34, 12 37.5, 4 34, 4 31)');
+
+-- This movement doesn't collide:
+SELECT 'T5', topology.ST_ChangeEdgeGeom('city_data', 3,
+ 'LINESTRING(25 30, 18 35, 18 39, 23 39, 23 36, 20 38, 19 37, 20 35, 25 35)');
+
+-- This movement doesn't collide either:
+SELECT 'T6', topology.ST_ChangeEdgeGeom('city_data', 3,
+ 'LINESTRING(25 30, 22 38, 25 35)');
+
+-- This movement gets to include an isolated node:
+SELECT topology.ST_ChangeEdgeGeom('city_data', 3,
+ 'LINESTRING(25 30, 18 35, 18 39, 23 39, 23 36, 20 35, 25 35)');
+
+-- This movement is legit
+SELECT 'T7', topology.ST_ChangeEdgeGeom('city_data', 2,
+ 'LINESTRING(25 30, 28 39, 16 39, 25 30)');
+
+-- This movement gets to exclude an isolated node:
+SELECT topology.ST_ChangeEdgeGeom('city_data', 2,
+ 'LINESTRING(25 30, 28 39, 20 39, 25 30)');
+
+-- Test changing winding direction of closed edge
+SELECT topology.ST_ChangeEdgeGeom('city_data', 26,
+ ST_Reverse('LINESTRING(4 31, 7 31, 4 34, 4 31)'));
+
+-- Maintain winding of closed edge 
+SELECT 'T8', topology.ST_ChangeEdgeGeom('city_data', 26,
+ 'LINESTRING(4 31, 4 30.4, 5 30.4, 4 31)');
+
+-- TODO: test moving closed edge into another face
+-- TODO: test changing winding of non-closed edge ring
+-- TODO: test face mbr update
 
 SELECT topology.DropTopology('city_data');
index 3f5b1fee357189168736e3bc47e8d6b94dc1ef9a..3080081a81a6b71f71ef4929ffd1e9234a14511a 100644 (file)
@@ -13,4 +13,12 @@ ERROR:  SQL/MM Spatial exception - geometry crosses an edge
 T2|Edge 5 changed
 T3|Edge 5 changed
 T4|Edge 26 changed
+ERROR:  Edge motion collision at POINT(9 35)
+T5|Edge 3 changed
+T6|Edge 3 changed
+ERROR:  Edge motion collision at POINT(20 37)
+T7|Edge 2 changed
+ERROR:  Edge motion collision at POINT(25 35)
+ERROR:  Edge twist at node POINT(4 31)
+T8|Edge 26 changed
 Topology 'city_data' dropped