From 90bb0776df195e6421c216c7f8f4c220494bd11e Mon Sep 17 00:00:00 2001 From: Sandro Santilli Date: Tue, 24 Jan 2012 11:15:56 +0000 Subject: [PATCH] Fix edge-linking in ST_ModEdgeSplit (#1496) Includes regression test. ST_NewEdgesSplit still needs testing. git-svn-id: http://svn.osgeo.org/postgis/trunk@8911 b70326c6-7e19-0410-871a-916f4a2858ee --- topology/sql/sqlmm.sql.in.c | 36 ++++--- topology/test/Makefile | 1 + topology/test/regress/st_modedgesplit.sql | 96 +++++++++++++++++++ .../test/regress/st_modedgesplit_expected | 36 +++++++ 4 files changed, 156 insertions(+), 13 deletions(-) create mode 100644 topology/test/regress/st_modedgesplit.sql create mode 100644 topology/test/regress/st_modedgesplit_expected diff --git a/topology/sql/sqlmm.sql.in.c b/topology/sql/sqlmm.sql.in.c index d36143f31..408d2e190 100644 --- a/topology/sql/sqlmm.sql.in.c +++ b/topology/sql/sqlmm.sql.in.c @@ -2116,6 +2116,10 @@ BEGIN 'SQL/MM Spatial exception - null argument'; END IF; + -- Get topology id + SELECT id FROM topology.topology into topoid + WHERE name = atopology; + -- -- Check node existance -- @@ -2200,13 +2204,20 @@ BEGIN || 'next_left_edge, next_right_edge,' || 'left_face, right_face, geom) ' || 'VALUES(' - ||newedgeid||','||nodeid - ||','||oldedge.end_node - ||','||oldedge.next_left_edge - ||',-'||anedge - ||','||oldedge.left_face - ||','||oldedge.right_face - ||','||quote_literal(newedge2::text) + || newedgeid + || ',' || nodeid + || ',' || oldedge.end_node + || ',' || COALESCE( -- next_left_edge + NULLIF( + oldedge.next_left_edge, + -anedge + ), + -newedgeid + ) + || ',' || -anedge -- next_right_edge + || ',' || oldedge.left_face -- left_face + || ',' || oldedge.right_face -- right_face + || ',' || quote_literal(newedge2::text) -- geom ||')'; -- @@ -2216,6 +2227,7 @@ BEGIN || ' SET geom = ' || quote_literal(newedge1::text) || ',' || ' next_left_edge = ' || newedgeid + || ', abs_next_left_edge = ' || newedgeid || ',' || ' end_node = ' || nodeid || ' WHERE edge_id = ' || anedge; @@ -2230,18 +2242,16 @@ BEGIN || -newedgeid || ',' || ' abs_next_right_edge = ' || newedgeid - || ' WHERE next_right_edge = ' || -anedge; + || ' WHERE edge_id != ' || newedgeid + || ' AND next_right_edge = ' || -anedge; EXECUTE 'UPDATE ' || quote_ident(atopology) || '.edge_data SET ' || ' next_left_edge = ' || -newedgeid || ',' || ' abs_next_left_edge = ' || newedgeid - || ' WHERE next_left_edge = ' || -anedge; - - -- Get topology id - SELECT id FROM topology.topology into topoid - WHERE name = atopology; + || ' WHERE edge_id != ' || newedgeid + || ' AND next_left_edge = ' || -anedge; -- -- Update references in the Relation table. diff --git a/topology/test/Makefile b/topology/test/Makefile index 7f3b35ee7..1c0de33f4 100644 --- a/topology/test/Makefile +++ b/topology/test/Makefile @@ -38,6 +38,7 @@ TESTS = regress/legacy_validate.sql regress/legacy_predicate.sql \ regress/st_getfacegeometry.sql \ regress/st_getfaceedges.sql \ regress/st_modedgeheal.sql \ + regress/st_modedgesplit.sql \ regress/st_newedgeheal.sql \ regress/st_remedgenewface.sql \ regress/st_remedgemodface.sql \ diff --git a/topology/test/regress/st_modedgesplit.sql b/topology/test/regress/st_modedgesplit.sql new file mode 100644 index 000000000..94fc38a4d --- /dev/null +++ b/topology/test/regress/st_modedgesplit.sql @@ -0,0 +1,96 @@ + +\set VERBOSITY terse +set client_min_messages to ERROR; + +-- Import city_data +\i load_topology.sql + +-- Save max node id +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; +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 (there should be one split) + 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 + || ''|nl'' || e.next_left_edge + || ''|nr'' || e.next_right_edge + || ''|lf'' || e.left_face + || ''|rf'' || e.right_face + :: 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; + + 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'; + +END; +$$ LANGUAGE 'plpgsql'; +-- } + +-- Invalid calls +SELECT 'invalid', ST_ModEdgeSplit('city_data', 999, 'POINT(36 26, 38 30)'); +SELECT 'invalid', ST_ModEdgeSplit('city_data', 10, 'POINT(28 15)'); +SELECT 'invalid', ST_ModEdgeSplit('', 10, 'POINT(28 14)'); +SELECT 'invalid', ST_ModEdgeSplit(NULL, 10, 'POINT(28 14)'); +SELECT 'invalid', ST_ModEdgeSplit('city_data', NULL, 'POINT(28 14)'); +SELECT 'invalid', ST_ModEdgeSplit('city_data', 10, NULL); +SELECT 'invalid', ST_ModEdgeSplit('fake', 10, 'POINT(28 14)'); + +-- Non-isolated edge +SELECT 'noniso', ST_ModEdgeSplit('city_data', 10, 'POINT(28 14)'); +SELECT check_changes(); + +-- Isolated edge +SELECT 'iso', ST_ModEdgeSplit('city_data', 25, 'POINT(11 35)'); +SELECT check_changes(); + +-- Dangling on end point +SELECT 'dangling_end', ST_ModEdgeSplit('city_data', 3, 'POINT(25 32)'); +SELECT check_changes(); + +-- Dangling on start point +SELECT 'dangling_start', ST_ModEdgeSplit('city_data', 4, 'POINT(45 32)'); +SELECT check_changes(); + +-- Splitting closed edge +SELECT 'closed', ST_ModEdgeSplit('city_data', 1, 'POINT(3 38)'); +SELECT check_changes(); + + + +DROP FUNCTION check_changes(); +SELECT DropTopology('city_data'); diff --git a/topology/test/regress/st_modedgesplit_expected b/topology/test/regress/st_modedgesplit_expected new file mode 100644 index 000000000..7ca7a80e9 --- /dev/null +++ b/topology/test/regress/st_modedgesplit_expected @@ -0,0 +1,36 @@ +BEGIN +t +9 +22 +26 +COMMIT +max|node|22 +max|edge|26 +ERROR: geometry has too many points at character 53 +ERROR: SQL/MM Spatial exception - point not on edge +ERROR: zero-length delimited identifier at or near """" at character 15 +ERROR: SQL/MM Spatial exception - null argument +ERROR: SQL/MM Spatial exception - null argument +ERROR: SQL/MM Spatial exception - null argument +ERROR: schema "fake" does not exist at character 15 +noniso|23 +N|23||POINT(28 14) +E|10|sn13|en23|nl27|nr17|lf7|rf4 +E|27|sn23|en14|nl-20|nr-10|lf7|rf4 +iso|24 +N|24||POINT(11 35) +E|25|sn21|en24|nl28|nr25|lf1|rf1 +E|28|sn24|en22|nl-28|nr-25|lf1|rf1 +dangling_end|25 +N|25||POINT(25 32) +E|3|sn2|en25|nl29|nr2|lf2|rf2 +E|29|sn25|en3|nl-29|nr-3|lf2|rf2 +dangling_start|26 +N|26||POINT(45 32) +E|4|sn5|en26|nl30|nr4|lf0|rf0 +E|30|sn26|en6|nl-5|nr-4|lf0|rf0 +closed|27 +N|27||POINT(3 38) +E|1|sn1|en27|nl31|nr-31|lf1|rf0 +E|31|sn27|en1|nl1|nr-1|lf1|rf0 +Topology 'city_data' dropped -- 2.50.1