From e13e1fc34943bce42f6a95d70ce5ca1c94be4587 Mon Sep 17 00:00:00 2001 From: Sandro Santilli Date: Fri, 17 Feb 2012 13:46:33 +0000 Subject: [PATCH] Handle some (not all) cases of non-isomorphic edge changes (#1571) 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 | 81 +++++++++++++------ topology/test/regress/st_changeedgegeom.sql | 37 ++++++++- .../test/regress/st_changeedgegeom_expected | 8 ++ 3 files changed, 99 insertions(+), 27 deletions(-) diff --git a/topology/sql/sqlmm.sql.in.c b/topology/sql/sqlmm.sql.in.c index 7f6eca0cf..9ddeae651 100644 --- a/topology/sql/sqlmm.sql.in.c +++ b/topology/sql/sqlmm.sql.in.c @@ -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 diff --git a/topology/test/regress/st_changeedgegeom.sql b/topology/test/regress/st_changeedgegeom.sql index af05e4288..1dd157ec2 100644 --- a/topology/test/regress/st_changeedgegeom.sql +++ b/topology/test/regress/st_changeedgegeom.sql @@ -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'); diff --git a/topology/test/regress/st_changeedgegeom_expected b/topology/test/regress/st_changeedgegeom_expected index 3f5b1fee3..3080081a8 100644 --- a/topology/test/regress/st_changeedgegeom_expected +++ b/topology/test/regress/st_changeedgegeom_expected @@ -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 -- 2.50.1