-- PostGIS - Spatial Types for PostgreSQL
-- http://postgis.refractions.net
--
--- Copyright (C) 2010, 2011 Sandro Santilli <strk@keybit.net>
+-- Copyright (C) 2010-2012 Sandro Santilli <strk@keybit.net>
--
-- This is free software; you can redistribute and/or modify it under
-- the terms of the GNU General Public Licence. See the COPYING file.
$$ LANGUAGE 'SQL' IMMUTABLE STRICT;
-- }
+-- {
+-- Get tolerance for a given topology
+-- and if zero the min for a given topology
+-- }{
+CREATE OR REPLACE FUNCTION topology._st_mintolerance(atopology varchar, ageom Geometry)
+ RETURNS float8
+AS $$
+ SELECT COALESCE(
+ NULLIF(precision, 0),
+ topology._st_mintolerance($2))
+ FROM topology.topology
+ WHERE name = $1;
+$$ LANGUAGE 'SQL' IMMUTABLE STRICT;
+-- }
+
--{
--
-- AddNode(atopology, point, allowEdgeSplitting, setContainingFace)
prj GEOMETRY;
snapedge GEOMETRY;
snaptol FLOAT8;
+ tol FLOAT8;
BEGIN
-- 0. Check arguments
RAISE EXCEPTION 'Invalid geometry type (%) passed to TopoGeo_AddPoint, expected POINT', geometrytype(apoint);
END IF;
+ -- Get tolerance, if 0 was given
+ tol := COALESCE( NULLIF(tolerance, 0), topology._st_mintolerance(atopology, apoint) );
+
-- 1. Check if any existing node falls within tolerance
-- and if so pick the closest
sql := 'SELECT a.node_id FROM '
|| quote_ident(atopology)
|| '.node as a WHERE ST_DWithin(a.geom,'
|| quote_literal(apoint::text) || '::geometry,'
- || tolerance || ') ORDER BY ST_Distance('
+ || tol || ') ORDER BY ST_Distance('
|| quote_literal(apoint::text)
|| '::geometry, a.geom) LIMIT 1;';
#ifdef POSTGIS_TOPOLOGY_DEBUG
|| quote_ident(atopology)
|| '.edge as a WHERE ST_DWithin(a.geom,'
|| quote_literal(apoint::text) || '::geometry,'
- || tolerance || ') ORDER BY ST_Distance('
+ || tol || ') ORDER BY ST_Distance('
|| quote_literal(apoint::text)
|| '::geometry, a.geom) LIMIT 1;';
#ifdef POSTGIS_TOPOLOGY_DEBUG
#ifdef POSTGIS_TOPOLOGY_DEBUG
IF NOT ST_Contains(snapedge, prj) THEN -- or if equal ?
- RAISE WARNING 'Edge within % distance from node still does not contain the node after snapping to it with tolerance %', tolerance, snaptol;
+ RAISE WARNING 'Edge within % distance from node still does not contain the node after snapping to it with tolerance %', tol, snaptol;
END IF;
#endif
PERFORM ST_ChangeEdgeGeom(atopology, rec.edge_id, snapedge);
id INTEGER;
inodes GEOMETRY;
iedges GEOMETRY;
+ tol float8;
BEGIN
-- 0. Check arguments
RAISE EXCEPTION 'Invalid geometry type (%) passed to TopoGeo_AddLinestring, expected LINESTRING', geometrytype(aline);
END IF;
+ -- Get tolerance, if 0 was given
+ tol := COALESCE( NULLIF(tolerance, 0), topology._st_mintolerance(atopology, aline) );
+
-- 1. Self-node
noded := ST_UnaryUnion(aline);
#ifdef POSTGIS_TOPOLOGY_DEBUG
RAISE DEBUG 'Self-noded: %', ST_AsText(noded);
#endif
- -- 2. Node to edges falling within tolerance distance
+ -- 2. Node to edges falling within tol distance
sql := 'WITH nearby AS ( SELECT e.geom FROM '
|| quote_ident(atopology)
|| '.edge e WHERE ST_DWithin(e.geom, '
|| quote_literal(noded::text)
|| '::geometry, '
- || tolerance || ') ) SELECT st_collect(geom) FROM nearby;';
+ || tol || ') ) SELECT st_collect(geom) FROM nearby;';
#ifdef POSTGIS_TOPOLOGY_DEBUG
RAISE DEBUG '%', sql;
#endif
RAISE DEBUG 'Intersecting edges: %', ST_AsText(iedges);
#endif
- snapped := ST_Snap(noded, iedges, tolerance);
+ snapped := ST_Snap(noded, iedges, tol);
#ifdef POSTGIS_TOPOLOGY_DEBUG
RAISE DEBUG 'Snapped: %', ST_AsText(snapped);
#endif
END IF;
- -- 2.1. Node with existing nodes within tolerance
+ -- 2.1. Node with existing nodes within tol
sql := 'WITH nearby AS ( SELECT n.geom FROM '
|| quote_ident(atopology)
|| '.node n WHERE ST_DWithin(n.geom, '
|| quote_literal(noded::text)
|| '::geometry, '
- || tolerance || ') ) SELECT (st_dump(st_unaryunion(st_collect(geom)))).geom FROM nearby;';
+ || tol || ') ) SELECT (st_dump(st_unaryunion(st_collect(geom)))).geom FROM nearby;';
#ifdef POSTGIS_TOPOLOGY_DEBUG
RAISE DEBUG '%', sql;
#endif
start_node := topology.TopoGeo_AddPoint(atopology,
ST_StartPoint(rec.geom),
- tolerance);
+ tol);
#ifdef POSTGIS_TOPOLOGY_DEBUG
RAISE DEBUG ' Start Node: %', start_node;
#endif
end_node := topology.TopoGeo_AddPoint(atopology,
ST_EndPoint(rec.geom),
- tolerance);
+ tol);
#ifdef POSTGIS_TOPOLOGY_DEBUG
RAISE DEBUG ' End Node: %', end_node;
#endif
- -- Added endpoints may have drifted due to tolerance, so
+ -- Added endpoints may have drifted due to tol, so
-- we need to re-snap the edge to the new nodes before adding it
sql := 'SELECT ST_Collect(geom) FROM ' || quote_ident(atopology)
|| '.node WHERE node_id IN (' || start_node || ',' || end_node || ')';
#ifdef POSTGIS_TOPOLOGY_DEBUG
RAISE DEBUG 'Endnodes: %', ST_AsText(set2);
#endif
- snapped := ST_Snap(rec.geom, set2, tolerance);
+ snapped := ST_Snap(rec.geom, set2, tol);
#ifdef POSTGIS_TOPOLOGY_DEBUG
RAISE DEBUG 'Snapped edge: %', ST_AsText(snapped);
#endif
rec RECORD;
edges INTEGER[];
sql TEXT;
+ tol FLOAT8;
BEGIN
-- 0. Check arguments
RAISE EXCEPTION 'Invalid geometry type (%) passed to TopoGeo_AddPolygon, expected POLYGON', geometrytype(apoly);
END IF;
+ -- Get tolerance, if 0 was given
+ tol := COALESCE( NULLIF(tolerance, 0), topology._st_mintolerance(atopology, apoly) );
+
-- 1. Extract boundary
boundary := ST_Boundary(apoly);
#ifdef POSTGIS_TOPOLOGY_DEBUG
-- 2. Add boundaries as edges
FOR rec IN SELECT (ST_Dump(boundary)).geom LOOP
- edges := array_cat(edges, array_agg(x)) FROM ( select topology.TopoGeo_addLinestring(atopology, rec.geom, tolerance) as x ) as foo;
+ edges := array_cat(edges, array_agg(x)) FROM ( select topology.TopoGeo_addLinestring(atopology, rec.geom, tol) as x ) as foo;
#ifdef POSTGIS_TOPOLOGY_DEBUG
RAISE DEBUG 'New edges: %', edges;
#endif
elems topology.TopoElementArray = '{{0,0}}';
sql TEXT;
typ TEXT;
+ tolerance FLOAT8;
BEGIN
-- Get topology information
atopology;
END;
+ -- Get tolerance, if 0 was given
+ tolerance := COALESCE( NULLIF(tolerance, 0), topology._st_mintolerance(atopology, ageom) );
+
-- Get layer information
BEGIN
SELECT *, CASE
|| '.relation(topogeo_id, layer_id, element_type, element_id) SELECT '
|| id(tg) || ', ' || alayer || ', 1, topogeo_addPoint('
|| quote_literal(atopology) || ', '
- || quote_literal(rec.geom::text) || '::geometry, ' || atolerance
+ || quote_literal(rec.geom::text) || '::geometry, ' || tolerance
|| ');';
--RAISE DEBUG '%', sql;
EXECUTE sql;
|| '.relation(topogeo_id, layer_id, element_type, element_id) SELECT '
|| id(tg) || ', ' || alayer || ', 2, topogeo_addLineString('
|| quote_literal(atopology) || ', '
- || quote_literal(rec.geom::text) || '::geometry, ' || atolerance
+ || quote_literal(rec.geom::text) || '::geometry, ' || tolerance
|| ');';
--RAISE DEBUG '%', sql;
EXECUTE sql;
|| '.relation(topogeo_id, layer_id, element_type, element_id) SELECT '
|| id(tg) || ', ' || alayer || ', 3, topogeo_addPolygon('
|| quote_literal(atopology) || ', '
- || quote_literal(rec.geom::text) || '::geometry, ' || atolerance
+ || quote_literal(rec.geom::text) || '::geometry, ' || tolerance
|| ');';
--RAISE DEBUG '%', sql;
EXECUTE sql;
SELECT check_changes();
-- Fails w/out tolerance as of 2.0.0
---FAILS---- clean all up first
---FAILS--DELETE FROM city_data.edge_data;
---FAILS--DELETE FROM city_data.node;
---FAILS--DELETE FROM city_data.face where face_id > 0;
---FAILS--
---FAILS--SELECT '#1641.3', TopoGeo_addLineString('city_data',
---FAILS-- 'LINESTRING(-0.223586 0.474301, 0.142550 0.406124)'
---FAILS--) ORDER BY 2;
---FAILS--SELECT check_changes();
---FAILS--SELECT '#1641.4', TopoGeo_addLineString('city_data',
---FAILS-- 'LINESTRING(0.095989 0.113619, -0.064646 0.470149)'
---FAILS--) ORDER BY 2;
---FAILS--SELECT check_changes();
+-- clean all up first
+--DELETE FROM city_data.edge_data;
+--DELETE FROM city_data.node;
+--DELETE FROM city_data.face where face_id > 0;
+--
+--SELECT '#1641.3', TopoGeo_addLineString('city_data',
+-- 'LINESTRING(-0.223586 0.474301, 0.142550 0.406124)'
+--) ORDER BY 2;
+--SELECT check_changes();
+--SELECT '#1641.4', TopoGeo_addLineString('city_data',
+-- 'LINESTRING(0.095989 0.113619, -0.064646 0.470149)'
+--) ORDER BY 2;
+--SELECT check_changes();
-- Cleanups
DROP FUNCTION check_changes();