[GRASS-SVN] r55706 - in grass/trunk/lib/vector: Vlib diglib

svn_grass at osgeo.org svn_grass at osgeo.org
Thu Apr 11 11:22:46 PDT 2013


Author: martinl
Date: 2013-04-11 11:22:45 -0700 (Thu, 11 Apr 2013)
New Revision: 55706

Modified:
   grass/trunk/lib/vector/Vlib/break_polygons.c
   grass/trunk/lib/vector/Vlib/level_two.c
   grass/trunk/lib/vector/Vlib/read_pg.c
   grass/trunk/lib/vector/Vlib/write_pg.c
   grass/trunk/lib/vector/diglib/plus_line.c
Log:
vlib(pg): add_line_to_topo_pg() and delete_line_from_topo_pg() added
          various minor improvements in PostGIS Topology support
          (work in progress)


Modified: grass/trunk/lib/vector/Vlib/break_polygons.c
===================================================================
--- grass/trunk/lib/vector/Vlib/break_polygons.c	2013-04-11 15:49:39 UTC (rev 55705)
+++ grass/trunk/lib/vector/Vlib/break_polygons.c	2013-04-11 18:22:45 UTC (rev 55706)
@@ -7,10 +7,8 @@
 
    (C) 2001-2009 by the GRASS Development Team
 
-   This program is free software under the 
-   GNU General Public License (>=v2). 
-   Read the file COPYING that comes with GRASS
-   for details.
+   This program is free software under the GNU General Public License
+   (>=v2).  Read the file COPYING that comes with GRASS for details.
 
    \author Radim Blazek
    \author Update for GRASS 7 Markus Metz
@@ -651,27 +649,24 @@
 }
 
 /*!
-   \brief Break polygons in vector map.
+   \brief Break polygons in vector map
 
    Breaks lines specified by type in vector map. Points at
-   intersections may be optionally written to error map. Input map
-   must be opened on level 2 for update at least on GV_BUILD_BASE.
+   intersections may be optionally written to error map. Input vector
+   map must be opened on level 2 for update at least on GV_BUILD_BASE.
 
-   Function is optimized for closed polygons rigs (e.g. imported from
+   Function is optimized for closed polygons rings (e.g. imported from
    OGR) but with clean geometry - adjacent polygons mostly have
    identical boundary. Function creates database of ALL points in the
-   map, and then is looking for those where polygons should be broken.
-   Lines may be broken only at points existing in input map!
+   vector map, and then is looking for those where polygons should be
+   broken.  Lines may be broken only at points existing in input
+   vector map!
 
    \param Map input map where polygons will be broken
-   \param type type of line to be broken
+   \param type type of line to be broken (GV_LINE or GV_BOUNDARY)
    \param Err vector map where points at intersections will be written or NULL
-
-   \return
  */
-
-void
-Vect_break_polygons(struct Map_info *Map, int type, struct Map_info *Err)
+void Vect_break_polygons(struct Map_info *Map, int type, struct Map_info *Err)
 {
     if (getenv("GRASS_VECTOR_LOWMEM"))
 	return Vect_break_polygons_file(Map, type, Err);

Modified: grass/trunk/lib/vector/Vlib/level_two.c
===================================================================
--- grass/trunk/lib/vector/Vlib/level_two.c	2013-04-11 15:49:39 UTC (rev 55705)
+++ grass/trunk/lib/vector/Vlib/level_two.c	2013-04-11 18:22:45 UTC (rev 55706)
@@ -226,17 +226,21 @@
 }
 
 /*!
-   \brief Get updated node by index
+   \brief Get updated (modified) node by index
 
    Note: Vect_set_updated() must be called to maintain list of updated
    features
 
-   Negative id indicates deleted node.
+   Negative id:
+    - if Node[id] is not NULL then the node was added
+    - if Node[id] is NULL then the node was deleted
+   Positive id:
+    - node was updated
 
    \param Map pointer to Map_info struct
    \param idx index
 
-   \return updated node
+   \return id of modified node
  */
 int Vect_get_updated_node(const struct Map_info *Map, int idx)
 {

Modified: grass/trunk/lib/vector/Vlib/read_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/read_pg.c	2013-04-11 15:49:39 UTC (rev 55705)
+++ grass/trunk/lib/vector/Vlib/read_pg.c	2013-04-11 18:22:45 UTC (rev 55706)
@@ -8,8 +8,13 @@
    \todo Currently only points, linestrings and polygons are supported,
    implement also other types
 
-   (C) 2011-2012 by the GRASS Development Team
+   \todo Support multigeometries
 
+   \todo PostGIS Topology - fix category handling (read categories
+   from feature table)
+
+   (C) 2011-2013 by the GRASS Development Team
+
    This program is free software under the GNU General Public License
    (>=v2). Read the file COPYING that comes with GRASS for details.
 
@@ -324,7 +329,7 @@
         return 0;
     }
     
