Added ST_ModEdgesSplit function, cleaned up test files, added tests for

the new topology editing functions.


git-svn-id: http://svn.osgeo.org/postgis/trunk@1971 b70326c6-7e19-0410-871a-916f4a2858ee
This commit is contained in:
Sandro Santilli 2005-10-19 10:04:15 +00:00
parent 307df8801e
commit e51b2fe6b6
7 changed files with 372 additions and 23 deletions

View file

@ -1,6 +1,8 @@
DATABASE=postgis_topo_regress
all:
@echo
@echo "make test - create the database, run all tests except sqlmm"
@echo
@echo "make initdb - create the regress database"
@echo "make inittopo - create topology routines"
@ -10,6 +12,8 @@ all:
@echo "make validate - validate 'city_data' loaded topology"
@echo
@echo "make hier - define some hierarchical TopoGeoms"
@echo
@echo "make edit - test sqlmm editing functions"
@echo
@echo "make cache - create geom caches for features tables"
@echo "make topopred - run predicates on topogeoms"
@ -19,6 +23,14 @@ all:
@echo "make sqlmm - test SQL/MM functions (exceptions are expected)"
@echo
pred:
@make geompred | grep -v make > /tmp/geompred.out
@make topopred | grep -v make > /tmp/topopred.out
@diff /tmp/geompred.out /tmp/topopred.out
@diff /tmp/geompred.out predicate.expected
test: inittopo load loadmore hier cache pred invalid edit
initdb:
createdb $(DATABASE)
createlang plpgsql $(DATABASE)
@ -49,10 +61,10 @@ sqlmm:
psql -f sqlmm_topology.sql $(DATABASE)
topopred: topo_predicates.sql
psql -f topo_predicates.sql $(DATABASE)
@psql -tf topo_predicates.sql $(DATABASE)
geompred: geom_predicates.sql
psql -f geom_predicates.sql $(DATABASE)
@psql -tf geom_predicates.sql $(DATABASE)
topo_predicates.sql: predicates.sql.in
cpp -P -traditional-cpp predicates.sql.in | sed -e 's:@COLUMN@:feature:g;s:@SCHEMA@:topology.:g' > topo_predicates.sql
@ -60,6 +72,8 @@ topo_predicates.sql: predicates.sql.in
geom_predicates.sql: predicates.sql.in
cpp -P -traditional-cpp predicates.sql.in | sed -e 's:@COLUMN@:the_geom:g;s:@SCHEMA@::g' > geom_predicates.sql
edit:
psql -f edit_topology.sql
clean distclean:
rm -f geom_predicates.sql topo_predicates.sql

View file

@ -2,17 +2,17 @@
-- created by load_topology.sql and stores there the SFS Geometry
-- derived by the TopoGeometry column
ALTER TABLE features.city_streets ADD the_geom geometry;
UPDATE features.city_streets set the_geom = topology.Geometry(feature);
--ALTER TABLE features.city_streets ADD the_geom geometry;
UPDATE features.city_streets set the_geom = multi(topology.Geometry(feature));
ALTER TABLE features.traffic_signs ADD the_geom geometry;
UPDATE features.traffic_signs set the_geom = topology.Geometry(feature);
--ALTER TABLE features.traffic_signs ADD the_geom geometry;
UPDATE features.traffic_signs set the_geom = multi(topology.Geometry(feature));
ALTER TABLE features.land_parcels ADD the_geom geometry;
UPDATE features.land_parcels set the_geom = topology.Geometry(feature);
--ALTER TABLE features.land_parcels ADD the_geom geometry;
UPDATE features.land_parcels set the_geom = multi(topology.Geometry(feature));
ALTER TABLE features.big_parcels ADD the_geom geometry;
UPDATE features.big_parcels set the_geom = topology.Geometry(feature);
--ALTER TABLE features.big_parcels ADD the_geom geometry;
UPDATE features.big_parcels set the_geom = multi(topology.Geometry(feature));
ALTER TABLE features.big_signs ADD the_geom geometry;
UPDATE features.big_signs set the_geom = topology.Geometry(feature);
--ALTER TABLE features.big_signs ADD the_geom geometry;
UPDATE features.big_signs set the_geom = multi(topology.Geometry(feature));

