mirror of
https://git.osgeo.org/gitea/postgis/postgis
synced 2024-10-24 09:02:37 +00:00
Implement topology.ST_AddEdgeModFace. Includes regress test. [RT-SIGTA]
git-svn-id: http://svn.osgeo.org/postgis/trunk@7273 b70326c6-7e19-0410-871a-916f4a2858ee
This commit is contained in:
parent
636222efcd
commit
3ead9a536d
|
@ -2508,6 +2508,655 @@ $$
|
|||
LANGUAGE 'plpgsql' VOLATILE;
|
||||
--} ST_AddEdgeNewFaces
|
||||
|
||||
--{
|
||||
-- Topo-Geo and Topo-Net 3: Routine Details
|
||||
-- X.3.13
|
||||
--
|
||||
-- ST_AddEdgeModFace(atopology, anode, anothernode, acurve)
|
||||
--
|
||||
-- Not in the specs:
|
||||
-- * Reset containing_face for starting and ending point,
|
||||
-- as they stop being isolated nodes
|
||||
-- * Update references in the Relation table.
|
||||
--
|
||||
CREATE OR REPLACE FUNCTION topology.ST_AddEdgeModFace(atopology varchar, anode integer, anothernode integer, acurve geometry)
|
||||
RETURNS INTEGER AS
|
||||
$$
|
||||
DECLARE
|
||||
rec RECORD;
|
||||
rrec RECORD;
|
||||
i INTEGER;
|
||||
topoid INTEGER;
|
||||
az FLOAT8;
|
||||
span RECORD; -- start point analysis data
|
||||
epan RECORD; -- end point analysis data
|
||||
fan RECORD; -- face analisys
|
||||
newedge RECORD; -- informations about new edge
|
||||
sql TEXT;
|
||||
newfaces INTEGER[];
|
||||
newface INTEGER;
|
||||
do_add BOOLEAN;
|
||||
bounds GEOMETRY;
|
||||
p1 GEOMETRY;
|
||||
p2 GEOMETRY;
|
||||
BEGIN
|
||||
|
||||
--
|
||||
-- All args required
|
||||
--
|
||||
IF atopology IS NULL
|
||||
OR anode IS NULL
|
||||
OR anothernode IS NULL
|
||||
OR acurve IS NULL
|
||||
THEN
|
||||
RAISE EXCEPTION 'SQL/MM Spatial exception - null argument';
|
||||
END IF;
|
||||
|
||||
--
|
||||
-- Acurve must be a LINESTRING
|
||||
--
|
||||
IF substring(geometrytype(acurve), 1, 4) != 'LINE'
|
||||
THEN
|
||||
RAISE EXCEPTION 'SQL/MM Spatial exception - invalid curve';
|
||||
END IF;
|
||||
|
||||
--
|
||||
-- Curve must be simple
|
||||
--
|
||||
IF NOT ST_IsSimple(acurve) THEN
|
||||
RAISE EXCEPTION 'SQL/MM Spatial exception - curve not simple';
|
||||
END IF;
|
||||
|
||||
--
|
||||
-- Get topology id
|
||||
--
|
||||
BEGIN
|
||||
SELECT id FROM topology.topology
|
||||
INTO STRICT topoid WHERE name = atopology;
|
||||
EXCEPTION
|
||||
WHEN NO_DATA_FOUND THEN
|
||||
RAISE EXCEPTION 'SQL/MM Spatial exception - invalid topology name';
|
||||
END;
|
||||
|
||||
-- Initialize new edge info (will be filled up more later)
|
||||
SELECT anode as start_node, anothernode as end_node, acurve as geom,
|
||||
NULL::int as next_left_edge, NULL::int as next_right_edge,
|
||||
NULL::int as left_face, NULL::int as right_face, NULL::int as edge_id,
|
||||
NULL::int as prev_left_edge, NULL::int as prev_right_edge, -- convenience
|
||||
anode = anothernode as isclosed, -- convenience
|
||||
false as start_node_isolated, -- convenience
|
||||
false as end_node_isolated, -- convenience
|
||||
ST_RemoveRepeatedPoints(acurve) as cleangeom -- convenience
|
||||
INTO newedge;
|
||||
|
||||
-- Compute azimut of first edge end on start node
|
||||
SELECT null::int AS nextCW, null::int AS nextCCW,
|
||||
null::float8 AS minaz, null::float8 AS maxaz,
|
||||
false AS was_isolated,
|
||||
ST_Azimuth(ST_StartPoint(newedge.cleangeom),
|
||||
ST_PointN(newedge.cleangeom, 2)) AS myaz
|
||||
INTO span;
|
||||
IF span.myaz IS NULL THEN
|
||||
RAISE EXCEPTION 'Invalid edge (no two distinct vertices exist)';
|
||||
END IF;
|
||||
|
||||
-- Compute azimuth of last edge end on end node
|
||||
SELECT null::int AS nextCW, null::int AS nextCCW,
|
||||
null::float8 AS minaz, null::float8 AS maxaz,
|
||||
false AS was_isolated,
|
||||
ST_Azimuth(ST_EndPoint(newedge.cleangeom),
|
||||
ST_PointN(newedge.cleangeom,
|
||||
ST_NumPoints(newedge.cleangeom)-1)) AS myaz
|
||||
INTO epan;
|
||||
IF epan.myaz IS NULL THEN
|
||||
RAISE EXCEPTION 'Invalid edge (no two distinct vertices exist)';
|
||||
END IF;
|
||||
|
||||
|
||||
--
|
||||
-- Check endpoints existance, match with Curve geometry
|
||||
-- and get face information (if any)
|
||||
--
|
||||
i := 0;
|
||||
FOR rec IN EXECUTE 'SELECT node_id, '
|
||||
|| ' CASE WHEN node_id = ' || anode
|
||||
|| ' THEN 1 WHEN node_id = ' || anothernode
|
||||
|| ' THEN 0 END AS start, containing_face, geom FROM '
|
||||
|| quote_ident(atopology)
|
||||
|| '.node '
|
||||
|| ' WHERE node_id IN ( '
|
||||
|| anode || ',' || anothernode
|
||||
|| ')'
|
||||
LOOP
|
||||
IF rec.containing_face IS NOT NULL THEN
|
||||
RAISE DEBUG 'containing_face for node %:%',
|
||||
rec.node_id, rec.containing_face;
|
||||
IF newedge.left_face IS NULL THEN
|
||||
newedge.left_face := rec.containing_face;
|
||||
newedge.right_face := rec.containing_face;
|
||||
ELSE
|
||||
IF newedge.left_face != rec.containing_face THEN
|
||||
RAISE EXCEPTION
|
||||
'SQL/MM Spatial exception - geometry crosses an edge (endnodes in faces % and %)', newedge.left_face, rec.containing_face;
|
||||
END IF;
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
IF rec.start THEN
|
||||
IF NOT Equals(rec.geom, ST_StartPoint(acurve))
|
||||
THEN
|
||||
RAISE EXCEPTION
|
||||
'SQL/MM Spatial exception - start node not geometry start point.';
|
||||
END IF;
|
||||
ELSE
|
||||
IF NOT Equals(rec.geom, ST_EndPoint(acurve))
|
||||
THEN
|
||||
RAISE EXCEPTION
|
||||
'SQL/MM Spatial exception - end node not geometry end point.';
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
i := i + 1;
|
||||
END LOOP;
|
||||
|
||||
IF NOT newedge.isclosed THEN
|
||||
IF i < 2 THEN
|
||||
RAISE EXCEPTION
|
||||
'SQL/MM Spatial exception - non-existent node';
|
||||
END IF;
|
||||
ELSE
|
||||
IF i < 1 THEN
|
||||
RAISE EXCEPTION
|
||||
'SQL/MM Spatial exception - non-existent node';
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
--
|
||||
-- Check if this geometry crosses any node
|
||||
--
|
||||
FOR rec IN EXECUTE
|
||||
'SELECT node_id, ST_Relate(geom, '
|
||||
|| quote_literal(acurve::text) || '::geometry, 2) as relate FROM '
|
||||
|| quote_ident(atopology)
|
||||
|| '.node WHERE geom && '
|
||||
|| quote_literal(acurve::text)
|
||||
|| '::geometry'
|
||||
LOOP
|
||||
IF ST_RelateMatch(rec.relate, 'T********') THEN
|
||||
RAISE EXCEPTION 'SQL/MM Spatial exception - geometry crosses a node';
|
||||
END IF;
|
||||
END LOOP;
|
||||
|
||||
--
|
||||
-- Check if this geometry has any interaction with any existing edge
|
||||
--
|
||||
FOR rec IN EXECUTE 'SELECT edge_id, ST_Relate(geom,'
|
||||
|| quote_literal(acurve::text)
|
||||
|| '::geometry, 2) as im FROM '
|
||||
|| quote_ident(atopology)
|
||||
|| '.edge_data WHERE geom && '
|
||||
|| quote_literal(acurve::text) || '::geometry'
|
||||
LOOP
|
||||
|
||||
--RAISE DEBUG 'IM=%',rec.im;
|
||||
|
||||
IF ST_RelateMatch(rec.im, 'F********') THEN
|
||||
CONTINUE; -- no interior intersection
|
||||
END IF;
|
||||
|
||||
IF ST_RelateMatch(rec.im, '1FFF*FFF2') THEN
|
||||
RAISE EXCEPTION
|
||||
'SQL/MM Spatial exception - coincident edge';
|
||||
END IF;
|
||||
|
||||
-- NOT IN THE SPECS: geometry touches an edge
|
||||
IF ST_RelateMatch(rec.im, '1********') THEN
|
||||
RAISE EXCEPTION
|
||||
'Spatial exception - geometry intersects edge %', rec.edge_id;
|
||||
END IF;
|
||||
|
||||
IF ST_RelateMatch(rec.im, 'T********') THEN
|
||||
RAISE EXCEPTION
|
||||
'SQL/MM Spatial exception - geometry crosses an edge';
|
||||
END IF;
|
||||
|
||||
END LOOP;
|
||||
|
||||
---------------------------------------------------------------
|
||||
--
|
||||
-- All checks passed, time to prepare the new edge
|
||||
--
|
||||
---------------------------------------------------------------
|
||||
|
||||
EXECUTE 'SELECT nextval(' || quote_literal(
|
||||
quote_ident(atopology) || '.edge_data_edge_id_seq') || ')'
|
||||
INTO STRICT newedge.edge_id;
|
||||
|
||||
|
||||
-- Find links on start node -- {
|
||||
|
||||
RAISE DEBUG 'My start-segment azimuth: %', span.myaz;
|
||||
|
||||
sql :=
|
||||
'SELECT edge_id, -1 AS end_node, start_node, left_face, right_face, '
|
||||
|| 'ST_RemoveRepeatedPoints(geom) as geom FROM '
|
||||
|| quote_ident(atopology)
|
||||
|| '.edge_data WHERE start_node = ' || anode
|
||||
|| ' UNION SELECT edge_id, end_node, -1, left_face, right_face, '
|
||||
|| 'ST_RemoveRepeatedPoints(geom) FROM '
|
||||
|| quote_ident(atopology)
|
||||
|| '.edge_data WHERE end_node = ' || anode;
|
||||
IF newedge.isclosed THEN
|
||||
sql := sql || ' UNION SELECT '
|
||||
|| newedge.edge_id || ',' || newedge.end_node
|
||||
|| ',-1,0,0,' -- pretend we start elsewhere
|
||||
|| quote_literal(newedge.cleangeom::text);
|
||||
END IF;
|
||||
i := 0;
|
||||
FOR rec IN EXECUTE sql
|
||||
LOOP -- incident edges {
|
||||
|
||||
i := i + 1;
|
||||
|
||||
IF rec.start_node = anode THEN
|
||||
--
|
||||
-- Edge starts at our node, we compute
|
||||
-- azimuth from node to its second point
|
||||
--
|
||||
az := ST_Azimuth(ST_StartPoint(rec.geom), ST_PointN(rec.geom, 2));
|
||||
|
||||
ELSE
|
||||
--
|
||||
-- Edge ends at our node, we compute
|
||||
-- azimuth from node to its second-last point
|
||||
--
|
||||
az := ST_Azimuth(ST_EndPoint(rec.geom),
|
||||
ST_PointN(rec.geom, ST_NumPoints(rec.geom)-1));
|
||||
rec.edge_id := -rec.edge_id;
|
||||
|
||||
END IF;
|
||||
|
||||
IF az IS NULL THEN
|
||||
RAISE EXCEPTION 'Invalid edge % found (no two distinct nodes exist)',
|
||||
rec.edge_id;
|
||||
END IF;
|
||||
|
||||
RAISE DEBUG 'Edge % - az % (%) - fl:% fr:%',
|
||||
rec.edge_id, az, az - span.myaz, rec.left_face, rec.right_face;
|
||||
|
||||
az = az - span.myaz;
|
||||
IF az < 0 THEN
|
||||
az := az + 2*PI();
|
||||
END IF;
|
||||
|
||||
-- RAISE DEBUG ' normalized az %', az;
|
||||
|
||||
IF span.maxaz IS NULL OR az > span.maxaz THEN
|
||||
span.maxaz := az;
|
||||
span.nextCCW := rec.edge_id;
|
||||
IF abs(rec.edge_id) != newedge.edge_id THEN
|
||||
IF rec.edge_id < 0 THEN
|
||||
-- TODO: check for mismatch ?
|
||||
newedge.left_face := rec.left_face;
|
||||
ELSE
|
||||
-- TODO: check for mismatch ?
|
||||
newedge.left_face := rec.right_face;
|
||||
END IF;
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
IF span.minaz IS NULL OR az < span.minaz THEN
|
||||
span.minaz := az;
|
||||
span.nextCW := rec.edge_id;
|
||||
IF abs(rec.edge_id) != newedge.edge_id THEN
|
||||
IF rec.edge_id < 0 THEN
|
||||
-- TODO: check for mismatch ?
|
||||
newedge.right_face := rec.right_face;
|
||||
ELSE
|
||||
-- TODO: check for mismatch ?
|
||||
newedge.right_face := rec.left_face;
|
||||
END IF;
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
--RAISE DEBUG 'Closest edges: CW:%(%) CCW:%(%)', span.nextCW, span.minaz, span.nextCCW, span.maxaz;
|
||||
|
||||
END LOOP; -- incident edges }
|
||||
|
||||
RAISE DEBUG 'span ROW_COUNT: %', i;
|
||||
IF newedge.isclosed THEN
|
||||
IF i < 2 THEN span.was_isolated = true; END IF;
|
||||
ELSE
|
||||
IF i < 1 THEN span.was_isolated = true; END IF;
|
||||
END IF;
|
||||
|
||||
IF span.nextCW IS NULL THEN
|
||||
-- This happens if the destination node is isolated
|
||||
newedge.next_right_edge := newedge.edge_id;
|
||||
newedge.prev_left_edge := -newedge.edge_id;
|
||||
ELSE
|
||||
newedge.next_right_edge := span.nextCW;
|
||||
newedge.prev_left_edge := -span.nextCCW;
|
||||
END IF;
|
||||
|
||||
RAISE DEBUG 'edge:%', newedge.edge_id;
|
||||
RAISE DEBUG ' left:%, next:%, prev:%',
|
||||
newedge.left_face, newedge.next_left_edge, newedge.prev_left_edge;
|
||||
RAISE DEBUG ' right:%, next:%, prev:%',
|
||||
newedge.right_face, newedge.next_right_edge, newedge.prev_right_edge;
|
||||
|
||||
-- } start_node analysis
|
||||
|
||||
|
||||
-- Find links on end_node {
|
||||
|
||||
RAISE DEBUG 'My end-segment azimuth: %', epan.myaz;
|
||||
|
||||
sql :=
|
||||
'SELECT edge_id, -1 as end_node, start_node, left_face, right_face, '
|
||||
|| 'ST_RemoveRepeatedPoints(geom) as geom FROM '
|
||||
|| quote_ident(atopology)
|
||||
|| '.edge_data WHERE start_node = ' || anothernode
|
||||
|| 'UNION SELECT edge_id, end_node, -1, left_face, right_face, '
|
||||
|| 'ST_RemoveRepeatedPoints(geom) FROM '
|
||||
|| quote_ident(atopology)
|
||||
|| '.edge_data WHERE end_node = ' || anothernode;
|
||||
IF newedge.isclosed THEN
|
||||
sql := sql || ' UNION SELECT '
|
||||
|| newedge.edge_id || ',' || -1 -- pretend we end elsewhere
|
||||
|| ',' || newedge.start_node || ',0,0,'
|
||||
|| quote_literal(newedge.cleangeom::text);
|
||||
END IF;
|
||||
i := 0;
|
||||
FOR rec IN EXECUTE sql
|
||||
LOOP -- incident edges {
|
||||
|
||||
i := i + 1;
|
||||
|
||||
IF rec.start_node = anothernode THEN
|
||||
--
|
||||
-- Edge starts at our node, we compute
|
||||
-- azimuth from node to its second point
|
||||
--
|
||||
az := ST_Azimuth(ST_StartPoint(rec.geom),
|
||||
ST_PointN(rec.geom, 2));
|
||||
|
||||
ELSE
|
||||
--
|
||||
-- Edge ends at our node, we compute
|
||||
-- azimuth from node to its second-last point
|
||||
--
|
||||
az := ST_Azimuth(ST_EndPoint(rec.geom),
|
||||
ST_PointN(rec.geom, ST_NumPoints(rec.geom)-1));
|
||||
rec.edge_id := -rec.edge_id;
|
||||
|
||||
END IF;
|
||||
|
||||
RAISE DEBUG 'Edge % - az % (%)', rec.edge_id, az, az - epan.myaz;
|
||||
|
||||
az := az - epan.myaz;
|
||||
IF az < 0 THEN
|
||||
az := az + 2*PI();
|
||||
END IF;
|
||||
|
||||
-- RAISE DEBUG ' normalized az %', az;
|
||||
|
||||
IF epan.maxaz IS NULL OR az > epan.maxaz THEN
|
||||
epan.maxaz := az;
|
||||
epan.nextCCW := rec.edge_id;
|
||||
IF abs(rec.edge_id) != newedge.edge_id THEN
|
||||
IF rec.edge_id < 0 THEN
|
||||
-- TODO: check for mismatch ?
|
||||
newedge.right_face := rec.left_face;
|
||||
ELSE
|
||||
-- TODO: check for mismatch ?
|
||||
newedge.right_face := rec.right_face;
|
||||
END IF;
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
IF epan.minaz IS NULL OR az < epan.minaz THEN
|
||||
epan.minaz := az;
|
||||
epan.nextCW := rec.edge_id;
|
||||
IF abs(rec.edge_id) != newedge.edge_id THEN
|
||||
IF rec.edge_id < 0 THEN
|
||||
-- TODO: check for mismatch ?
|
||||
newedge.left_face := rec.right_face;
|
||||
ELSE
|
||||
-- TODO: check for mismatch ?
|
||||
newedge.left_face := rec.left_face;
|
||||
END IF;
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
--RAISE DEBUG 'Closest edges: CW:%(%) CCW:%(%)', epan.nextCW, epan.minaz, epan.nextCCW, epan.maxaz;
|
||||
|
||||
END LOOP; -- incident edges }
|
||||
|
||||
RAISE DEBUG 'epan ROW_COUNT: %', i;
|
||||
IF newedge.isclosed THEN
|
||||
IF i < 2 THEN epan.was_isolated = true; END IF;
|
||||
ELSE
|
||||
IF i < 1 THEN epan.was_isolated = true; END IF;
|
||||
END IF;
|
||||
|
||||
IF epan.nextCW IS NULL THEN
|
||||
-- This happens if the destination node is isolated
|
||||
newedge.next_left_edge := -newedge.edge_id;
|
||||
newedge.prev_right_edge := newedge.edge_id;
|
||||
ELSE
|
||||
newedge.next_left_edge := epan.nextCW;
|
||||
newedge.prev_right_edge := -epan.nextCCW;
|
||||
END IF;
|
||||
|
||||
-- } end_node analysis
|
||||
|
||||
RAISE DEBUG 'edge:%', newedge.edge_id;
|
||||
RAISE DEBUG ' left:%, next:%, prev:%',
|
||||
newedge.left_face, newedge.next_left_edge, newedge.prev_left_edge;
|
||||
RAISE DEBUG ' right:%, next:%, prev:%',
|
||||
newedge.right_face, newedge.next_right_edge, newedge.prev_right_edge;
|
||||
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- If we don't have faces setup by now we must have encountered
|
||||
-- a malformed topology (no containing_face on isolated nodes, no
|
||||
-- left/right faces on adjacent edges or mismatching values)
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
IF newedge.left_face != newedge.right_face THEN
|
||||
RAISE EXCEPTION 'Left(%)/right(%) faces mismatch: invalid topology ?',
|
||||
newedge.left_face, newedge.right_face;
|
||||
END IF;
|
||||
IF newedge.left_face IS NULL THEN
|
||||
RAISE EXCEPTION 'Could not derive edge face from linked primitives: invalid topology ?';
|
||||
END IF;
|
||||
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- Polygonize the current edges (to see later if the addition
|
||||
-- of the new one created another ring)
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
|
||||
SELECT null::geometry as post, null::geometry as pre INTO fan;
|
||||
|
||||
EXECUTE
|
||||
'SELECT ST_Polygonize(geom) FROM '
|
||||
|| quote_ident(atopology) || '.edge_data WHERE left_face = '
|
||||
|| newedge.left_face || ' OR right_face = ' || newedge.right_face
|
||||
INTO STRICT fan.pre;
|
||||
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- Insert the new edge, and update all linking
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
|
||||
-- Insert the new edge with what we have so far
|
||||
EXECUTE 'INSERT INTO ' || quote_ident(atopology)
|
||||
|| '.edge VALUES(' || newedge.edge_id
|
||||
|| ',' || newedge.start_node
|
||||
|| ',' || newedge.end_node
|
||||
|| ',' || newedge.next_left_edge
|
||||
|| ',' || newedge.next_right_edge
|
||||
|| ',' || newedge.left_face
|
||||
|| ',' || newedge.right_face
|
||||
|| ',' || quote_literal(newedge.geom::geometry::text)
|
||||
|| ')';
|
||||
|
||||
-- Link prev_left_edge to us
|
||||
-- (if it's not us already)
|
||||
IF abs(newedge.prev_left_edge) != newedge.edge_id THEN
|
||||
IF newedge.prev_left_edge > 0 THEN
|
||||
-- its next_left_edge is us
|
||||
EXECUTE 'UPDATE ' || quote_ident(atopology)
|
||||
|| '.edge_data SET next_left_edge = '
|
||||
|| newedge.edge_id
|
||||
|| ', abs_next_left_edge = '
|
||||
|| newedge.edge_id
|
||||
|| ' WHERE edge_id = '
|
||||
|| newedge.prev_left_edge;
|
||||
ELSE
|
||||
-- its next_right_edge is us
|
||||
EXECUTE 'UPDATE ' || quote_ident(atopology)
|
||||
|| '.edge_data SET next_right_edge = '
|
||||
|| newedge.edge_id
|
||||
|| ', abs_next_right_edge = '
|
||||
|| newedge.edge_id
|
||||
|| ' WHERE edge_id = '
|
||||
|| -newedge.prev_left_edge;
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
-- Link prev_right_edge to us
|
||||
-- (if it's not us already)
|
||||
IF abs(newedge.prev_right_edge) != newedge.edge_id THEN
|
||||
IF newedge.prev_right_edge > 0 THEN
|
||||
-- its next_left_edge is -us
|
||||
EXECUTE 'UPDATE ' || quote_ident(atopology)
|
||||
|| '.edge_data SET next_left_edge = '
|
||||
|| -newedge.edge_id
|
||||
|| ', abs_next_left_edge = '
|
||||
|| newedge.edge_id
|
||||
|| ' WHERE edge_id = '
|
||||
|| newedge.prev_right_edge;
|
||||
ELSE
|
||||
-- its next_right_edge is -us
|
||||
EXECUTE 'UPDATE ' || quote_ident(atopology)
|
||||
|| '.edge_data SET next_right_edge = '
|
||||
|| -newedge.edge_id
|
||||
|| ', abs_next_right_edge = '
|
||||
|| newedge.edge_id
|
||||
|| ' WHERE edge_id = '
|
||||
|| -newedge.prev_right_edge;
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
-- NOT IN THE SPECS...
|
||||
-- set containing_face = null for start_node and end_node
|
||||
-- if they where isolated
|
||||
IF span.was_isolated OR epan.was_isolated THEN
|
||||
EXECUTE 'UPDATE ' || quote_ident(atopology)
|
||||
|| '.node SET containing_face = null WHERE node_id IN ('
|
||||
|| anode || ',' || anothernode || ')';
|
||||
END IF;
|
||||
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- Polygonize the new edges and see if the addition created a new ring
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
|
||||
EXECUTE 'SELECT ST_Polygonize(geom) FROM '
|
||||
|| quote_ident(atopology) || '.edge_data WHERE left_face = '
|
||||
|| newedge.left_face || ' OR right_face = ' || newedge.right_face
|
||||
INTO STRICT fan.post;
|
||||
|
||||
IF ST_NumGeometries(fan.pre) = ST_NumGeometries(fan.post) THEN
|
||||
-- No splits, all done
|
||||
RETURN newedge.edge_id;
|
||||
END IF;
|
||||
|
||||
RAISE NOTICE 'ST_AddEdgeModFace: edge % splitted face %',
|
||||
newedge.edge_id, newedge.left_face;
|
||||
|
||||
-- Call topology.AddFace for every face containing the new edge
|
||||
p1 = ST_StartPoint(newedge.cleangeom);
|
||||
p2 = ST_PointN(newedge.cleangeom, 2);
|
||||
FOR rec IN SELECT geom FROM ST_Dump(fan.post)
|
||||
WHERE ST_Contains(
|
||||
ST_Boundary(geom),
|
||||
ST_MakeLine(p1, p2)
|
||||
)
|
||||
LOOP -- {
|
||||
|
||||
-- NOTE: the only difference with ST_AddEdgeNewFace here is
|
||||
-- that we want to retain the face on the right side of
|
||||
-- the new edge
|
||||
--
|
||||
IF newedge.left_face != 0 THEN -- {
|
||||
|
||||
RAISE NOTICE 'Checking face %', ST_AsText(rec.geom);
|
||||
|
||||
-- Skip this if our edge is on the right side
|
||||
IF ST_IsEmpty(ST_GeometryN(
|
||||
ST_SharedPaths(ST_Boundary(ST_ForceRHR(rec.geom)),
|
||||
ST_MakeLine(p1, p2)), 2))
|
||||
THEN
|
||||
-- We keep this face, but update its MBR
|
||||
sql := 'UPDATE ' || quote_ident(atopology)
|
||||
|| '.face set mbr = ' || quote_literal(ST_Envelope(rec.geom)::text)
|
||||
|| ' WHERE face_id = ' || newedge.left_face;
|
||||
EXECUTE sql;
|
||||
CONTINUE;
|
||||
END IF;
|
||||
|
||||
END IF; -- }
|
||||
|
||||
RAISE NOTICE 'Adding face %', ST_AsText(rec.geom);
|
||||
sql :=
|
||||
'SELECT topology.AddFace(' || quote_literal(atopology)
|
||||
|| ', ' || quote_literal(rec.geom::text) || ', true)';
|
||||
EXECUTE sql INTO newface;
|
||||
|
||||
END LOOP; --}
|
||||
RAISE DEBUG 'Added face: %', newface;
|
||||
|
||||
IF newedge.left_face != 0 THEN -- {
|
||||
|
||||
-- NOT IN THE SPECS:
|
||||
-- update TopoGeometry compositions to add newface
|
||||
sql := 'SELECT r.topogeo_id, r.layer_id FROM '
|
||||
|| quote_ident(atopology)
|
||||
|| '.relation r, topology.layer l '
|
||||
|| ' WHERE l.topology_id = ' || topoid
|
||||
|| ' AND l.level = 0 '
|
||||
|| ' AND l.layer_id = r.layer_id '
|
||||
|| ' AND r.element_id = ' || newedge.left_face
|
||||
|| ' AND r.element_type = 3 ';
|
||||
--RAISE DEBUG 'SQL: %', sql;
|
||||
FOR rec IN EXECUTE sql
|
||||
LOOP
|
||||
RAISE DEBUG 'TopoGeometry % in layer % contained the face being split (%) - updating to contain also new face %', rec.topogeo_id, rec.layer_id, newedge.left_face, newface;
|
||||
|
||||
-- Add reference to the other face
|
||||
sql := 'INSERT INTO ' || quote_ident(atopology)
|
||||
|| '.relation VALUES( ' || rec.topogeo_id
|
||||
|| ',' || rec.layer_id || ',' || newface || ', 3)';
|
||||
--RAISE DEBUG 'SQL: %', sql;
|
||||
EXECUTE sql;
|
||||
|
||||
END LOOP;
|
||||
|
||||
END IF; -- }
|
||||
|
||||
RETURN newedge.edge_id;
|
||||
END
|
||||
$$
|
||||
LANGUAGE 'plpgsql' VOLATILE;
|
||||
--} ST_AddEdgeModFace
|
||||
|
||||
--{
|
||||
-- Topo-Geo and Topo-Net 3: Routine Details
|
||||
-- X.3.17
|
||||
|
|
|
@ -30,6 +30,7 @@ TESTS = regress/legacy_validate.sql regress/legacy_predicate.sql \
|
|||
regress/polygonize.sql \
|
||||
regress/st_addisoedge.sql \
|
||||
regress/st_addisonode.sql \
|
||||
regress/st_addedgemodface.sql \
|
||||
regress/st_addedgenewfaces.sql \
|
||||
regress/st_changeedgegeom.sql \
|
||||
regress/st_getfacegeometry.sql \
|
||||
|
|
394
topology/test/regress/st_addedgemodface.sql
Normal file
394
topology/test/regress/st_addedgemodface.sql
Normal file
|
@ -0,0 +1,394 @@
|
|||
set client_min_messages to ERROR;
|
||||
|
||||
\i load_topology.sql
|
||||
|
||||
-- Endpoint / node mismatch
|
||||
SELECT topology.ST_AddEdgeModFace('city_data', 7, 6,
|
||||
'LINESTRING(36 38,57 33)');
|
||||
SELECT topology.ST_AddEdgeModFace('city_data', 5, 7,
|
||||
'LINESTRING(36 38,57 33)');
|
||||
|
||||
-- Crosses a node
|
||||
SELECT topology.ST_AddEdgeModFace('city_data', 5, 6,
|
||||
'LINESTRING(36 38, 41 40, 57 33)');
|
||||
|
||||
-- Non-existent node
|
||||
SELECT topology.ST_AddEdgeModFace('city_data', 5, 60000,
|
||||
'LINESTRING(36 38,57 33)');
|
||||
SELECT topology.ST_AddEdgeModFace('city_data', 60000, 6,
|
||||
'LINESTRING(36 38,57 33)');
|
||||
|
||||
-- Non-simple curve
|
||||
SELECT topology.ST_AddEdgeModFace('city_data', 5, 5,
|
||||
'LINESTRING(36 38, 40 50, 36 38)');
|
||||
|
||||
-- Collapsed curve
|
||||
SELECT topology.ST_AddEdgeModFace('city_data', 5, 5,
|
||||
'LINESTRING(36 38, 36 38, 36 38)');
|
||||
|
||||
-- Empty curve
|
||||
SELECT topology.ST_AddEdgeModFace('city_data', 5, 5,
|
||||
'LINESTRING EMPTY');
|
||||
|
||||
-- Coincident edge
|
||||
SELECT topology.ST_AddEdgeModFace('city_data', 18, 19,
|
||||
'LINESTRING(35 22,47 22)');
|
||||
|
||||
-- Crosses an edge
|
||||
SELECT topology.ST_AddEdgeModFace('city_data', 5, 6,
|
||||
'LINESTRING(36 38, 40 50, 57 33)');
|
||||
|
||||
-- Touches an existing edge
|
||||
SELECT 'O', topology.ST_AddEdgeModFace('city_data', 5, 6,
|
||||
'LINESTRING(36 38,45 32,57 33)');
|
||||
|
||||
-- Shares a portion of an existing edge
|
||||
SELECT 'O', topology.ST_AddEdgeModFace('city_data', 5, 6,
|
||||
'LINESTRING(36 38,38 35,57 33)');
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Define some features
|
||||
---------------------------------------------------------------------
|
||||
|
||||
CREATE TABLE city_data.fp(id varchar);
|
||||
SELECT 'L' || topology.AddTopoGeometryColumn('city_data',
|
||||
'city_data', 'fp', 'g', 'POLYGON');
|
||||
|
||||
-- Feature composed by face 3 and face 4
|
||||
INSERT INTO city_data.fp VALUES ('F3,F4',
|
||||
topology.CreateTopoGeom('city_data', 3, 1, '{{3,3},{4,3}}'));
|
||||
|
||||
CREATE TABLE city_data.fc(id varchar);
|
||||
SELECT 'L' || topology.AddTopoGeometryColumn('city_data',
|
||||
'city_data', 'fc', 'g', 'COLLECTION');
|
||||
|
||||
-- Feature composed by face 5 and node 4
|
||||
INSERT INTO city_data.fc VALUES ('F5,N4',
|
||||
topology.CreateTopoGeom('city_data', 4, 2, '{{5,3},{4,1}}'));
|
||||
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Now add some edges splitting faces...
|
||||
---------------------------------------------------------------------
|
||||
|
||||
--
|
||||
-- start node has:
|
||||
-- outward edge on the left face
|
||||
-- inward edge on the right face
|
||||
-- end node has:
|
||||
-- inward edge on the left face
|
||||
-- inward edge on the right face
|
||||
--
|
||||
SELECT 1 as id, topology.st_addedgemodface('city_data', 14, 18,
|
||||
'LINESTRING(21 14, 35 22)') as edge_id INTO newedge;
|
||||
SELECT 'T1', 'E'||edge_id, next_left_edge, next_right_edge,
|
||||
left_face, right_face FROM
|
||||
city_data.edge WHERE edge_id IN (19, 7, 17, 10,
|
||||
( SELECT edge_id FROM newedge WHERE id = 1 ) )
|
||||
ORDER BY edge_id;
|
||||
|
||||
--
|
||||
-- start node has:
|
||||
-- inward edge on the left face
|
||||
-- outward edge on the right face
|
||||
-- end node has:
|
||||
-- inward edge on the left face
|
||||
-- outward edge on the right face
|
||||
--
|
||||
INSERT INTO newedge SELECT 2, topology.st_addedgemodface('city_data',
|
||||
12, 18, 'LINESTRING(47 14, 35 22)');
|
||||
SELECT 'T2', 'E'||edge_id, next_left_edge, next_right_edge,
|
||||
left_face, right_face FROM
|
||||
city_data.edge WHERE edge_id IN (17, 8, 15, 11,
|
||||
( SELECT edge_id FROM newedge WHERE id = 2 ) )
|
||||
ORDER BY edge_id;
|
||||
|
||||
--
|
||||
-- start node has:
|
||||
-- inward edge on the left face
|
||||
-- inward edge on the right face
|
||||
-- end node has:
|
||||
-- outward edge on the left face
|
||||
-- outward edge on the right face
|
||||
--
|
||||
INSERT INTO newedge SELECT 3, topology.st_addedgemodface('city_data',
|
||||
12, 10, 'LINESTRING(47 14, 35 6)');
|
||||
SELECT 'T3', 'E'||edge_id, next_left_edge, next_right_edge,
|
||||
left_face, right_face FROM
|
||||
city_data.edge WHERE edge_id IN (11, 16, 14, 18,
|
||||
( SELECT edge_id FROM newedge WHERE id = 3 ) )
|
||||
ORDER BY edge_id;
|
||||
|
||||
--
|
||||
-- start node has:
|
||||
-- outward edge on the left face
|
||||
-- outward edge on the right face
|
||||
-- end node has:
|
||||
-- outward edge on the left face
|
||||
-- inward edge on the right face
|
||||
--
|
||||
INSERT INTO newedge SELECT 4, topology.st_addedgemodface('city_data',
|
||||
9, 13, 'LINESTRING(21 6, 35 14)');
|
||||
SELECT 'T4', 'E'||edge_id, next_left_edge, next_right_edge,
|
||||
left_face, right_face FROM
|
||||
city_data.edge WHERE edge_id IN (20, 10, 18, 13,
|
||||
( SELECT edge_id FROM newedge WHERE id = 4 ) )
|
||||
ORDER BY edge_id;
|
||||
|
||||
--
|
||||
-- Same edge on start and end node, for left face, swapped direction
|
||||
--
|
||||
INSERT INTO newedge SELECT 5, topology.st_addedgemodface('city_data',
|
||||
14, 9, 'LINESTRING(21 14, 19 10, 21 6)');
|
||||
SELECT 'T5', 'E'||edge_id, next_left_edge, next_right_edge,
|
||||
left_face, right_face FROM
|
||||
city_data.edge WHERE edge_id IN (9, 12, 20,
|
||||
( SELECT edge_id FROM newedge WHERE id = 5 ) )
|
||||
ORDER BY edge_id;
|
||||
|
||||
--
|
||||
-- Same edge on start and end node, for left face, same direction
|
||||
--
|
||||
INSERT INTO newedge SELECT 6, topology.st_addedgemodface('city_data',
|
||||
8, 15, 'LINESTRING(9 6, 11 10, 9 14)');
|
||||
SELECT 'T6', 'E'||edge_id, next_left_edge, next_right_edge,
|
||||
left_face, right_face FROM
|
||||
city_data.edge WHERE edge_id IN (9, 12, 22,
|
||||
( SELECT edge_id FROM newedge WHERE id = 6 ) )
|
||||
ORDER BY edge_id;
|
||||
|
||||
--
|
||||
-- Same edge on start and end node, for right face, swapped direction
|
||||
--
|
||||
INSERT INTO newedge SELECT 7, topology.st_addedgemodface('city_data',
|
||||
17, 16, 'LINESTRING(21 22, 15 20, 9 22)');
|
||||
SELECT 'T7', 'E'||edge_id, next_left_edge, next_right_edge,
|
||||
left_face, right_face FROM
|
||||
city_data.edge WHERE edge_id IN (21, 6, 19,
|
||||
( SELECT edge_id FROM newedge WHERE id = 7 ) )
|
||||
ORDER BY edge_id;
|
||||
|
||||
--
|
||||
-- Same edge on start and end node, for right face, same direction
|
||||
--
|
||||
INSERT INTO newedge SELECT 8, topology.st_addedgemodface('city_data',
|
||||
15, 14, 'LINESTRING(9 14, 15 16, 21 14)');
|
||||
SELECT 'T8', 'E'||edge_id, next_left_edge, next_right_edge,
|
||||
left_face, right_face FROM
|
||||
city_data.edge WHERE edge_id IN (9, 21, 19,
|
||||
( SELECT edge_id FROM newedge WHERE id = 8 ) )
|
||||
ORDER BY edge_id;
|
||||
|
||||
--
|
||||
-- Closed edge, counterclockwise, in universe face, next right
|
||||
--
|
||||
INSERT INTO newedge SELECT 9, topology.st_addedgemodface('city_data',
|
||||
9, 9, 'LINESTRING(21 6, 18 0, 24 0, 21 6)');
|
||||
SELECT 'T9', 'E'||edge_id, next_left_edge, next_right_edge,
|
||||
left_face, right_face FROM
|
||||
city_data.edge WHERE edge_id IN (12, 13,
|
||||
( SELECT edge_id FROM newedge WHERE id = 9 ) )
|
||||
ORDER BY edge_id;
|
||||
|
||||
--
|
||||
-- Closed edge, clockwise, in universe face, next right
|
||||
--
|
||||
INSERT INTO newedge SELECT 10, topology.st_addedgemodface('city_data',
|
||||
10, 10, 'LINESTRING(35 6, 38 0, 32 0, 35 6)');
|
||||
SELECT 'T10', 'E'||edge_id, next_left_edge, next_right_edge,
|
||||
left_face, right_face FROM
|
||||
city_data.edge WHERE edge_id IN (13, 14,
|
||||
( SELECT edge_id FROM newedge WHERE id = 10 ) )
|
||||
ORDER BY edge_id;
|
||||
|
||||
--
|
||||
-- Closed edge, clockwise, in universe face, next left
|
||||
--
|
||||
INSERT INTO newedge SELECT 11, topology.st_addedgemodface('city_data',
|
||||
15, 15, 'LINESTRING(9 14, 3 11, 3 17, 9 14)');
|
||||
SELECT 'T11', 'E'||edge_id, next_left_edge, next_right_edge,
|
||||
left_face, right_face FROM
|
||||
city_data.edge WHERE edge_id IN (21, 22,
|
||||
( SELECT edge_id FROM newedge WHERE id = 11 ) )
|
||||
ORDER BY edge_id;
|
||||
|
||||
--
|
||||
-- Closed edge, clockwise, in universe face, against closed edge
|
||||
--
|
||||
INSERT INTO newedge SELECT 12, topology.st_addedgemodface('city_data',
|
||||
1, 1, 'LINESTRING(8 30, 5 27, 11 27, 8 30)');
|
||||
SELECT 'T12', 'E'||edge_id, next_left_edge, next_right_edge,
|
||||
left_face, right_face FROM
|
||||
city_data.edge WHERE edge_id IN (1,
|
||||
( SELECT edge_id FROM newedge WHERE id = 12 ) )
|
||||
ORDER BY edge_id;
|
||||
|
||||
--
|
||||
-- Closed edge, counterclockwise, in universe face, against closed edge
|
||||
--
|
||||
INSERT INTO newedge SELECT 13, topology.st_addedgemodface('city_data',
|
||||
2, 2, 'LINESTRING(25 30, 28 27, 22 27, 25 30)');
|
||||
SELECT 'T13', 'E'||edge_id, next_left_edge, next_right_edge,
|
||||
left_face, right_face FROM
|
||||
city_data.edge WHERE edge_id IN (2,
|
||||
( SELECT edge_id FROM newedge WHERE id = 13 ) )
|
||||
ORDER BY edge_id;
|
||||
|
||||
--
|
||||
-- Dangling edge, ending into closed edge endpoint
|
||||
--
|
||||
INSERT INTO city_data.node(geom, containing_face)
|
||||
VALUES ('POINT(9 33)', 1); -- N23
|
||||
INSERT INTO newedge SELECT 14, topology.st_addedgemodface('city_data',
|
||||
23, 1, 'LINESTRING(9 33, 8 30)');
|
||||
SELECT 'T14', 'E'||edge_id, next_left_edge, next_right_edge,
|
||||
left_face, right_face FROM
|
||||
city_data.edge WHERE edge_id IN (1,
|
||||
( SELECT edge_id FROM newedge WHERE id = 14 ) )
|
||||
ORDER BY edge_id;
|
||||
SELECT 'N' || node_id, containing_face
|
||||
FROM city_data.node WHERE node_id = 23;
|
||||
|
||||
--
|
||||
-- Dangling edge, originating from closed edge endpoint
|
||||
--
|
||||
INSERT INTO city_data.node(geom, containing_face)
|
||||
VALUES ('POINT(12 28)', 0); -- N24
|
||||
INSERT INTO newedge SELECT 15, topology.st_addedgemodface('city_data',
|
||||
1, 24, 'LINESTRING(8 30, 12 28)');
|
||||
SELECT 'T15', 'E'||edge_id, next_left_edge, next_right_edge,
|
||||
left_face, right_face FROM
|
||||
city_data.edge WHERE edge_id IN (38, 1,
|
||||
( SELECT edge_id FROM newedge WHERE id = 15 ) )
|
||||
ORDER BY edge_id;
|
||||
SELECT 'N' || node_id, containing_face
|
||||
FROM city_data.node WHERE node_id = 24;
|
||||
|
||||
--
|
||||
-- Closed edge on isolated node
|
||||
--
|
||||
INSERT INTO newedge SELECT 16, topology.st_addedgemodface('city_data',
|
||||
4, 4, 'LINESTRING(20 37, 23 37, 20 34, 20 37)');
|
||||
SELECT 'T16', 'E'||edge_id, next_left_edge, next_right_edge,
|
||||
left_face, right_face FROM
|
||||
city_data.edge WHERE edge_id IN (2, 3,
|
||||
( SELECT edge_id FROM newedge WHERE id = 16 ) )
|
||||
ORDER BY edge_id;
|
||||
SELECT 'N' || node_id, containing_face FROM city_data.node WHERE node_id = 4;
|
||||
|
||||
--
|
||||
-- Isolated edge
|
||||
--
|
||||
INSERT INTO city_data.node(geom, containing_face)
|
||||
VALUES ('POINT(35 28)', 0); -- N25
|
||||
INSERT INTO city_data.node(geom, containing_face)
|
||||
VALUES ('POINT(39 28)', 0); -- N26
|
||||
INSERT INTO newedge SELECT 17, topology.st_addedgemodface('city_data',
|
||||
25, 26, 'LINESTRING(35 28, 39 28)');
|
||||
SELECT 'T17', 'E'||edge_id, next_left_edge, next_right_edge,
|
||||
left_face, right_face FROM
|
||||
city_data.edge WHERE edge_id IN (
|
||||
( SELECT edge_id FROM newedge WHERE id = 17 ) )
|
||||
ORDER BY edge_id;
|
||||
SELECT 'N' || node_id, containing_face
|
||||
FROM city_data.node WHERE node_id IN ( 25, 26 );
|
||||
|
||||
--
|
||||
-- New face in universal face, enclosing isolated edge chain
|
||||
--
|
||||
INSERT INTO newedge SELECT 18, topology.st_addedgemodface('city_data',
|
||||
25, 26, 'LINESTRING(35 28, 35 45, 63 45, 63 25, 39 25, 39 28)');
|
||||
SELECT 'T18', 'E'||edge_id, next_left_edge, next_right_edge,
|
||||
left_face, right_face FROM
|
||||
city_data.edge WHERE edge_id IN ( 4, 5, 43,
|
||||
( SELECT edge_id FROM newedge WHERE id = 18 ) )
|
||||
ORDER BY edge_id;
|
||||
|
||||
--
|
||||
-- New face in universal face, with both endpoints on same existing edge
|
||||
--
|
||||
INSERT INTO newedge SELECT 19, topology.st_addedgemodface('city_data',
|
||||
9, 8, 'LINESTRING(21 6, 12 0, 9 6)');
|
||||
SELECT 'T19', 'E'||edge_id, next_left_edge, next_right_edge,
|
||||
left_face, right_face FROM
|
||||
city_data.edge WHERE edge_id IN ( 12, 35, 22,
|
||||
( SELECT edge_id FROM newedge WHERE id = 19 ) )
|
||||
ORDER BY edge_id;
|
||||
|
||||
--
|
||||
-- New face in universal face, with both endpoints on same existing edge
|
||||
-- and endpoints duplicated
|
||||
--
|
||||
INSERT INTO newedge SELECT 20, topology.st_addedgemodface('city_data',
|
||||
10, 11, 'LINESTRING(35 6, 35 6, 44 0, 47 6, 47 6)');
|
||||
SELECT 'T20', 'E'||edge_id, next_left_edge, next_right_edge,
|
||||
left_face, right_face FROM
|
||||
city_data.edge WHERE edge_id IN ( 36, 14, 16,
|
||||
( SELECT edge_id FROM newedge WHERE id = 20 ) )
|
||||
ORDER BY edge_id;
|
||||
|
||||
--
|
||||
-- Another face in universal face, with both endpoints on same existing edge
|
||||
-- and both edges' endpoints duplicated
|
||||
--
|
||||
INSERT INTO newedge SELECT 21, topology.st_addedgemodface('city_data',
|
||||
10, 11, 'LINESTRING(35 6, 35 6, 44 -4, 47 6, 47 6)');
|
||||
SELECT 'T21', 'E'||edge_id, next_left_edge, next_right_edge,
|
||||
left_face, right_face FROM
|
||||
city_data.edge WHERE edge_id IN (
|
||||
SELECT edge_id FROM newedge WHERE id IN (20, 21)
|
||||
UNION VALUES (36),(16) )
|
||||
ORDER BY edge_id;
|
||||
|
||||
--
|
||||
-- Split a face containing an hole
|
||||
--
|
||||
INSERT INTO newedge SELECT 22, topology.st_addedgemodface('city_data',
|
||||
3, 3, 'LINESTRING(25 35, 27 35, 26 34, 25 35)');
|
||||
SELECT 'T22', 'E'||edge_id, next_left_edge, next_right_edge,
|
||||
left_face, right_face FROM
|
||||
city_data.edge WHERE edge_id IN (
|
||||
SELECT edge_id FROM newedge WHERE id IN (22, 16)
|
||||
UNION VALUES (2),(3) )
|
||||
ORDER BY edge_id;
|
||||
|
||||
--
|
||||
-- Split a face containing an holes in both sides of the split
|
||||
--
|
||||
INSERT INTO newedge SELECT 23, topology.st_addedgemodface('city_data',
|
||||
2, 3, 'LINESTRING(25 30, 29 32, 29 37, 25 35)');
|
||||
SELECT 'T23', 'E'||edge_id, next_left_edge, next_right_edge,
|
||||
left_face, right_face FROM
|
||||
city_data.edge WHERE edge_id IN (
|
||||
SELECT edge_id FROM newedge WHERE id IN (13, 23, 22, 16)
|
||||
UNION VALUES (2),(3) )
|
||||
ORDER BY edge_id;
|
||||
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Check new relations and faces status
|
||||
---------------------------------------------------------------------
|
||||
|
||||
SELECT id, array_agg(comp) FROM (
|
||||
SELECT f.id, r.element_type||':'||r.element_id as comp
|
||||
FROM city_data.fp f, city_data.relation r
|
||||
WHERE r.topogeo_id = id(f.g) AND r.layer_id = layer_id(f.g)
|
||||
ORDER BY f.id, element_type, element_id
|
||||
) f GROUP BY id;
|
||||
|
||||
SELECT id, array_agg(comp) FROM (
|
||||
SELECT f.id, r.element_type||':'||r.element_id as comp
|
||||
FROM city_data.fc f, city_data.relation r
|
||||
WHERE r.topogeo_id = id(f.g) AND r.layer_id = layer_id(f.g)
|
||||
ORDER BY f.id, element_type, element_id
|
||||
) f GROUP BY id;
|
||||
|
||||
SELECT 'F'||face_id, st_astext(mbr) FROM city_data.face ORDER BY face_id;
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Cleanups
|
||||
---------------------------------------------------------------------
|
||||
|
||||
DROP TABLE newedge;
|
||||
SELECT topology.DropTopology('city_data');
|
||||
|
142
topology/test/regress/st_addedgemodface_expected
Normal file
142
topology/test/regress/st_addedgemodface_expected
Normal file
|
@ -0,0 +1,142 @@
|
|||
BEGIN
|
||||
t
|
||||
9
|
||||
22
|
||||
26
|
||||
COMMIT
|
||||
ERROR: SQL/MM Spatial exception - start node not geometry start point.
|
||||
ERROR: SQL/MM Spatial exception - end node not geometry end point.
|
||||
ERROR: SQL/MM Spatial exception - geometry crosses a node
|
||||
ERROR: SQL/MM Spatial exception - non-existent node
|
||||
ERROR: SQL/MM Spatial exception - non-existent node
|
||||
ERROR: SQL/MM Spatial exception - curve not simple
|
||||
ERROR: Invalid edge (no two distinct vertices exist)
|
||||
ERROR: Invalid edge (no two distinct vertices exist)
|
||||
ERROR: SQL/MM Spatial exception - coincident edge
|
||||
ERROR: SQL/MM Spatial exception - geometry crosses an edge
|
||||
ERROR: SQL/MM Spatial exception - geometry crosses an edge
|
||||
ERROR: Spatial exception - geometry intersects edge 4
|
||||
L1
|
||||
L2
|
||||
T1|E7|8|-19|0|10
|
||||
T1|E10|-20|17|7|4
|
||||
T1|E17|-27|11|4|5
|
||||
T1|E19|-6|27|3|10
|
||||
T1|E27|-7|-10|10|4
|
||||
T2|E8|-15|-28|0|5
|
||||
T2|E11|28|-18|11|8
|
||||
T2|E15|-8|-16|5|0
|
||||
T2|E17|-27|11|4|11
|
||||
T2|E28|-17|15|11|5
|
||||
T3|E11|28|-18|11|8
|
||||
T3|E14|16|-13|12|0
|
||||
T3|E16|29|-14|12|0
|
||||
T3|E18|10|-29|7|8
|
||||
T3|E29|14|-11|12|8
|
||||
T4|E10|-20|17|13|4
|
||||
T4|E13|18|-12|7|0
|
||||
T4|E18|-30|-29|7|8
|
||||
T4|E20|-9|30|6|13
|
||||
T4|E30|10|13|13|7
|
||||
T5|E9|19|-22|3|6
|
||||
T5|E12|-31|22|6|0
|
||||
T5|E20|31|30|14|13
|
||||
T5|E31|20|-9|14|6
|
||||
T6|E9|19|-32|3|6
|
||||
T6|E12|-31|22|6|0
|
||||
T6|E22|21|32|0|15
|
||||
T6|E32|-22|12|15|6
|
||||
T7|E6|7|-33|0|3
|
||||
T7|E19|33|27|16|10
|
||||
T7|E21|6|9|0|16
|
||||
T7|E33|-21|-6|16|3
|
||||
T8|E9|-34|-32|16|6
|
||||
T8|E19|33|27|17|10
|
||||
T8|E21|6|34|0|17
|
||||
T8|E34|19|9|17|16
|
||||
T9|E12|-31|22|6|0
|
||||
T9|E13|18|-35|7|0
|
||||
T9|E35|35|-12|18|0
|
||||
T10|E13|18|-35|7|0
|
||||
T10|E14|16|36|12|0
|
||||
T10|E36|-13|-36|0|19
|
||||
T11|E21|6|34|0|17
|
||||
T11|E22|37|32|0|15
|
||||
T11|E37|21|-37|0|20
|
||||
T12|E1|1|-38|1|0
|
||||
T12|E38|38|-1|21|0
|
||||
T13|E2|3|39|2|0
|
||||
T13|E39|-2|-39|0|22
|
||||
T14|E1|-40|-38|1|0
|
||||
T14|E40|1|40|1|1
|
||||
N23|
|
||||
T15|E1|-40|41|1|0
|
||||
T15|E38|38|-1|21|0
|
||||
T15|E41|-41|-38|0|0
|
||||
N24|
|
||||
T16|E2|3|39|23|0
|
||||
T16|E3|-3|2|23|23
|
||||
T16|E42|42|-42|23|2
|
||||
N4|
|
||||
T17|E43|-43|43|0|0
|
||||
N25|
|
||||
N26|
|
||||
T18|E4|-5|4|24|24
|
||||
T18|E5|-4|5|24|24
|
||||
T18|E43|-44|44|24|0
|
||||
T18|E44|-43|43|0|24
|
||||
T19|E12|-31|-45|6|25
|
||||
T19|E22|37|32|0|15
|
||||
T19|E35|35|45|18|0
|
||||
T19|E45|22|-12|0|25
|
||||
T20|E14|16|46|12|26
|
||||
T20|E16|29|-46|12|0
|
||||
T20|E36|-13|-36|0|19
|
||||
T20|E46|-14|36|26|0
|
||||
T21|E16|29|-47|12|0
|
||||
T21|E36|-13|-36|0|19
|
||||
T21|E46|-14|47|26|27
|
||||
T21|E47|-46|36|27|0
|
||||
T22|E2|3|39|28|0
|
||||
T22|E3|48|2|28|28
|
||||
T22|E42|42|-42|28|2
|
||||
T22|E48|-3|-48|28|23
|
||||
T23|E2|3|39|28|0
|
||||
T23|E3|-49|49|28|29
|
||||
T23|E39|-2|-39|0|22
|
||||
T23|E42|42|-42|28|2
|
||||
T23|E48|-3|-48|29|23
|
||||
T23|E49|48|2|29|28
|
||||
F3,F4|{3:3,3:4,3:10,3:16,3:17}
|
||||
F5,N4|{1:4,3:5,3:11}
|
||||
F0|
|
||||
F1|POLYGON((3 30,3 38,16 38,16 30,3 30))
|
||||
F2|POLYGON((20 34,20 37,23 37,23 34,20 34))
|
||||
F3|POLYGON((9 20,9 22,21 22,21 20,9 20))
|
||||
F4|POLYGON((21 14,21 22,35 22,35 14,21 14))
|
||||
F5|POLYGON((35 14,35 22,47 22,47 14,35 14))
|
||||
F6|POLYGON((9 6,9 14,21 14,21 6,9 6))
|
||||
F7|POLYGON((21 6,21 14,35 14,35 6,21 6))
|
||||
F8|POLYGON((35 6,35 14,47 14,47 6,35 6))
|
||||
F9|POLYGON((4 31,4 34,7 34,7 31,4 31))
|
||||
F10|POLYGON((21 14,21 22,35 22,35 14,21 14))
|
||||
F11|POLYGON((35 14,35 22,47 22,47 14,35 14))
|
||||
F12|POLYGON((35 6,35 14,47 14,47 6,35 6))
|
||||
F13|POLYGON((21 6,21 14,35 14,35 6,21 6))
|
||||
F14|POLYGON((19 6,19 14,21 14,21 6,19 6))
|
||||
F15|POLYGON((9 6,9 14,11 14,11 6,9 6))
|
||||
F16|POLYGON((9 14,9 16,21 16,21 14,9 14))
|
||||
F17|POLYGON((9 14,9 22,21 22,21 14,9 14))
|
||||
F18|POLYGON((18 0,18 6,24 6,24 0,18 0))
|
||||
F19|POLYGON((32 0,32 6,38 6,38 0,32 0))
|
||||
F20|POLYGON((3 11,3 17,9 17,9 11,3 11))
|
||||
F21|POLYGON((5 27,5 30,11 30,11 27,5 27))
|
||||
F22|POLYGON((22 27,22 30,28 30,28 27,22 27))
|
||||
F23|POLYGON((25 34,25 35,27 35,27 34,25 34))
|
||||
F24|POLYGON((35 25,35 45,63 45,63 25,35 25))
|
||||
F25|POLYGON((9 0,9 6,21 6,21 0,9 0))
|
||||
F26|POLYGON((35 0,35 6,47 6,47 0,35 0))
|
||||
F27|POLYGON((35 -4,35 6,47 6,47 -4,35 -4))
|
||||
F28|POLYGON((17 30,17 40,31 40,31 30,17 30))
|
||||
F29|POLYGON((25 30,25 37,29 37,29 30,25 30))
|
||||
Topology 'city_data' dropped
|
Loading…
Reference in a new issue