-    G_debug(4, "V2_read_line_pg() line = %d type = %d offset = %lu",
+    G_debug(4, "V2_read_line_pg() line = %d type = %d offset = %"PRI_OFF_T,
             line, Line->type, Line->offset);
     
     if (!line_p && !line_c)
@@ -335,7 +340,7 @@
     if (line_c != NULL)
         Vect_reset_cats(line_c);
 
-    if (line_c)
+    if (line_c) 
         Vect_cat_set(line_c, 1, (int) Line->offset);
     
     if (Line->type == GV_CENTROID && !pg_info->toposchema_name) {

Modified: grass/trunk/lib/vector/Vlib/write_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/write_pg.c	2013-04-11 15:49:39 UTC (rev 55705)
+++ grass/trunk/lib/vector/Vlib/write_pg.c	2013-04-11 18:22:45 UTC (rev 55706)
@@ -7,11 +7,9 @@
 
    Write subroutine inspired by OGR PostgreSQL driver.
 
-   \todo PostGIS version of V2__add_line_to_topo_nat()
-   \todo OGR version of V2__delete_area_cats_from_cidx_nat()
+   \todo PostGIS version of V2__delete_area_cats_from_cidx_nat()
    \todo function to delete corresponding entry in fidx
-   \todo OGR version of V2__add_area_cats_to_cidx_nat
-   \todo OGR version of V2__add_line_to_topo_nat
+   \todo PostGIS version of V2__add_area_cats_to_cidx_nat
 
    (C) 2012-2013 by Martin Landa, and the GRASS Development Team
 
@@ -68,6 +66,8 @@
 static int delete_face(const struct Map_info *, int);
 static int update_topo_edge(struct Map_info *, int);
 static int update_topo_face(struct Map_info *, int);
+static int add_line_to_topo_pg(struct Map_info *, off_t, int, const struct line_pnts *);
+static int delete_line_from_topo_pg(struct Map_info *, int, int, const struct line_pnts *);
 #endif
 
 static struct line_pnts *Points;
@@ -214,7 +214,7 @@
   \return -1 on error
 */
 off_t V2_rewrite_line_pg(struct Map_info *Map, int line, int type, off_t old_offset,
-			  const struct line_pnts *points, const struct line_cats *cats)
+                         const struct line_pnts *points, const struct line_cats *cats)
 {
     G_debug(3, "V2_rewrite_line_pg(): line=%d type=%d offset=%"PRI_OFF_T,
             line, type, old_offset);
@@ -249,7 +249,7 @@
     }
 
     /* remove line from topology */
-    if (0 != V2__delete_line_from_topo_nat(Map, line, type, Points, NULL))
+    if (0 != delete_line_from_topo_pg(Map, line, type, Points))
         return -1;
 
     if (pg_info->toposchema_name) { /* PostGIS Topology */
@@ -281,7 +281,7 @@
 
     /* update topology
        note: offset is not changed */
-    return V2__add_line_to_topo_nat(Map, old_offset, type, points, cats, -1, NULL);
+    return add_line_to_topo_pg(Map, old_offset, type, points);
 #else
     G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
     return -1;
@@ -377,7 +377,7 @@
         return V2_delete_line_sfa(Map, line);
     }
     else {                          /* PostGIS topology */
-        int type, n_nodes;
+        int type;
         char stmt[DB_SQL_MAX];
         const char *table_name, *keycolumn;
         
@@ -441,34 +441,7 @@
         }
         
         /* update topology */
-        Vect_reset_updated(Map);
-        if (0 != V2__delete_line_from_topo_nat(Map, line, type, Points, NULL))
-            return -1;
-     
-        /* delete nodes from 'nodes' table */
-        n_nodes = Vect_get_num_updated_nodes(Map);
-        if (n_nodes > 0) {
-            int i, node;
-            
-            for (i = 0; i < n_nodes; i++) {
-                node = Vect_get_updated_node(Map, i);
-                if (node > 0)
-                    continue; /* node was updated, not deleted */
-                
-                node = abs(node);
-                G_debug(3, "delete node %d from 'node' table", node);
-                
-                sprintf(stmt, "DELETE FROM \"%s\".\"node\" WHERE node_id = %d",
-                        pg_info->toposchema_name, node);
-                if (Vect__execute_pg(pg_info->conn, stmt) == -1) {
-                    G_warning(_("Unable to delete node %d"), node);
-                    Vect__execute_pg(pg_info->conn, "ROLLBACK");
-                    return -1;
-                }
-            }
-        }
-        
-        return 0;
+        return delete_line_from_topo_pg(Map, line, type, Points);
     }
 #else
     G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
