]> granicus.if.org Git - postgis/commitdiff
Implement ST_NewEdgesSplit in C
authorSandro Santilli <strk@keybit.net>
Mon, 29 Jun 2015 14:07:31 +0000 (14:07 +0000)
committerSandro Santilli <strk@keybit.net>
Mon, 29 Jun 2015 14:07:31 +0000 (14:07 +0000)
Involved adding a new "deleteEdges" callback.

Funded by Tuscany Region (Italy) - SITA (CIG: 60351023B8)

git-svn-id: http://svn.osgeo.org/postgis/trunk@13738 b70326c6-7e19-0410-871a-916f4a2858ee

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

index f09225274a00c8d72f17e7961a37d1e8f12a1886..d2057c98483fbe4fd7b63964ea26a7c2e86eba7f 100644 (file)
@@ -398,6 +398,22 @@ typedef struct LWT_BE_CALLBACKS_T {
       LWT_ELEMID split_edge, LWT_ELEMID new_edge1, LWT_ELEMID new_edge2
   );
 
+  /**
+   * Delete edges
+   *
+   * @param topo the topology to act upon
+   * @param sel_edge an LWT_ISO_EDGE object with selecting fields set.
+   * @param sel_fields fields used to select edges to be deleted,
+   *                   see LWT_COL_EDGE_* macros
+   *
+   * @return number of edges being deleted or -1 on error
+   *         (@see lastErroMessage)
+   */
+  int (*deleteEdges) (
+      const LWT_BE_TOPOLOGY* topo,
+      const LWT_ISO_EDGE* sel_edge, int sel_fields
+  );
+
 } LWT_BE_CALLBACKS;
 
 
@@ -815,7 +831,7 @@ void lwt_ChangeEdgeGeom(LWT_TOPOLOGY* topo, LWT_ELEMID edge, LWGEOM* geom);
  * @param edge identifier of the edge to be split
  * @param pt geometry of the new node
  * @param skipChecks if non-zero skips consistency checks
- *                   (coincident node)
+ *                   (coincident node, point not on edge...)
  * @return the id of newly created node, or -1 on error
  *         (liblwgeom error handler will be invoked with error message)
  *
@@ -830,10 +846,12 @@ LWT_ELEMID lwt_ModEdgeSplit(LWT_TOPOLOGY* topo, LWT_ELEMID edge, LWPOINT* pt, in
  * @param topo the topology to operate on
  * @param edge identifier of the edge to be split
  * @param pt geometry of the new node
+ * @param skipChecks if non-zero skips consistency checks
+ *                   (coincident node, point not on edge...)
  * @return the id of newly created node
  *
  */
-LWT_ELEMID lwt_NewEdgesSplit(LWT_TOPOLOGY* topo, LWT_ELEMID edge, LWPOINT* pt);
+LWT_ELEMID lwt_NewEdgesSplit(LWT_TOPOLOGY* topo, LWT_ELEMID edge, LWPOINT* pt, int skipChecks);
 
 /**
  * Merge two edges, modifying the first and deleting the second
index aea576f98fa9093b17f36af5bb91d4b2b4a50f2b..c6fc38d5ea1d2d79bcc8907af21ade6ba511ab23 100644 (file)
@@ -53,6 +53,8 @@ int
 lwt_be_insertEdges(LWT_TOPOLOGY* topo, LWT_ISO_EDGE* edge, int numelems);
 int
 lwt_be_updateEdges(LWT_TOPOLOGY* topo, const LWT_ISO_EDGE* sel_edge, int sel_fields, const LWT_ISO_EDGE* upd_edge, int upd_fields, const LWT_ISO_EDGE* exc_edge, int exc_fields);
+int
+lwt_be_deleteEdges(LWT_TOPOLOGY* topo, const LWT_ISO_EDGE* sel_edge, int sel_fields);
 
 LWT_ELEMID lwt_be_getFaceContainingPoint(LWT_TOPOLOGY* topo, LWPOINT* pt);
 
index 963adfb5caa4535577b5596a63402fb73469959b..41f6a68ccc3d72bf327bd8e1d5488563c59af8c7 100644 (file)
@@ -160,6 +160,14 @@ lwt_be_updateEdges(LWT_TOPOLOGY* topo,
                           exc_edge, exc_fields);
 }
 
+int
+lwt_be_deleteEdges(LWT_TOPOLOGY* topo,
+  const LWT_ISO_EDGE* sel_edge, int sel_fields
+)
+{
+  CBT2(topo, deleteEdges, sel_edge, sel_fields);
+}
+
 LWT_ELEMID
 lwt_be_getFaceContainingPoint(LWT_TOPOLOGY* topo, LWPOINT* pt)
 {
@@ -496,3 +504,177 @@ lwt_ModEdgeSplit( LWT_TOPOLOGY* topo, LWT_ELEMID edge,
   /* return new node id */
   return node.node_id;
 }
