]> granicus.if.org Git - postgis/commitdiff
Handle 0 tolerance by using topology.precision or min float one
authorSandro Santilli <strk@keybit.net>
Mon, 5 Mar 2012 10:49:41 +0000 (10:49 +0000)
committerSandro Santilli <strk@keybit.net>
Mon, 5 Mar 2012 10:49:41 +0000 (10:49 +0000)
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

topology/sql/populate.sql.in.c
topology/sql/topogeometry/totopogeom.sql.in.c
topology/test/regress/topogeo_addlinestring.sql
topology/test/regress/topogeo_addlinestring_expected

index 01ee770d9d1dd9c2f246813a8941cbe2ec3f4d2e..d878049d2073b771d2803055fd04adba1f463a49 100644 (file)
@@ -3,7 +3,7 @@
 -- 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.
@@ -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
index 57e69593922755e97de221f2a4cdfb832b63f8ed..006a6566d378e308a552ddd6371303d3e57b2f85 100644 (file)
@@ -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;
index 9536b6252c18a275c16bf667efe951a76d839114..8260e5286052353e73d871cc9d204f7c3cf8375d 100644 (file)
@@ -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();
index 3de84a9d2889093cfc0cc5da4bf6a84668ae11c2..80acfe60c69c26ba33d0b52c6683e41ff02089da 100644 (file)
@@ -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