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"
@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"
@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)
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
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
-- 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));
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
(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
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
-- 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 ?
--
|| '' 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)
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
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