+
+LWT_ELEMID
+lwt_NewEdgesSplit( LWT_TOPOLOGY* topo, LWT_ELEMID edge,
+                   LWPOINT* pt, int skipISOChecks )
+{
+  LWT_ISO_NODE node;
+  LWT_ISO_EDGE* oldedge = NULL;
+  LWCOLLECTION *split_col;
+  const LWGEOM *oldedge_geom;
+  const LWGEOM *newedge_geom;
+  LWT_ISO_EDGE newedges[2];
+  //LWT_ISO_EDGE newedge1, newedge2;
+  LWT_ISO_EDGE seledge, updedge;
+  int ret;
+
+  split_col = _lwt_EdgeSplit( topo, edge, pt, skipISOChecks, &oldedge );
+  if ( ! split_col ) return -1; /* should have raised an exception */
+  oldedge_geom = split_col->geoms[0];
+  newedge_geom = split_col->geoms[1];
+
+  /* Add new node, getting new id back */
+  node.node_id = -1;
+  node.containing_face = -1; /* means not-isolated */
+  node.geom = pt;
+  if ( ! lwt_be_insertNodes(topo, &node, 1) )
+  {
+    lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
+    return -1;
+  }
+  if (node.node_id == -1) {
+    /* should have been set by backend */
+    lwerror("Backend coding error: "
+            "insertNodes callback did not return node_id");
+    return -1;
+  }
+
+  /* Delete the old edge */
+  seledge.edge_id = edge;
+  ret = lwt_be_deleteEdges(topo, &seledge, LWT_COL_EDGE_EDGE_ID);
+  if ( ret == -1 ) {
+    lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
+    return -1;
+  }
+
+  /* Get new edges identifiers */
+  newedges[0].edge_id = lwt_be_getNextEdgeId(topo);
+  if ( newedges[0].edge_id == -1 ) {
+    lwcollection_release(split_col);
+    lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
+    return -1;
+  }
+  newedges[1].edge_id = lwt_be_getNextEdgeId(topo);
+  if ( newedges[1].edge_id == -1 ) {
+    lwcollection_release(split_col);
+    lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
+    return -1;
+  }
+
+  /* Define the first new edge (to new node) */
+  newedges[0].start_node = oldedge->start_node;
+  newedges[0].end_node = node.node_id;
+  newedges[0].face_left = oldedge->face_left;
+  newedges[0].face_right = oldedge->face_right;
+  newedges[0].next_left = newedges[1].edge_id;
+  if ( oldedge->next_right == edge )
+    newedges[0].next_right = newedges[0].edge_id;
+  else if ( oldedge->next_right == -edge )
+    newedges[0].next_right = -newedges[1].edge_id;
+  else
+    newedges[0].next_right = oldedge->next_right;
+  newedges[0].geom = lwgeom_as_lwline(oldedge_geom);
+  /* lwgeom_split of a line should only return lines ... */
+  if ( ! newedges[0].geom ) {
+    lwcollection_release(split_col);
+    lwerror("first geometry in lwgeom_split output is not a line");
+    return -1;
+  }
+
+  /* Define the second new edge (from new node) */
+  newedges[1].start_node = node.node_id;
+  newedges[1].end_node = oldedge->end_node;
+  newedges[1].face_left = oldedge->face_left;
+  newedges[1].face_right = oldedge->face_right;
+  newedges[1].next_right = -newedges[0].edge_id;
+  if ( oldedge->next_left == -edge )
+    newedges[1].next_left = -newedges[1].edge_id;
+  else if ( oldedge->next_left == edge )
+    newedges[1].next_left = newedges[0].edge_id;
+  else
+    newedges[1].next_left = oldedge->next_left;
+  newedges[1].geom = lwgeom_as_lwline(newedge_geom);
+  /* lwgeom_split of a line should only return lines ... */
+  if ( ! newedges[1].geom ) {
+    lwcollection_release(split_col);
+    lwerror("second geometry in lwgeom_split output is not a line");
+    return -1;
+  }
+
+  /* Insert both new edges */
+  ret = lwt_be_insertEdges(topo, newedges, 2);
+  if ( ret == -1 ) {
+    lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
+    return -1;
+  } else if ( ret == 0 ) {
+    lwcollection_release(split_col);
+    lwerror("Insertion of split edge failed (no reason)");
+    return -1;
+  }
+
+  /* Update all next edge references pointing to old edge id */
+
+  updedge.next_right = newedges[1].edge_id;
+  seledge.next_right = edge;
+  seledge.start_node = oldedge->start_node;
+  ret = lwt_be_updateEdges(topo,
+      &seledge, LWT_COL_EDGE_NEXT_RIGHT|LWT_COL_EDGE_START_NODE,
+      &updedge, LWT_COL_EDGE_NEXT_RIGHT,
+      NULL, 0);
+  if ( ret == -1 ) {
+    lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
+    return -1;
+  }
+
+  updedge.next_right = -newedges[0].edge_id;
+  seledge.next_right = -edge;
+  seledge.start_node = oldedge->end_node;
+  ret = lwt_be_updateEdges(topo,
+      &seledge, LWT_COL_EDGE_NEXT_RIGHT|LWT_COL_EDGE_START_NODE,
+      &updedge, LWT_COL_EDGE_NEXT_RIGHT,
+      NULL, 0);
+  if ( ret == -1 ) {
+    lwcollection_release(split_col);
+    lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
+    return -1;
+  }
+
+  updedge.next_left = newedges[0].edge_id;
+  seledge.next_left = edge;
+  seledge.end_node = oldedge->start_node;
+  ret = lwt_be_updateEdges(topo,
+      &seledge, LWT_COL_EDGE_NEXT_LEFT|LWT_COL_EDGE_END_NODE,
+      &updedge, LWT_COL_EDGE_NEXT_LEFT,
+      NULL, 0);
+  if ( ret == -1 ) {
+    lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
+    return -1;
+  }
+
+  updedge.next_left = -newedges[1].edge_id;
+  seledge.next_left = -edge;
+  seledge.end_node = oldedge->end_node;
+  ret = lwt_be_updateEdges(topo,
+      &seledge, LWT_COL_EDGE_NEXT_LEFT|LWT_COL_EDGE_END_NODE,
+      &updedge, LWT_COL_EDGE_NEXT_LEFT,
+      NULL, 0);
+  if ( ret == -1 ) {
+    lwcollection_release(split_col);
+    lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
+    return -1;
+  }
+
+  /* Update TopoGeometries composition -- TODO */
+  ret = lwt_be_updateTopoGeomEdgeSplit(topo, oldedge->edge_id, newedges[0].edge_id, newedges[1].edge_id);
+  if ( ! ret ) {
+    lwcollection_release(split_col);
+    lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
+    return -1;
+  }
+
+  lwcollection_release(split_col);
+
+  /* return new node id */
+  return node.node_id;
+}
index 70476ca07b30659877d2f84f0035e71362b8c816..40cdf97381561ac97e4d295fa58300e7b44e186e 100644 (file)
@@ -767,6 +767,34 @@ cb_updateEdges( const LWT_BE_TOPOLOGY* topo,
   return SPI_processed;
 }
 
