Implement ST_RemoveIsoEdge in C
authorSandro Santilli <strk@keybit.net>
Thu, 20 Aug 2015 16:24:23 +0000 (16:24 +0000)
committerSandro Santilli <strk@keybit.net>
Thu, 20 Aug 2015 16:24:23 +0000 (16:24 +0000)
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

liblwgeom/TODO
liblwgeom/liblwgeom_topo.h
liblwgeom/lwgeom_topo.c
topology/postgis_topology.c
topology/sql/sqlmm.sql.in

index f47ff1e959a90ee651802a3e048f0ee8916c09e5..fe68c6c56d9092bdd8b71c7e8afba079050debb2 100644 (file)
@@ -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
index ad33ebabb6bb97c52ab7d129c65b01e14f1f2024..461aef0f287f9695af7ab46994be8f7e535026e6 100644 (file)
@@ -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
  *
index f82865ba624254f5fa33d38cd6a835853b3e8ac1..8df4b246500ee1c70b36eb3ba5c41a428d900435 100644 (file)
@@ -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; i<n; ++i )
+  {
+    if ( edge[i].edge_id == id ) continue;
+    lwfree(edge);
+    lwerror("SQL/MM Spatial exception - not isolated edge");
+    return -1;
+  }
+  if ( edge ) lwfree(edge);
+
+  deledge.edge_id = id;
+  n = lwt_be_deleteEdges( topo, &deledge, LWT_COL_EDGE_EDGE_ID );
+  if ( n == -1 )
+  {
+    lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_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)
index 3b3d43cf63e307ca16effa561bcd938d4755e86a..c1ebf598b1ed19f0539847bba1e7fdc7a4e79a77 100644 (file)
@@ -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);
index 7046a3216748e21cefb1d100e3b144e3b8a4582e..2ec3c63c07a6e700530f04a1a50487aa34566e51 100644 (file)
@@ -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
 
 --{