From: Sandro Santilli Date: Thu, 12 May 2011 16:14:53 +0000 (+0000) Subject: topology.ST_AddEdgeNewFaces : tabs to spaces, named arguments, code cleanups and... X-Git-Tag: 2.0.0alpha1~1674 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6e3318a18c16740b8e52f65d3331f3601bc4078b;p=postgis topology.ST_AddEdgeNewFaces : tabs to spaces, named arguments, code cleanups and improved checks, tests for invalid calls [RT-SIGTA] git-svn-id: http://svn.osgeo.org/postgis/trunk@7134 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/topology/sql/sqlmm.sql b/topology/sql/sqlmm.sql index 8b59eec53..8ef9b8e19 100644 --- a/topology/sql/sqlmm.sql +++ b/topology/sql/sqlmm.sql @@ -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; diff --git a/topology/test/Makefile b/topology/test/Makefile index 4ff3dad3d..41a6dadeb 100644 --- a/topology/test/Makefile +++ b/topology/test/Makefile @@ -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 index 000000000..11cb5c3ae --- /dev/null +++ b/topology/test/regress/st_addedgenewfaces.sql @@ -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 index 000000000..7c044d170 --- /dev/null +++ b/topology/test/regress/st_addedgenewfaces_expected @@ -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