@@ -1234,7 +1207,6 @@
         dig_add_node(plus, points->x[0], points->y[0], points->z[0]);
     }
     else {
-        int n_nodes;
         off_t offset;
         
         /* better is probably to check nextval directly */
@@ -1246,31 +1218,7 @@
             offset = Vect_get_num_primitives(Map, GV_LINES) + 1; /* next */
         }
         
-        Vect_reset_updated(Map);
-        line = V2__add_line_to_topo_nat(Map, offset, type, points, NULL, /* TODO: handle categories */
-                                        -1, NULL);
-        
-        /* insert new nodes into 'nodes' table */
-        n_nodes = Vect_get_num_updated_nodes(Map);
-        if (n_nodes > 0) {
-            int i, node;
-            double x, y, z;
-            
-            if (!Points)
-                Points = Vect_new_line_struct();
-            
-            for (i = 0; i < n_nodes; i++) {
-                node = Vect_get_updated_node(Map, i);
-                G_debug(3, "  new node: %d", node);
-
-                Vect_get_node_coor(Map, node, &x, &y, &z);
-                Vect_reset_line(Points);
-                Vect_append_point(Points, x, y, z);
-                
-                write_feature(Map, -1, GV_POINT, (const struct line_pnts **) &Points, 1,
-                              -1, NULL);
-            }
-        }
+        line = add_line_to_topo_pg(Map, offset, type, points);
     }
     
     /* write new feature to PostGIS
@@ -1922,25 +1870,53 @@
 /*!
   \brief Insert topological element into 'node' or 'edge' table
 
+  Negative id for nodes.
+  
   \param Map pointer to Map_info struct
-  \param line feature id (-1 for nodes/points)
+  \param id feature id (-1 for nodes/points)
   \param type feature type (GV_POINT, GV_LINE, ...)
   \param geom_data geometry in wkb
 
   \return 0 on success
   \return -1 on error
 */
-int insert_topo_element(struct Map_info *Map, int line, int type,
+int insert_topo_element(struct Map_info *Map, int id, int type,
                         const char *geom_data)
 {
+    int ret;
     char *stmt;
     struct Format_info_pg *pg_info;
     struct P_line *Line;
-    
+    struct P_node *Node;
+
     pg_info = &(Map->fInfo.pg);
-    
-    if (line > 0)
+
+    Line = NULL;
+    Node = NULL;
+    if (id > 0) {
+        int line;
+
+        line = id;
+        if (line > Map->plus.n_lines) {
+            G_warning(_("Invalid line %d (%d)"), line, Map->plus.n_lines);
+            return -1;
+        }
         Line = Map->plus.Line[line];
+    }
+    else {
+        int node;
+        
+        node = abs(id);
+        if (type != GV_POINT) {
+            G_warning(_("Invalid feature type (%d) for node"), type);
+            return -1;
+        }
+        if (node > Map->plus.n_nodes) {
+            G_warning(_("Invalid node %d (%d)"), node, Map->plus.n_nodes);
+            return -1;
+        }
+        Node = Map->plus.Node[node];
+    }
 
     stmt = NULL;
     switch(type) {
@@ -1949,8 +1925,8 @@
         G_asprintf(&stmt, "SELECT topology.AddNode('%s', '%s'::GEOMETRY)",
                    pg_info->toposchema_name, geom_data);
 #else
-        G_asprintf(&stmt, "INSERT INTO \"%s\".node (geom) VALUES ('%s'::GEOMETRY)",
-                   pg_info->toposchema_name, geom_data);
+        G_asprintf(&stmt, "INSERT INTO \"%s\".node (node_id, geom) VALUES (%d, '%s'::GEOMETRY)",
+                   pg_info->toposchema_name, abs(id), geom_data);
 #endif
         break;
     }
@@ -1976,12 +1952,12 @@
         G_debug(3, "new edge: id=%d next_left_edge=%d next_right_edge=%d",
                 (int)Line->offset, nle, nre);
         
-        G_asprintf(&stmt, "INSERT INTO \"%s\".edge_data (geom, start_node, end_node, "
+        G_asprintf(&stmt, "INSERT INTO \"%s\".edge_data (edge_id, start_node, end_node, "
                    "next_left_edge, abs_next_left_edge, next_right_edge, abs_next_right_edge, "
-                   "left_face, right_face) "
-                   "VALUES ('%s'::GEOMETRY, %d, %d, %d, %d, %d, %d, 0, 0)",
-                   pg_info->toposchema_name, geom_data, topo->N1, topo->N2, nle, abs(nle),
-                   nre, abs(nre));
+                   "left_face, right_face, geom) "
+                   "VALUES (%d, %d, %d, %d, %d, %d, %d, 0, 0, '%s'::GEOMETRY)",
+                   pg_info->toposchema_name, (int) Line->offset, topo->N1, topo->N2,
+                   nle, abs(nle), nre, abs(nre), geom_data);
 #endif
         break;
     }
@@ -2007,9 +1983,9 @@
             return NULL;
         }
         */