+static int
+cb_deleteEdges( const LWT_BE_TOPOLOGY* topo,
+      const LWT_ISO_EDGE* sel_edge, int sel_fields )
+{
+       int spi_result;
+  StringInfoData sqldata;
+  StringInfo sql = &sqldata;
+
+  initStringInfo(sql);
+  appendStringInfo(sql, "DELETE FROM \"%s\".edge_data WHERE ", topo->name);
+  addEdgeUpdate( sql, sel_edge, sel_fields, 0, updSel );
+
+  /* lwpgnotice("cb_deleteEdges: %s", sql->data); */
+
+  spi_result = SPI_execute( sql->data, false, 0 );
+  if ( spi_result != SPI_OK_DELETE )
+  {
+               cberror(topo->be_data, "unexpected return (%d) from query execution: %s",
+            spi_result, sql->data);
+         return -1;
+  }
+  pfree(sqldata.data);
+
+  lwpgnotice("cb_deleteEdges: delete query processed %d rows", SPI_processed);
+
+  return SPI_processed;
+}
+
 static LWT_ELEMID
 cb_getNextEdgeId( const LWT_BE_TOPOLOGY* topo )
 {
@@ -819,15 +847,15 @@ cb_updateTopoGeomEdgeSplit ( const LWT_BE_TOPOLOGY* topo,
   } else {
     appendStringInfoString(sql, "DELETE");
   }
-  appendStringInfo(sql, " FROM \"%s\".relation r, topology.layer l WHERE "
+  appendStringInfo( sql, " FROM \"%s\".relation r %s topology.layer l WHERE "
     "l.topology_id = %d AND l.level = 0 AND l.layer_id = r.layer_id "
     "AND abs(r.element_id) = %lld AND r.element_type = 2",
-    topo->name, topo->id, split_edge);
+    topo->name, (new_edge2 == -1 ? "," : "USING" ), topo->id, split_edge );
   if ( new_edge2 != -1 ) {
     appendStringInfo(sql, " RETURNING %s", proj);
   }
 
-  spi_result = SPI_execute(sql->data, true, 0);
+  spi_result = SPI_execute(sql->data, new_edge2 == -1, 0);
   if ( spi_result != ( new_edge2 == -1 ? SPI_OK_SELECT : SPI_OK_DELETE_RETURNING ) ) {
                cberror(topo->be_data, "unexpected return (%d) from query execution: %s",
             spi_result, sql->data);
@@ -964,7 +992,8 @@ LWT_BE_CALLBACKS be_callbacks = {
     cb_updateEdges,
     NULL, /* getFacesById */
     cb_getFaceContainingPoint,
-    cb_updateTopoGeomEdgeSplit
+    cb_updateTopoGeomEdgeSplit,
+    cb_deleteEdges
 };
 
 
@@ -1074,6 +1103,71 @@ Datum ST_ModEdgeSplit(PG_FUNCTION_ARGS)
   PG_RETURN_INT32(node_id);
 }
 
+/*  ST_NewEdgesSplit(atopology, anedge, apoint) */
+Datum ST_NewEdgesSplit(PG_FUNCTION_ARGS);
+PG_FUNCTION_INFO_V1(ST_NewEdgesSplit);
+Datum ST_NewEdgesSplit(PG_FUNCTION_ARGS)
+{
+  text* toponame_text;
+  char* toponame;
+  LWT_ELEMID edge_id;
+  LWT_ELEMID node_id;
+  GSERIALIZED *geom;
+  LWGEOM *lwgeom;
+  LWPOINT *pt;
+  LWT_TOPOLOGY *topo;
+
+  if ( PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2) ) {
+    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);
+
+  edge_id = PG_GETARG_INT32(1) ;
+
+  geom = PG_GETARG_GSERIALIZED_P(2);
+  lwgeom = lwgeom_from_gserialized(geom);
+  pt = lwgeom_as_lwpoint(lwgeom);
+  if ( ! pt ) {
+    lwgeom_free(lwgeom);
+         PG_FREE_IF_COPY(geom, 2);
+    lwpgerror("ST_NewEdgesSplit third argument must be a point geometry");
+    PG_RETURN_NULL();
+  }
+
+  if ( SPI_OK_CONNECT != SPI_connect() ) {
+    lwpgerror("Could not connect to SPI");
+    PG_RETURN_NULL();
+  }
+
+  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_NewEdgesSplit");
+  node_id = lwt_NewEdgesSplit(topo, edge_id, pt, 0);
+  POSTGIS_DEBUG(1, "lwt_NewEdgesSplit returned");
+  lwgeom_free(lwgeom);
+  PG_FREE_IF_COPY(geom, 3);
+  lwt_FreeTopology(topo);
+
+  if ( node_id == -1 ) {
+    /* should never reach this point, as lwerror would raise an exception */
+    SPI_finish();
+    PG_RETURN_NULL();
+  }
+
+  SPI_finish();
+  PG_RETURN_INT32(node_id);
+}
+
 /*  ST_AddIsoNode(atopology, aface, apoint) */
 Datum ST_AddIsoNode(PG_FUNCTION_ARGS);
 PG_FUNCTION_INFO_V1(ST_AddIsoNode);
