From: Sandro Santilli Date: Thu, 20 Aug 2015 16:24:23 +0000 (+0000) Subject: Implement ST_RemoveIsoEdge in C X-Git-Tag: 2.2.0rc1~135 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=440899a78e2988fb4f1d8677e71976719e8812e6;p=postgis Implement ST_RemoveIsoEdge in C Adds lwt_RemIsoEdge to liblwgeom Funded by Tuscany Region (Italy) - SITA (CIG: 60351023B8) git-svn-id: http://svn.osgeo.org/postgis/trunk@13953 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/liblwgeom/TODO b/liblwgeom/TODO index f47ff1e95..fe68c6c56 100644 --- a/liblwgeom/TODO +++ b/liblwgeom/TODO @@ -16,6 +16,7 @@ lwt_GetFaceGeometry X lwt_GetFaceEdges X lwt_ChangeEdgeGeom X lwt_RemoveIsoNode X +lwt_RemoveIsoEdge X lwt_MoveIsoNode X lwt_RemEdgeModFace X lwt_RemEdgeNewFace X diff --git a/liblwgeom/liblwgeom_topo.h b/liblwgeom/liblwgeom_topo.h index ad33ebabb..461aef0f2 100644 --- a/liblwgeom/liblwgeom_topo.h +++ b/liblwgeom/liblwgeom_topo.h @@ -1113,13 +1113,26 @@ int lwt_MoveIsoNode(LWT_TOPOLOGY* topo, * For ST_RemoveIsoNode * * @param topo the topology to operate on - * @param node the identifier of the nod to be moved + * @param node the identifier of the node to be moved * @return 0 on success, -1 on error * (liblwgeom error handler will be invoked with error message) * */ int lwt_RemoveIsoNode(LWT_TOPOLOGY* topo, LWT_ELEMID node); +/** + * Remove an isolated edge + * + * For ST_RemIsoEdge + * + * @param topo the topology to operate on + * @param edge the identifier of the edge to be moved + * @return 0 on success, -1 on error + * (liblwgeom error handler will be invoked with error message) + * + */ +int lwt_RemIsoEdge(LWT_TOPOLOGY* topo, LWT_ELEMID edge); + /** * Add an isolated edge connecting two existing isolated nodes * diff --git a/liblwgeom/lwgeom_topo.c b/liblwgeom/lwgeom_topo.c index f82865ba6..8df4b2465 100644 --- a/liblwgeom/lwgeom_topo.c +++ b/liblwgeom/lwgeom_topo.c @@ -3493,7 +3493,7 @@ lwt_RemoveIsoNode(LWT_TOPOLOGY* topo, LWT_ELEMID nid) n = lwt_be_deleteNodesById( topo, &nid, n ); if ( n == -1 ) { - lwerror("SQL/MM Spatial exception - not isolated node"); + lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface)); return -1; } if ( n != 1 ) @@ -3509,6 +3509,84 @@ lwt_RemoveIsoNode(LWT_TOPOLOGY* topo, LWT_ELEMID nid) return 0; /* success */ } +int +lwt_RemIsoEdge(LWT_TOPOLOGY* topo, LWT_ELEMID id) +{ + LWT_ISO_EDGE deledge; + LWT_ISO_EDGE *edge; + LWT_ELEMID nid[2]; + int n = 1; + int i; + + edge = lwt_be_getEdgeById( topo, &id, &n, LWT_COL_EDGE_START_NODE| + LWT_COL_EDGE_END_NODE | + LWT_COL_EDGE_FACE_LEFT | + LWT_COL_EDGE_FACE_RIGHT ); + if ( ! edge ) + { + lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface)); + return -1; + } + if ( ! n ) + { + lwerror("SQL/MM Spatial exception - non-existent edge"); + return -1; + } + if ( n > 1 ) + { + lwfree(edge); + lwerror("Corrupted topology: more than a single edge have id %" + LWTFMT_ELEMID, id); + return -1; + } + + if ( edge[0].face_left != edge[0].face_right ) + { + lwfree(edge); + lwerror("SQL/MM Spatial exception - not isolated edge"); + return -1; + } + + nid[0] = edge[0].start_node; + nid[1] = edge[0].end_node; + lwfree(edge); + + n = 2; + edge = lwt_be_getEdgeByNode( topo, nid, &n, LWT_COL_EDGE_EDGE_ID ); + if ( n == -1 ) + { + lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface)); + return -1; + } + for ( i=0; ibe_iface)); + return -1; + } + if ( n != 1 ) + { + lwerror("Unexpected error: %d edges deleted when expecting 1", n); + return -1; + } + + /* TODO: notify to caller about edge being removed ? + * See https://trac.osgeo.org/postgis/ticket/3248 + */ + + return 0; /* success */ +} + /* Used by _lwt_RemEdge to update edge face ref on healing * * @param of old face id (never 0 as you cannot remove face 0) diff --git a/topology/postgis_topology.c b/topology/postgis_topology.c index 3b3d43cf6..c1ebf598b 100644 --- a/topology/postgis_topology.c +++ b/topology/postgis_topology.c @@ -3548,6 +3548,67 @@ Datum ST_RemoveIsoNode(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(cstring2text(buf)); } +/* ST_RemIsoEdge(atopology, anedge) */ +Datum ST_RemIsoEdge(PG_FUNCTION_ARGS); +PG_FUNCTION_INFO_V1(ST_RemIsoEdge); +Datum ST_RemIsoEdge(PG_FUNCTION_ARGS) +{ + text* toponame_text; + char buf[64]; + char* toponame; + int ret; + LWT_ELEMID node_id; + LWT_TOPOLOGY *topo; + + if ( PG_ARGISNULL(0) || PG_ARGISNULL(1) ) { + lwpgerror("SQL/MM Spatial exception - null argument"); + PG_RETURN_NULL(); + } + + toponame_text = PG_GETARG_TEXT_P(0); + toponame = text2cstring(toponame_text); + PG_FREE_IF_COPY(toponame_text, 0); + + node_id = PG_GETARG_INT32(1) ; + + if ( SPI_OK_CONNECT != SPI_connect() ) { + lwpgerror("Could not connect to SPI"); + PG_RETURN_NULL(); + } + be_data.data_changed = false; + + topo = lwt_LoadTopology(be_iface, toponame); + pfree(toponame); + if ( ! topo ) { + /* should never reach this point, as lwerror would raise an exception */ + SPI_finish(); + PG_RETURN_NULL(); + } + + POSTGIS_DEBUG(1, "Calling lwt_RemIsoEdge"); + ret = lwt_RemIsoEdge(topo, node_id); + POSTGIS_DEBUG(1, "lwt_RemIsoEdge returned"); + lwt_FreeTopology(topo); + + if ( ret == -1 ) { + /* should never reach this point, as lwerror would raise an exception */ + SPI_finish(); + PG_RETURN_NULL(); + } + + /* TODO: check if any TopoGeometry exists including this point in + * its definition ! */ + + SPI_finish(); + + if ( snprintf(buf, 64, "Isolated edge " INT64_FORMAT + " removed", node_id) >= 64 ) + { + buf[63] = '\0'; + } + PG_RETURN_TEXT_P(cstring2text(buf)); +} + /* ST_MoveIsoNode(atopology, anode, apoint) */ Datum ST_MoveIsoNode(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(ST_MoveIsoNode); diff --git a/topology/sql/sqlmm.sql.in b/topology/sql/sqlmm.sql.in index 7046a3216..2ec3c63c0 100644 --- a/topology/sql/sqlmm.sql.in +++ b/topology/sql/sqlmm.sql.in @@ -198,67 +198,8 @@ CREATE OR REPLACE FUNCTION topology.ST_RemIsoNode(varchar, integer) -- CREATE OR REPLACE FUNCTION topology.ST_RemoveIsoEdge(atopology varchar, anedge integer) RETURNS TEXT AS -$$ -DECLARE - edge RECORD; - rec RECORD; - ok BOOL; -BEGIN - - -- - -- Atopology and anedge are required - -- - IF atopology IS NULL OR anedge IS NULL THEN - RAISE EXCEPTION - 'SQL/MM Spatial exception - null argument'; - END IF; - - -- - -- Check edge existance - -- - ok = false; - FOR edge IN EXECUTE 'SELECT * FROM ' - || quote_ident(atopology) || '.edge_data ' || - ' WHERE edge_id = ' || anedge - LOOP - ok = true; - END LOOP; - IF NOT ok THEN - RAISE EXCEPTION - 'SQL/MM Spatial exception - non-existent edge'; - END IF; - - -- - -- Check node isolation - -- - IF edge.left_face != edge.right_face THEN - RAISE EXCEPTION - 'SQL/MM Spatial exception - not isolated edge'; - END IF; - - FOR rec IN EXECUTE 'SELECT * FROM ' - || quote_ident(atopology) || '.edge_data ' - || ' WHERE edge_id != ' || anedge - || ' AND ( start_node = ' || edge.start_node - || ' OR start_node = ' || edge.end_node - || ' OR end_node = ' || edge.start_node - || ' OR end_node = ' || edge.end_node - || ' ) ' - LOOP - RAISE EXCEPTION - 'SQL/MM Spatial exception - not isolated edge'; - END LOOP; - - -- - -- Delete the edge - -- - EXECUTE 'DELETE FROM ' || quote_ident(atopology) || '.edge_data ' - || ' WHERE edge_id = ' || anedge; - - RETURN 'Isolated edge ' || anedge || ' removed'; -END -$$ -LANGUAGE 'plpgsql' VOLATILE; + 'MODULE_PATHNAME','ST_RemIsoEdge' + LANGUAGE 'c' VOLATILE; --} ST_RemoveIsoEdge --{