-        G_asprintf(&stmt, "INSERT INTO \"%s\".node (containing_face, geom) "
-                   "VALUES (%d, '%s'::GEOMETRY)",
-                   pg_info->toposchema_name, topo->area, geom_data);
+        G_asprintf(&stmt, "INSERT INTO \"%s\".node (node_id, containing_face, geom) "
+                   "VALUES (%d, %d, '%s'::GEOMETRY)",
+                   pg_info->toposchema_name, (int)Line->offset, topo->area, geom_data);
 #endif
         break;
     }
@@ -2018,7 +1994,10 @@
         break;
     }
     
-    if(Vect__execute_pg(pg_info->conn, stmt) == -1) {
+    ret = Vect__execute_pg(pg_info->conn, stmt);
+    G_free(stmt);
+    
+    if (ret == -1) {
         /* rollback transaction */
         Vect__execute_pg(pg_info->conn, "ROLLBACK");
         return -1;
@@ -2174,7 +2153,7 @@
 }
 
 /*!
-  \brief Delete existing face
+  \brief Delete existing face (currently unused)
 
   \todo Set foreign keys as DEFERRABLE INITIALLY DEFERRED and use SET
   CONSTRAINTS ALL DEFERRED
@@ -2429,4 +2408,117 @@
     
     return 0;
 }
+
+/*!
+  \brief Add line to native and PostGIS topology
+
+  \param Map vector map
+  \param line feature id to remove from topo
+  \param type feature type
+  \param Points feature vertices
+
+  \return feature id
+  \return -1 on error
+*/
+int add_line_to_topo_pg(struct Map_info *Map, off_t offset, int type,
+                          const struct line_pnts *points)
+{
+    int line, n_nodes;
+    
+    struct Plus_head *plus;
+
+    plus    = &(Map->plus);
+
+    Vect_reset_updated(Map);
+    line = V2__add_line_to_topo_nat(Map, offset, type, points, NULL, 
+                                    -1, NULL);
+    
+    /* insert new nodes into 'node' table */
+    n_nodes = Vect_get_num_updated_nodes(Map);
+    if (n_nodes > 0) {
+        int i, node;
+        double x, y, z;
+        
+        if (!Points)
+            Points = Vect_new_line_struct();
+        
+        for (i = 0; i < n_nodes; i++) {
+            node = Vect_get_updated_node(Map, i);
+            /* skip updated and deleted nodes */
+            if (node > 0 || plus->Node[abs(node)] == NULL)
+                continue;
+            
+            G_debug(3, "  new node: %d", node);
+            
+            Vect_get_node_coor(Map, abs(node), &x, &y, &z);
+            Vect_reset_line(Points);
+            Vect_append_point(Points, x, y, z);
+            
+            write_feature(Map, node, GV_POINT, (const struct line_pnts **) &Points, 1,
+                          -1, NULL);
+        }
+    }
+
+    return line;
+}
+
+/*!
+  \brief Delete line from native and PostGIS topology
+
+  \todo Implement deleting nodes on request
+  
+  \param Map vector map
+  \param line feature id to remove from topo
+  \param type feature type
+  \param Points feature vertices
+
+  \return 0 on success
+  \return -1 on error
+*/
+int delete_line_from_topo_pg(struct Map_info *Map, int line, int type,
+                             const struct line_pnts *Points)
+{
+    int n_nodes;
+    char stmt[DB_SQL_MAX];
+    
+    struct Format_info_pg *pg_info;
+    struct Plus_head *plus;
+
+    pg_info = &(Map->fInfo.pg);
+    plus    = &(Map->plus);
+    
+    Vect_reset_updated(Map);
+    if (0 != V2__delete_line_from_topo_nat(Map, line, type, Points, NULL))
+        return -1;
+    
+    /* disabled: remove isolated nodes when closing the map
+       note: node id cannot be used as node_id
+       
+       delete nodes from 'node' table
+    n_nodes = Vect_get_num_updated_nodes(Map);
+    if (n_nodes > 0) {
+        int i, node;
+        
+        for (i = 0; i < n_nodes; i++) {
+            node = Vect_get_updated_node(Map, i);
+            if (node > 0 || plus->Node[abs(node)] != NULL)
+                continue; 
+            
+            node = abs(node);
+            G_debug(3, "delete node %d from 'node' table", node);
+            
+            sprintf(stmt, "DELETE FROM \"%s\".\"node\" WHERE node_id = %d",
+                    pg_info->toposchema_name, node);
+            if (Vect__execute_pg(pg_info->conn, stmt) == -1) {
+                G_warning(_("Unable to delete node %d"), node);
+                Vect__execute_pg(pg_info->conn, "ROLLBACK");
+                return -1;
+            }
+        }
+    }
+    */
+
+    return 0;
+}
+
 #endif

Modified: grass/trunk/lib/vector/diglib/plus_line.c
===================================================================
--- grass/trunk/lib/vector/diglib/plus_line.c	2013-04-11 15:49:39 UTC (rev 55705)
+++ grass/trunk/lib/vector/diglib/plus_line.c	2013-04-11 18:22:45 UTC (rev 55706)
@@ -21,7 +21,7 @@
 static int add_line(struct Plus_head *plus, int lineid, int type, const struct line_pnts *Points,
 		    const struct bound_box *box, off_t offset)
 {
-    int node, lp;
+    int node, lp, node_new;
     struct P_line *line;
 
     plus->Line[lineid] = dig_alloc_line();
@@ -54,15 +54,19 @@
     G_debug(3, "Register node: type = %d,  %f,%f", type, Points->x[0],
 	    Points->y[0]);
 
+    /* Start node */
     node = dig_find_node(plus, Points->x[0], Points->y[0], Points->z[0]);
     G_debug(3, "node = %d", node);
     if (node == 0) {
 	node = dig_add_node(plus, Points->x[0], Points->y[0], Points->z[0]);
 	G_debug(3, "Add new node: %d", node);
+        node_new = TRUE;
     }
     else {
-	G_debug(3, "Old node found: %d", node);
+        G_debug(3, "Old node found: %d", node);
+        node_new = FALSE;
     }
+    
     if (type == GV_LINE) {
 	struct P_topo_l *topo = (struct P_topo_l *)line->topo;
 
@@ -80,8 +84,9 @@
 
     dig_node_add_line(plus, node, lineid, Points, type);
     if (plus->uplist.do_uplist)
-	dig_node_add_updated(plus, node);
+	dig_node_add_updated(plus, node_new ? -node : node);
 
+    /* End node */
     lp = Points->n_points - 1;
     G_debug(3, "Register node %f,%f", Points->x[lp], Points->y[lp]);
     node = dig_find_node(plus, Points->x[lp], Points->y[lp],
@@ -91,9 +96,11 @@
 	node = dig_add_node(plus, Points->x[lp], Points->y[lp],
 			    Points->z[lp]);
 	G_debug(3, "Add new node: %d", node);
+        node_new = TRUE;
     }
     else {
 	G_debug(3, "Old node found: %d", node);
+        node_new = FALSE;
     }
     if (type == GV_LINE) {
 	struct P_topo_l *topo = (struct P_topo_l *)line->topo;
@@ -108,7 +115,7 @@
 
     dig_node_add_line(plus, node, -lineid, Points, type);
     if (plus->uplist.do_uplist)
-	dig_node_add_updated(plus, node);
+	dig_node_add_updated(plus, node_new ? -node : node);
 
     return (lineid);
 }



More information about the grass-commit mailing list