index 564085ed7e61872d410c6c1295e195b7ffb88181..3bc9232cfe9a0150982c79baf53d4763107a9611 100644 (file)
@@ -1698,289 +1698,8 @@ LANGUAGE 'plpgsql' VOLATILE;
 --
 CREATE OR REPLACE FUNCTION topology.ST_NewEdgesSplit(atopology varchar, anedge integer, apoint geometry)
   RETURNS INTEGER AS
-$$
-DECLARE
-  oldedge RECORD;
-  rec RECORD;
-  tmp integer;
-  topoid integer;
-  nodeid integer;
-  nodepos float8;
-  edgeid1 integer;
-  edgeid2 integer;
-  edge1 geometry;
-  edge2 geometry;
-  ok BOOL;
-BEGIN
-
-  --
-  -- All args required
-  -- 
-  IF atopology IS NULL OR anedge IS NULL OR apoint IS NULL THEN
-    RAISE EXCEPTION
-     'SQL/MM Spatial exception - null argument';
-  END IF;
-  
-  -- Get topology id
-  BEGIN
-    SELECT id FROM topology.topology
-      INTO STRICT topoid WHERE name = atopology;
-    EXCEPTION
-      WHEN NO_DATA_FOUND THEN
-        RAISE EXCEPTION 'SQL/MM Spatial exception - invalid topology name';
-  END;
-
-  --
-  -- Check edge existance
-  -- 
-  ok = false;
-  FOR oldedge 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 that given point is Within(anedge.geom)
-  -- 
-  IF NOT ST_Within(apoint, oldedge.geom) THEN
-    RAISE EXCEPTION
-      'SQL/MM Spatial exception - point not on edge';
-  END IF;
-
-  --
-  -- Check if a coincident node already exists
-  --
-  FOR rec IN EXECUTE 'SELECT node_id FROM '
-    || quote_ident(atopology) || '.node WHERE geom && $1 '
-    || ' AND ST_X(geom) = ST_X($1) AND ST_Y(geom) = ST_Y($1)'
-    USING apoint
-  LOOP
-    RAISE EXCEPTION
-     'SQL/MM Spatial exception - coincident node';
-  END LOOP;
-
-  --
-  -- Get new node id
-  --
-  FOR rec IN EXECUTE 'SELECT nextval(''' ||
-    atopology || '.node_node_id_seq'')'
-  LOOP
-    nodeid = rec.nextval;
-  END LOOP;
-
-  --RAISE NOTICE 'Next node id = % ', nodeid;
-
-  --
-  -- Add the new node 
-  --
-  EXECUTE 'INSERT INTO ' || quote_ident(atopology)
-    || '.node(node_id, geom) VALUES($1, $2)'
-    USING nodeid, apoint;
-
-  --
-  -- Delete the old edge
-  --
-  EXECUTE 'DELETE FROM ' || quote_ident(atopology)
-    || '.edge_data WHERE edge_id = $1'
-    USING anedge;
-
-  --
-  -- Compute new edges
-  --
-  edge2 := ST_Split(oldedge.geom, apoint);
-  edge1 := ST_GeometryN(edge2, 1);
-  edge2 := ST_GeometryN(edge2, 2);
-
-  --
-  -- Get ids for the new edges 
-  --
-  FOR rec IN EXECUTE 'SELECT nextval(''' ||
-    atopology || '.edge_data_edge_id_seq'')'
-  LOOP
-    edgeid1 = rec.nextval;
-  END LOOP;
-  FOR rec IN EXECUTE 'SELECT nextval(''' ||
-    atopology || '.edge_data_edge_id_seq'')'
-  LOOP
-    edgeid2 = rec.nextval;
-  END LOOP;
-
-#ifdef POSTGIS_TOPOLOGY_DEBUG
-  RAISE DEBUG ' inserting new edges % and % split from %', edgeid1, edgeid2, anedge;
-#endif
-
-  --RAISE NOTICE 'EdgeId1 % EdgeId2 %', edgeid1, edgeid2;
-
-  --RAISE DEBUG 'oldedge.next_left_edge: %', oldedge.next_left_edge;
-  --RAISE DEBUG 'oldedge.next_right_edge: %', oldedge.next_right_edge;
-
-  --
-  -- Insert the two new edges
-  --
-  EXECUTE 'INSERT INTO ' || quote_ident(atopology)
-    || '.edge VALUES('
-    || edgeid1                                -- edge_id
-    || ',' || oldedge.start_node              -- start_node
-    || ',' || nodeid                          -- end_node
-    || ',' || edgeid2                         -- next_left_edge
-    || ',' || CASE                            -- next_right_edge
-               WHEN 
-                oldedge.next_right_edge = anedge
-               THEN edgeid1
-               WHEN
-                oldedge.next_right_edge = -anedge
-               THEN -edgeid2
-               ELSE oldedge.next_right_edge
-              END
-    || ',' || oldedge.left_face               -- left_face
-    || ',' || oldedge.right_face              -- right_face
-    || ',$1)' -- geom
-    USING edge1;
-
-  EXECUTE 'INSERT INTO ' || quote_ident(atopology)
-    || '.edge VALUES('
-    || edgeid2                                -- edge_id
-    || ',' || nodeid                          -- start_node
-    || ',' || oldedge.end_node                -- end_node
-    || ',' || CASE                            -- next_left_edge
-               WHEN 
-                oldedge.next_left_edge =
-                -anedge
-               THEN -edgeid2
-               WHEN 
-                oldedge.next_left_edge =
-                anedge
-               THEN edgeid1
-               ELSE oldedge.next_left_edge
-              END
-    || ',' || -edgeid1                        -- next_right_edge
-    || ',' || oldedge.left_face               -- left_face
-    || ',' || oldedge.right_face              -- right_face
-    || ',$1)' -- geom
-    USING edge2;
-
-  --
-  -- Update all next edge references to match new layout (ST_NewEdgeSplit)
-  --
-
-  EXECUTE 'UPDATE ' || quote_ident(atopology)
-    || '.edge_data SET next_right_edge = '
-    || edgeid2
-    || ','
-    || ' abs_next_right_edge = ' || edgeid2
-    || ' WHERE next_right_edge = ' || anedge
-    || ' AND start_node = ' || oldedge.start_node
-    || ' AND edge_id NOT IN (' || edgeid1 || ',' || edgeid2 || ')'
-    ;
-  EXECUTE 'UPDATE ' || quote_ident(atopology)
-    || '.edge_data SET next_right_edge = '
-    || -edgeid1
-    || ','
-    || ' abs_next_right_edge = ' || edgeid1
-    || ' WHERE next_right_edge = ' || -anedge
-    || ' AND start_node = ' || oldedge.end_node
-    || ' AND edge_id NOT IN (' || edgeid1 || ',' || edgeid2 || ')'
-    ;
-
-  EXECUTE 'UPDATE ' || quote_ident(atopology)
-    || '.edge_data SET next_left_edge = '
-    || edgeid1
-    || ','
-    || ' abs_next_left_edge = ' || edgeid1
-    || ' WHERE next_left_edge = ' || anedge
-    || ' AND end_node = ' || oldedge.start_node
-    || ' AND edge_id NOT IN (' || edgeid1 || ',' || edgeid2 || ')'
-    ;
-  EXECUTE 'UPDATE ' || quote_ident(atopology)
-    || '.edge_data SET '
-    || ' next_left_edge = ' || -edgeid2
-    || ','
-    || ' abs_next_left_edge = ' || edgeid2
-    || ' WHERE next_left_edge = ' || -anedge
-    || ' AND end_node = ' || oldedge.end_node
-    || ' AND edge_id NOT IN (' || edgeid1 || ',' || edgeid2 || ')'
-    ;
-
-  --
-  -- Update references in the Relation table.
-  -- We only take into considerations non-hierarchical
-  -- TopoGeometry here, for obvious reasons.
-  --
-  FOR rec IN EXECUTE 'SELECT r.* FROM '
-    || quote_ident(atopology)
-    || '.relation r, topology.layer l '
-    || ' WHERE '
-    || ' l.topology_id = ' || topoid
-    || ' AND l.level = 0 '
-    || ' AND l.layer_id = r.layer_id '
-    || ' AND abs(r.element_id) = ' || anedge
-    || ' AND r.element_type = 2'
-  LOOP
-    --RAISE NOTICE 'TopoGeometry % in layer % contains the edge being split', rec.topogeo_id, rec.layer_id;
-
-    -- Delete old reference
-    EXECUTE 'DELETE FROM ' || quote_ident(atopology)
-      || '.relation '
-      || ' WHERE '
-      || 'layer_id = ' || rec.layer_id
-      || ' AND '
-      || 'topogeo_id = ' || rec.topogeo_id
-      || ' AND '
-      || 'element_type = ' || rec.element_type
-      || ' AND '
-      || 'abs(element_id) = ' || anedge;
-
-    -- Add new reference to edge1
-    IF rec.element_id < 0 THEN
-      tmp = -edgeid1;
-    ELSE
-      tmp = edgeid1;
-    END IF;
-    EXECUTE 'INSERT INTO ' || quote_ident(atopology)
-      || '.relation '
-      || ' VALUES( '
-      || rec.topogeo_id
-      || ','
-      || rec.layer_id
-      || ','
-      || tmp
-      || ','
-      || rec.element_type
-      || ')';
-
-    -- Add new reference to edge2
-    IF rec.element_id < 0 THEN
-      tmp = -edgeid2;
-    ELSE
-      tmp = edgeid2;
-    END IF;
-    EXECUTE 'INSERT INTO ' || quote_ident(atopology)
-      || '.relation '
-      || ' VALUES( '
-      || rec.topogeo_id
-      || ','
-      || rec.layer_id
-      || ','
-      || tmp
-      || ','
-      || rec.element_type
-      || ')';
-      
-  END LOOP;
-
-  --RAISE NOTICE 'Edge % split in edges % and % by node %',
-  --  anedge, edgeid1, edgeid2, nodeid;
-
-  RETURN nodeid; 
-END
-$$
-LANGUAGE 'plpgsql' VOLATILE;
+  'MODULE_PATHNAME','ST_NewEdgesSplit'
+  LANGUAGE 'c' VOLATILE;
 --} ST_NewEdgesSplit
 
 --{