View file

@ -0,0 +1,3 @@
select topology.ST_NewEdgesSplit('city_data',25,'POINT(10 35)');
select topology.ST_ModEdgesSplit('city_data',27,'POINT(9.5 35)');
select topology.ST_ModEdgesSplit('city_data',28,'POINT(11 35)');

View file

@ -15,6 +15,8 @@ SELECT topology.AddTopoGeometryColumn('city_data', 'features',
1 -- the land_parcles
);
SELECT AddGeometryColumn('features','big_parcels','the_geom',-1,'MULTIPOLYGON',2);
INSERT INTO features.big_parcels VALUES ('P1P2', -- Feature name
topology.CreateTopoGeom(
'city_data', -- Topology name
@ -36,13 +38,6 @@ INSERT INTO features.big_parcels VALUES ('F3F6', -- Feature name
(SELECT layer_id FROM topology.layer WHERE table_name = 'big_parcels'),
'{{6,1},{7,1}}')); -- F3 and F6
INSERT INTO features.big_parcels VALUES ('F3F6', -- Feature name
topology.CreateTopoGeom(
'city_data', -- Topology name
3, -- Topology geometry type (polygon/multipolygon)
(SELECT layer_id FROM topology.layer WHERE table_name = 'big_parcels'),
'{{7,1},{6,1}}')); -- F3 and F6
SELECT feature_name, astext(topology.geometry(feature)) from features.big_parcels;
SELECT a.feature_name, b.feature_name
@ -62,6 +57,8 @@ SELECT topology.AddTopoGeometryColumn('city_data', 'features',
2 -- the traffic_signs
);
SELECT AddGeometryColumn('features','big_signs','the_geom',-1,'MULTIPOINT',2);
INSERT INTO features.big_signs VALUES ('S1S2', -- Feature name
topology.CreateTopoGeom(
'city_data', -- Topology name

View file

@ -221,6 +221,12 @@ SELECT topology.AddTopoGeometryColumn('city_data', 'features', 'city_streets','f
--NOTYET---- 5. Initialize topology metadata.
--NOTYET--EXECUTE topology.INITIALIZE_METADATA('CITY_DATA');
-- 4bis. Add geometry columns, for caching Geometries from TopoGeometries
SELECT AddGeometryColumn('features','land_parcels','the_geom',-1,'MULTIPOLYGON',2);
SELECT AddGeometryColumn('features','city_streets','the_geom',-1,'MULTILINESTRING',2);
SELECT AddGeometryColumn('features','traffic_signs','the_geom',-1,'MULTIPOINT',2);
-- 6. Load feature tables using the CreateTopoGeom constructor.

View file

@ -0,0 +1,118 @@
BEGIN
POINT/POINT INTERSECTS
S1 | N1N6N14
S3 | N1N6N14
S4 | N3N4
S4 | N4
N1N2N3 | N1N6N14
N1N2N3 | N3N4
N3N4 | N4
POINT/LINE INTERSECTS
S1 | R1
S1 | E20E19
S1 | R1a
S2 | R1
S2 | R1a
S3 | R2
N1N2N3 | R4
N1N6N14 | R1
N1N6N14 | R2
N1N6N14 | E20E19
N1N6N14 | R1a
N3N4 | R4
LINE/LINE INTERSECTS
R1 | E20E19
R1 | R1a
R3 | E25
E7E8 | E20E19
E20E19 | R1a
POINT/POLY INTERSECTS
S1 | P1
S1 | P2
S1 | F3
S1 | F6
S1 | F3F4
S2 | P2
S2 | P3
S2 | F3F4
S4 | P4
N1N2N3 | P4
N1N2N3 | P5
N1N2N3 | F1
N1N6N14 | P1
N1N6N14 | P2
N1N6N14 | P5
N1N6N14 | F3
N1N6N14 | F6
N1N6N14 | F3F4
N1N6N14 | F1
N3N4 | P4
N4 | P4
LINE/POLY INTERSECTS
R1 | P1
R1 | P2
R1 | P3
R1 | F3
R1 | F6
R1 | F3F4
R3 | P5
R3 | F1
R4 | P4
E7E8 | P1
E7E8 | P2
E7E8 | P3
E7E8 | F3
E7E8 | F3F4
E20E19 | P1
E20E19 | P2
E20E19 | F3
E20E19 | F6
E20E19 | F3F4
E25 | P5
E25 | F1
R1a | P1
R1a | P2
R1a | P3
R1a | F3
R1a | F6
R1a | F3F4
POLY/POLY INTERSECTS
P1 | P2
P1 | F3
P1 | F6
P1 | F3F4
P2 | P3
P2 | F3
P2 | F6
P2 | F3F4
P3 | F3F4
P5 | F1
F3 | F6
F3 | F3F4
F6 | F3F4
POINT/POINT EQUALS
S4 | N4
LINE/LINE EQUALS
R1 | R1a
R3 | E25
POLYGON/POLYGON EQUALS
P5 | F1
COMMIT

View file

@ -140,7 +140,12 @@
-- Complete
--
-- ST_NewEdgesSplit
-- Complete, exceptions untested
-- Complete
-- this also updates the Relation table
-- TODO: add entries to the History table ?
--
-- ST_ModEdgesSplit
-- Complete
-- this also updates the Relation table
-- TODO: add entries to the History table ?
--
@ -2880,7 +2885,7 @@ BEGIN
|| '' AND abs(r.element_id) = '' || anedge
|| '' AND r.element_type = 2''
LOOP
RAISE NOTICE ''TopoGeometry % in layer % contains the edge being split'', rec.topogeo_id, rec.layer_id;
--RAISE NOTICE ''TopoGeometry % in layer % contains the edge being split'', rec.topogeo_id, rec.layer_id;
-- Delete old reference
EXECUTE ''DELETE FROM '' || quote_ident(atopology)
@ -2932,8 +2937,8 @@ BEGIN
END LOOP;
RAISE NOTICE ''Edge % split in edges % and % by node %'',
anedge, edgeid1, edgeid2, nodeid;
--RAISE NOTICE ''Edge % split in edges % and % by node %'',
-- anedge, edgeid1, edgeid2, nodeid;
RETURN nodeid;
END
@ -2941,6 +2946,212 @@ END
LANGUAGE 'plpgsql' _VOLATILE;
--} ST_NewEdgesSplit
--{
-- Topo-Geo and Topo-Net 3: Routine Details
-- X.3.9
--
-- ST_ModEdgesSplit(atopology, anedge, apoint)
--
CREATEFUNCTION topology.ST_ModEdgesSplit(varchar, integer, geometry)
RETURNS INTEGER AS
'
DECLARE
atopology ALIAS FOR $1;
anedge ALIAS FOR $2;
apoint ALIAS FOR $3;
oldedge RECORD;
rec RECORD;
tmp integer;
topoid integer;
nodeid integer;
nodepos float8;
newedgeid integer;
newedge1 geometry;
newedge2 geometry;
query text;
ok BOOL;
BEGIN
--
-- All args required
--
IF atopology IS NULL OR anedge IS NULL OR apoint IS NULL THEN
RAISE EXCEPTION
''SQL/MM Spatial exception - null argument'';
END IF;
--
-- Check node existance
--
ok = false;
FOR oldedge IN EXECUTE ''SELECT * FROM ''
|| quote_ident(atopology) || ''.edge_data '' ||
'' WHERE edge_id = '' || anedge
LOOP
ok = true;
END LOOP;
IF NOT ok THEN
RAISE EXCEPTION
''SQL/MM Spatial exception - non-existent edge'';
END IF;
--
-- Check that given point is Within(anedge.geom)
--
IF NOT within(apoint, oldedge.geom) THEN
RAISE EXCEPTION
''SQL/MM Spatial exception - point not on edge'';
END IF;
--
-- Check if a coincident node already exists
--
FOR rec IN EXECUTE ''SELECT node_id FROM ''
|| quote_ident(atopology) || ''.node '' ||
''WHERE geom && '' || quote_literal(apoint) || ''::geometry''
||'' AND x(geom) = x(''||quote_literal(apoint)||''::geometry)''
||'' AND y(geom) = y(''||quote_literal(apoint)||''::geometry)''
LOOP
RAISE EXCEPTION
''SQL/MM Spatial exception - coincident node'';
END LOOP;
--
-- Get new node id
--
FOR rec IN EXECUTE ''SELECT nextval('''''' ||
atopology || ''.node_node_id_seq'''')''
LOOP
nodeid = rec.nextval;
END LOOP;
--RAISE NOTICE ''Next node id = % '', nodeid;
--
-- Add the new node
--
EXECUTE ''INSERT INTO '' || quote_ident(atopology)
|| ''.node(node_id, geom)
VALUES(''||nodeid||'',''||quote_literal(apoint)||
'')'';
--
-- Compute new edge
--
nodepos = line_locate_point(oldedge.geom, apoint);
newedge1 = line_substring(oldedge.geom, 0, nodepos);
newedge2 = line_substring(oldedge.geom, nodepos, 1);
--
-- Get ids for the new edge
--
FOR rec IN EXECUTE ''SELECT nextval('''''' ||
atopology || ''.edge_data_edge_id_seq'''')''
LOOP
newedgeid = rec.nextval;
END LOOP;
--
-- Insert the new edge
--
EXECUTE ''INSERT INTO '' || quote_ident(atopology)
|| ''.edge ''
|| ''(edge_id, start_node, end_node,''
|| ''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)
||'')'';
--
-- Update the old edge
--
EXECUTE ''UPDATE '' || quote_ident(atopology) || ''.edge_data ''
|| '' SET geom = '' || quote_literal(newedge1)
|| '',''
|| '' next_left_edge = '' || newedgeid
|| '',''
|| '' end_node = '' || nodeid
|| '' WHERE edge_id = '' || anedge;
--
-- Update all next edge references to match new layout
--
EXECUTE ''UPDATE '' || quote_ident(atopology)
|| ''.edge_data SET next_right_edge = ''
|| -newedgeid
|| '',''
|| '' abs_next_right_edge = '' || newedgeid
|| '' WHERE 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;
--
-- Update references in the Relation table.
-- We only take into considerations non-hierarchical
-- TopoGeometry here, for obvious reasons.
--
FOR rec IN EXECUTE ''SELECT r.* 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 abs(r.element_id) = '' || anedge
|| '' AND r.element_type = 2''
LOOP
--RAISE NOTICE ''TopoGeometry % in layer % contains the edge being split (%) - updating to add new edge %'', rec.topogeo_id, rec.layer_id, anedge, newedgeid;
-- Add new reference to edge1
IF rec.element_id < 0 THEN
tmp = -newedgeid;
ELSE
tmp = newedgeid;
END IF;
query = ''INSERT INTO '' || quote_ident(atopology)
|| ''.relation ''
|| '' VALUES( ''
|| rec.topogeo_id
|| '',''
|| rec.layer_id
|| '',''
|| tmp
|| '',''
|| rec.element_type
|| '')'';
--RAISE NOTICE ''%'', query;
EXECUTE query;
END LOOP;
--RAISE NOTICE ''Edge % split in edges % and % by node %'',
-- anedge, anedge, newedgeid, nodeid;
RETURN nodeid;
END
'
LANGUAGE 'plpgsql' _VOLATILE;
--} ST_ModEdgesSplit
--{
-- Topo-Geo and Topo-Net 3: Routine Details
-- X.3.4