From: Sandro Santilli Date: Mon, 5 Mar 2012 10:49:41 +0000 (+0000) Subject: Handle 0 tolerance by using topology.precision or min float one X-Git-Tag: 2.0.0beta2~32 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=249909d5da49e1c3aec7336ff991188324561b04;p=postgis Handle 0 tolerance by using topology.precision or min float one This handling fixes the #1641 case w/out passing an explicit tolerance and makes a step toward #785. git-svn-id: http://svn.osgeo.org/postgis/trunk@9395 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/topology/sql/populate.sql.in.c b/topology/sql/populate.sql.in.c index 01ee770d9..d878049d2 100644 --- a/topology/sql/populate.sql.in.c +++ b/topology/sql/populate.sql.in.c @@ -3,7 +3,7 @@ -- PostGIS - Spatial Types for PostgreSQL -- http://postgis.refractions.net -- --- Copyright (C) 2010, 2011 Sandro Santilli +-- Copyright (C) 2010-2012 Sandro Santilli -- -- This is free software; you can redistribute and/or modify it under -- the terms of the GNU General Public Licence. See the COPYING file. @@ -40,6 +40,21 @@ AS $$ $$ 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) @@ -669,6 +684,7 @@ DECLARE prj GEOMETRY; snapedge GEOMETRY; snaptol FLOAT8; + tol FLOAT8; BEGIN -- 0. Check arguments @@ -676,13 +692,16 @@ BEGIN 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 @@ -703,7 +722,7 @@ BEGIN || 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 @@ -742,7 +761,7 @@ BEGIN #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); @@ -782,6 +801,7 @@ DECLARE id INTEGER; inodes GEOMETRY; iedges GEOMETRY; + tol float8; BEGIN -- 0. Check arguments @@ -789,19 +809,22 @@ BEGIN 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 @@ -812,7 +835,7 @@ BEGIN 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 @@ -839,13 +862,13 @@ BEGIN 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 @@ -874,19 +897,19 @@ BEGIN 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 || ')'; @@ -897,7 +920,7 @@ BEGIN #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 @@ -947,6 +970,7 @@ DECLARE rec RECORD; edges INTEGER[]; sql TEXT; + tol FLOAT8; BEGIN -- 0. Check arguments @@ -954,6 +978,9 @@ BEGIN 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 @@ -962,7 +989,7 @@ BEGIN -- 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 diff --git a/topology/sql/topogeometry/totopogeom.sql.in.c b/topology/sql/topogeometry/totopogeom.sql.in.c index 57e695939..006a6566d 100644 --- a/topology/sql/topogeometry/totopogeom.sql.in.c +++ b/topology/sql/topogeometry/totopogeom.sql.in.c @@ -28,6 +28,7 @@ DECLARE elems topology.TopoElementArray = '{{0,0}}'; sql TEXT; typ TEXT; + tolerance FLOAT8; BEGIN -- Get topology information @@ -41,6 +42,9 @@ BEGIN atopology; END; + -- Get tolerance, if 0 was given + tolerance := COALESCE( NULLIF(tolerance, 0), topology._st_mintolerance(atopology, ageom) ); + -- Get layer information BEGIN SELECT *, CASE @@ -122,7 +126,7 @@ BEGIN || '.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; @@ -131,7 +135,7 @@ BEGIN || '.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; @@ -140,7 +144,7 @@ BEGIN || '.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; diff --git a/topology/test/regress/topogeo_addlinestring.sql b/topology/test/regress/topogeo_addlinestring.sql index 9536b6252..8260e5286 100644 --- a/topology/test/regress/topogeo_addlinestring.sql +++ b/topology/test/regress/topogeo_addlinestring.sql @@ -161,19 +161,19 @@ SELECT '#1641.2', TopoGeo_addLineString('city_data', 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(); diff --git a/topology/test/regress/topogeo_addlinestring_expected b/topology/test/regress/topogeo_addlinestring_expected index 3de84a9d2..80acfe60c 100644 --- a/topology/test/regress/topogeo_addlinestring_expected +++ b/topology/test/regress/topogeo_addlinestring_expected @@ -112,26 +112,23 @@ E|54|sn49|en50 N|51||POINT(556267.6 144887) N|52||POINT(556267.6 144888) E|55|sn51|en52 +#1631.2|56 #1631.2|57 -#1631.2|58 N|53||POINT(556254.6 144886.6) N|54||POINT(556267.6 144887) -N|55||POINT(556267.6 144887) -E|55|sn51|en54 -E|56|sn54|en52 -E|57|sn53|en54 -E|58|sn54|en55 -#1641.1|59 -N|56||POINT(-0.2 0.4) -N|57||POINT(0.2 0.4) -E|59|sn56|en57 +E|56|sn53|en51 +E|57|sn51|en54 +#1641.1|58 +N|55||POINT(-0.2 0.4) +N|56||POINT(0.2 0.4) +E|58|sn55|en56 +#1641.2|60 #1641.2|61 -#1641.2|62 -N|58||POINT(0 0.2) +N|57||POINT(0 0.2) +N|58||POINT(0 0.4) N|59||POINT(0 0.4) -N|60||POINT(0 0.4) -E|59|sn56|en59 -E|60|sn59|en57 +E|58|sn55|en58 +E|59|sn58|en56 +E|60|sn57|en58 E|61|sn58|en59 -E|62|sn59|en60 Topology 'city_data' dropped