]> granicus.if.org Git - postgis/commitdiff
topology.ST_AddEdgeNewFaces : tabs to spaces, named arguments, code cleanups and...
authorSandro Santilli <strk@keybit.net>
Thu, 12 May 2011 16:14:53 +0000 (16:14 +0000)
committerSandro Santilli <strk@keybit.net>
Thu, 12 May 2011 16:14:53 +0000 (16:14 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@7134 b70326c6-7e19-0410-871a-916f4a2858ee

topology/sql/sqlmm.sql
topology/test/Makefile
topology/test/regress/st_addedgenewfaces.sql [new file with mode: 0644]
topology/test/regress/st_addedgenewfaces_expected [new file with mode: 0644]

index 8b59eec53e25649f497fd897d5ae97f04e6c3d71..8ef9b8e195f8d4fbcdd0bf53ec73c6991fffd4e8 100644 (file)
@@ -1828,200 +1828,202 @@ LANGUAGE 'plpgsql' VOLATILE;
 --
 --  ST_AddEdgeNewFaces(atopology, anode, anothernode, acurve)
 --
-CREATE OR REPLACE FUNCTION topology.ST_AddEdgeNewFaces(varchar, integer, integer, geometry)
-       RETURNS INTEGER AS
+CREATE OR REPLACE FUNCTION topology.ST_AddEdgeNewFaces(atopology varchar, anode integer, anothernode integer, acurve geometry)
+  RETURNS INTEGER AS
 $$
 DECLARE
-       atopology ALIAS FOR $1;
-       anode ALIAS FOR $2;
-       anothernode ALIAS FOR $3;
-       acurve ALIAS FOR $4;
-       rec RECORD;
-       i INTEGER;
-       az FLOAT8;
-       azdif FLOAT8;
-       myaz FLOAT8;
-       minazimuth FLOAT8;
-       maxazimuth FLOAT8;
-       p2 GEOMETRY;
+  rec RECORD;
+  i INTEGER;
+  az FLOAT8;
+  azdif FLOAT8;
+  myaz FLOAT8;
+  minazimuth FLOAT8;
+  maxazimuth FLOAT8;
+  p2 GEOMETRY;
 BEGIN
 
-       --
-       -- All args required
-       -- 
-       IF atopology IS NULL
-               OR anode IS NULL
-               OR anothernode IS NULL
-               OR acurve IS NULL
-       THEN
-               RAISE EXCEPTION 'SQL/MM Spatial exception - null argument';
-       END IF;
+  --
+  -- All args required
+  -- 
+  IF atopology IS NULL
+    OR anode IS NULL
+    OR anothernode IS NULL
+    OR acurve IS NULL
+  THEN
+    RAISE EXCEPTION 'SQL/MM Spatial exception - null argument';
+  END IF;
 
-       --
-       -- Acurve must be a LINESTRING
-       --
-       IF substring(geometrytype(acurve), 1, 4) != 'LINE'
-       THEN
-               RAISE EXCEPTION
-                'SQL/MM Spatial exception - invalid curve';
-       END IF;
-       
-       --
-       -- Curve must be simple
-       --
-       IF NOT ST_IsSimple(acurve) THEN
-               RAISE EXCEPTION
-                'SQL/MM Spatial exception - curve not simple';
-       END IF;
+  --
+  -- Acurve must be a LINESTRING
+  --
+  IF substring(geometrytype(acurve), 1, 4) != 'LINE'
+  THEN
+    RAISE EXCEPTION 'SQL/MM Spatial exception - invalid curve';
+  END IF;
+  
+  --
+  -- Curve must be simple
+  --
+  IF NOT ST_IsSimple(acurve) THEN
+    RAISE EXCEPTION 'SQL/MM Spatial exception - curve not simple';
+  END IF;
 
-       -- 
-       -- Check endpoints existance and match with Curve geometry
-       --
-       i=0;
-       FOR rec IN EXECUTE 'SELECT '
-               || ' CASE WHEN node_id = ' || anode
-               || ' THEN 1 WHEN node_id = ' || anothernode
-               || ' THEN 0 END AS start, geom FROM '
-               || quote_ident(atopology)
-               || '.node '
-               || ' WHERE node_id IN ( '
-               || anode || ',' || anothernode
-               || ')'
-       LOOP
-               IF rec.start THEN
-                       IF NOT Equals(rec.geom, ST_StartPoint(acurve))
-                       THEN
-       RAISE EXCEPTION
-       'SQL/MM Spatial exception - start node not geometry start point.';
-                       END IF;
-               ELSE
-                       IF NOT Equals(rec.geom, ST_EndPoint(acurve))
-                       THEN
-       RAISE EXCEPTION
-       'SQL/MM Spatial exception - end node not geometry end point.';
-                       END IF;
-               END IF;
+  -- 
+  -- Check endpoints existance and match with Curve geometry
+  --
+  i=0;
+  FOR rec IN EXECUTE 'SELECT '
+    || ' CASE WHEN node_id = ' || anode
+    || ' THEN 1 WHEN node_id = ' || anothernode
+    || ' THEN 0 END AS start, geom FROM '
+    || quote_ident(atopology)
+    || '.node '
+    || ' WHERE node_id IN ( '
+    || anode || ',' || anothernode
+    || ')'
+  LOOP
+    IF rec.start THEN
+      IF NOT Equals(rec.geom, ST_StartPoint(acurve))
+      THEN
+        RAISE EXCEPTION
+          'SQL/MM Spatial exception - start node not geometry start point.';
+      END IF;
+    ELSE
+      IF NOT Equals(rec.geom, ST_EndPoint(acurve))
+      THEN
+        RAISE EXCEPTION
+          'SQL/MM Spatial exception - end node not geometry end point.';
+      END IF;
+    END IF;
 
-               i=i+1;
-       END LOOP;
+    i=i+1;
+  END LOOP;
 
-       IF i < 2 THEN
-               RAISE EXCEPTION
-                'SQL/MM Spatial exception - non-existent node';
-       END IF;
+  IF anode != anothernode THEN
+    IF i < 2 THEN
+    RAISE EXCEPTION
+     'SQL/MM Spatial exception - non-existent node';
+    END IF;
+  ELSE
+    IF i < 1 THEN
+    RAISE EXCEPTION
+     'SQL/MM Spatial exception - non-existent node';
+    END IF;
+  END IF;
 
-       --
-       -- Check if this geometry crosses any node
-       --
-       FOR rec IN EXECUTE 'SELECT node_id FROM '
-               || quote_ident(atopology) || '.node
-               WHERE geom && ' || quote_literal(acurve::text) || '::geometry
-               AND ST_Within(geom, ' || quote_literal(acurve::text) || '::geometry)'
-       LOOP
-               RAISE EXCEPTION
-               'SQL/MM Spatial exception - geometry crosses a node';
-       END LOOP;
+  --
+  -- Check if this geometry crosses any node
+  --
+  FOR rec IN EXECUTE 'SELECT node_id FROM '
+    || quote_ident(atopology)
+    || '.node WHERE geom && '
+    || quote_literal(acurve::text)
+    || '::geometry AND ST_Within(geom, '
+    || quote_literal(acurve::text) || '::geometry)'
+  LOOP
+    RAISE EXCEPTION
+    'SQL/MM Spatial exception - geometry crosses a node';
+  END LOOP;
 
-       --
-       -- Check if this geometry crosses any existing edge
-       --
-       FOR rec IN EXECUTE 'SELECT * FROM '
-               || quote_ident(atopology) || '.edge_data
-               WHERE geom && ' || quote_literal(acurve::text) || '::geometry
-               AND crosses(geom, ' || quote_literal(acurve::text) || '::geometry)'
-       LOOP
-               RAISE EXCEPTION
-               'SQL/MM Spatial exception - geometry crosses an edge';
-       END LOOP;
+  --
+  -- Check if this geometry has any interaction with any existing edge
+  --
+  FOR rec IN EXECUTE 'SELECT edge_id, ST_Relate(geom,' 
+    || quote_literal(acurve::text)
+    || '::geometry) as im FROM '
+    || quote_ident(atopology)
+    || '.edge_data WHERE geom && '
+    || quote_literal(acurve::text) || '::geometry'
+  LOOP
 
-       --
-       -- Check if another edge share this edge endpoints
-       --
-       FOR rec IN EXECUTE 'SELECT * FROM '
-               || quote_ident(atopology) || '.edge_data '
-               || ' WHERE '
-               || ' geom && ' || quote_literal(acurve::text) || '::geometry '
-               || ' AND '
-               || ' ( ('
-               || ' start_node = ' || anode
-               || ' AND '
-               || ' end_node = ' || anothernode
-               || ' ) OR ( '
-               || ' end_node = ' || anode
-               || ' AND '
-               || ' start_node = ' || anothernode
-               || ' ) )'
-               || ' AND '
-               || 'equals(geom,' || quote_literal(acurve::text) || '::geometry)'
-       LOOP
-               RAISE EXCEPTION
-               'SQL/MM Spatial exception - coincident edge';
-       END LOOP;
+    --RAISE DEBUG 'IM=%',rec.im;
 
-       ---------------------------------------------------------------
-       --
-       -- All checks passed, time to extract informations about
-       -- endpoints:
-       --
-       --      next_left_edge
-       --      next_right_edge
-       --      left_face
-       --      right_face
-       --
-       ---------------------------------------------------------------
+    IF ST_RelateMatch(rec.im, 'F********') THEN
+      CONTINUE; -- no interior intersection
+    END IF;
 
-       --
-       --
-       -- Compute next_left_edge 
-       --
-       -- We fetch all edges with an endnode equal to
-       -- this edge end_node (anothernode).
-       -- For each edge we compute azimuth of the segment(s).
-       -- Of interest are the edges with closest (smaller
-       -- and bigger) azimuths then the azimuth of
-       -- this edge last segment.
-       --
+    IF ST_RelateMatch(rec.im, '1FFF*FFF2') THEN
+      RAISE EXCEPTION
+        'SQL/MM Spatial exception - coincident edge';
+    END IF;
 
-       myaz = ST_Azimuth(ST_EndPoint(acurve), ST_PointN(acurve, ST_NumPoints(acurve)-1));
-       RAISE NOTICE 'My end-segment azimuth: %', myaz;
-       FOR rec IN EXECUTE 'SELECT '
-               || 'edge_id, end_node, start_node, geom'
-               || ' FROM '
-               || quote_ident(atopology)
-               || '.edge_data '
-               || ' WHERE '
-               || ' end_node = ' || anothernode
-               || ' OR '
-               || ' start_node = ' || anothernode
-       LOOP
+    -- NOT IN THE SPECS: geometry touches an edge
+    IF ST_RelateMatch(rec.im, '1********') THEN
+      RAISE EXCEPTION
+        'Spatial exception - geometry intersects edge %', rec.edge_id;
+    END IF;
+
+    IF ST_RelateMatch(rec.im, 'T********') THEN
+      RAISE EXCEPTION
+        'SQL/MM Spatial exception - geometry crosses an edge';
+    END IF;
 
-               IF rec.start_node = anothernode THEN
-                       --
-                       -- Edge starts at our node, we compute
-                       -- azimuth from node to its second point
-                       --
-                       az = ST_Azimuth(ST_EndPoint(acurve),
-                               ST_PointN(rec.geom, 2));
+  END LOOP;
 
-                       RAISE NOTICE 'Edge % starts at node % - azimuth %',
-                               rec.edge_id, rec.start_node, az;
-               END IF;
+  ---------------------------------------------------------------
+  --
+  -- All checks passed, time to extract informations about
+  -- endpoints:
+  --
+  --  next_left_edge
+  --  next_right_edge
+  --  left_face
+  --  right_face
+  --
+  ---------------------------------------------------------------
 
-               IF rec.end_node = anothernode THEN
-                       --
-                       -- Edge ends at our node, we compute
-                       -- azimuth from node to its second-last point
-                       --
-                       az = ST_Azimuth(ST_EndPoint(acurve),
-                               ST_PointN(rec.geom, ST_NumPoints(rec.geom)-1));
+  --
+  --
+  -- Compute next_left_edge 
+  --
+  -- We fetch all edges with an endnode equal to
+  -- this edge end_node (anothernode).
+  -- For each edge we compute azimuth of the segment(s).
+  -- Of interest are the edges with closest (smaller
+  -- and bigger) azimuths then the azimuth of
+  -- this edge last segment.
+  --
 
-                       RAISE NOTICE 'Edge % ends at node % - azimuth %',
-                               rec.edge_id, rec.end_node, az;
-               END IF;
-       END LOOP;
+  myaz = ST_Azimuth(ST_EndPoint(acurve), ST_PointN(acurve, ST_NumPoints(acurve)-1));
+  RAISE NOTICE 'My end-segment azimuth: %', myaz;
+  FOR rec IN EXECUTE 'SELECT '
+    || 'edge_id, end_node, start_node, geom'
+    || ' FROM '
+    || quote_ident(atopology)
+    || '.edge_data '
+    || ' WHERE '
+    || ' end_node = ' || anothernode
+    || ' OR '
+    || ' start_node = ' || anothernode
+  LOOP
+
+    IF rec.start_node = anothernode THEN
+      --
+      -- Edge starts at our node, we compute
+      -- azimuth from node to its second point
+      --
+      az = ST_Azimuth(ST_EndPoint(acurve),
+        ST_PointN(rec.geom, 2));
+
+      RAISE NOTICE 'Edge % starts at node % - azimuth %',
+        rec.edge_id, rec.start_node, az;
+    END IF;
+
+    IF rec.end_node = anothernode THEN
+      --
+      -- Edge ends at our node, we compute
+      -- azimuth from node to its second-last point
+      --
+      az = ST_Azimuth(ST_EndPoint(acurve),
+        ST_PointN(rec.geom, ST_NumPoints(rec.geom)-1));
+
+      RAISE NOTICE 'Edge % ends at node % - azimuth %',
+        rec.edge_id, rec.end_node, az;
+    END IF;
+  END LOOP;
 
 
-       RAISE EXCEPTION 'Not implemented yet';
+  RAISE EXCEPTION 'Not implemented yet';
 END
 $$
 LANGUAGE 'plpgsql' VOLATILE;
index 4ff3dad3d3cd8977978a4ac595cd0b47c5d70dc2..41a6dadeb3d2f3c2b0639336b2ccb855a717d142 100644 (file)
@@ -28,6 +28,7 @@ TESTS = regress/legacy_validate.sql regress/legacy_predicate.sql \
        regress/addedge.sql regress/addface.sql \
        regress/addface2.5d.sql \
        regress/polygonize.sql \
+       regress/st_addedgenewfaces.sql \
        regress/st_getfacegeometry.sql \
        regress/st_getfaceedges.sql \
        regress/st_modedgeheal.sql \
diff --git a/topology/test/regress/st_addedgenewfaces.sql b/topology/test/regress/st_addedgenewfaces.sql
new file mode 100644 (file)
index 0000000..11cb5c3
--- /dev/null
@@ -0,0 +1,44 @@
+set client_min_messages to ERROR;
+
+\i load_topology.sql
+
+
+-- Endpoint / node mismatch
+SELECT topology.ST_AddEdgeNewFaces('city_data', 7, 6,
+ 'LINESTRING(36 38,57 33)');
+SELECT topology.ST_AddEdgeNewFaces('city_data', 5, 7,
+ 'LINESTRING(36 38,57 33)');
+
+-- Crosses a node
+SELECT topology.ST_AddEdgeNewFaces('city_data', 5, 6,
+ 'LINESTRING(36 38, 41 40, 57 33)');
+
+-- Non-existent node 
+SELECT topology.ST_AddEdgeNewFaces('city_data', 5, 60000,
+ 'LINESTRING(36 38,57 33)');
+SELECT topology.ST_AddEdgeNewFaces('city_data', 60000, 6,
+ 'LINESTRING(36 38,57 33)');
+
+-- Non-simple curve
+SELECT topology.ST_AddEdgeNewFaces('city_data', 5, 5,
+ 'LINESTRING(36 38, 40 50, 36 38)');
+
+-- Coincident edge
+SELECT topology.ST_AddEdgeNewFaces('city_data', 18, 19,
+ 'LINESTRING(35 22,47 22)');
+
+-- Crosses an edge
+SELECT topology.ST_AddEdgeNewFaces('city_data', 5, 6,
+ 'LINESTRING(36 38, 40 50, 57 33)');
+
+-- Touches an existing edge
+SELECT 'O', topology.ST_AddEdgeNewFaces('city_data', 5, 6,
+ 'LINESTRING(36 38,45 32,57 33)');
+
+-- Shares a portion of an existing edge
+SELECT 'O', topology.ST_AddEdgeNewFaces('city_data', 5, 6,
+ 'LINESTRING(36 38,38 35,57 33)');
+
+-- TODO: check succeeding ones...
+
+SELECT topology.DropTopology('city_data');
diff --git a/topology/test/regress/st_addedgenewfaces_expected b/topology/test/regress/st_addedgenewfaces_expected
new file mode 100644 (file)
index 0000000..7c044d1
--- /dev/null
@@ -0,0 +1,17 @@
+BEGIN
+t
+8
+22
+26
+COMMIT
+ERROR:  SQL/MM Spatial exception - start node not geometry start point.
+ERROR:  SQL/MM Spatial exception - end node not geometry end point.
+ERROR:  SQL/MM Spatial exception - geometry crosses a node
+ERROR:  SQL/MM Spatial exception - non-existent node
+ERROR:  SQL/MM Spatial exception - non-existent node
+ERROR:  SQL/MM Spatial exception - curve not simple
+ERROR:  SQL/MM Spatial exception - coincident edge
+ERROR:  SQL/MM Spatial exception - geometry crosses an edge
+ERROR:  SQL/MM Spatial exception - geometry crosses an edge
+ERROR:  Spatial exception - geometry intersects edge 4
+Topology 'city_data' dropped