[GRASS-SVN] r55764 - grass/trunk/lib/vector/Vlib

svn_grass at osgeo.org svn_grass at osgeo.org
Sat Apr 13 11:59:22 PDT 2013


Author: martinl
Date: 2013-04-13 11:59:22 -0700 (Sat, 13 Apr 2013)
New Revision: 55764

Modified:
   grass/trunk/lib/vector/Vlib/build_pg.c
   grass/trunk/lib/vector/Vlib/close.c
   grass/trunk/lib/vector/Vlib/copy.c
   grass/trunk/lib/vector/Vlib/open.c
   grass/trunk/lib/vector/Vlib/write_pg.c
Log:
vlip(pg): fix creating topogeometry objects
          fix transfering attributes
          (work in progress)


Modified: grass/trunk/lib/vector/Vlib/build_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/build_pg.c	2013-04-13 18:58:13 UTC (rev 55763)
+++ grass/trunk/lib/vector/Vlib/build_pg.c	2013-04-13 18:59:22 UTC (rev 55764)
@@ -24,7 +24,7 @@
 #include "pg_local_proto.h"
 
 static int build_topo(struct Map_info *, int);
-static int build_topogeom_stmt(const struct Format_info_pg *, int, int, char *);
+static int build_topogeom_stmt(const struct Format_info_pg *, int, int, int, char *);
 static int save_map_bbox(const struct Format_info_pg *, const struct bound_box*);
 static int create_topo_grass(const struct Format_info_pg *);
 static int has_topo_grass(const struct Format_info_pg *);
@@ -122,16 +122,16 @@
 */
 int build_topo(struct Map_info *Map, int build)
 {
-    int line, type, topo_id, s;
+    int line, type, s;
     int area, nareas, isle, nisles;
     int face[2];
     char stmt[DB_SQL_MAX];
     
     struct Plus_head *plus;
     struct Format_info_pg *pg_info;
+
     struct P_line *Line;
     struct P_area *Area;
-    struct P_topo_c *topo_c;
     struct P_topo_b *topo_b;
     struct P_isle *Isle;
     
@@ -188,7 +188,8 @@
             return 0;
         }
         
-        /* insert face from GRASS topology */
+        /* insert faces & update nodes (containing_face) based on
+         * GRASS topology */
         nareas = Vect_get_num_areas(Map);
         for (area = 1; area <= nareas; area++) {
             if (0 == Vect__insert_face_pg(Map, area)) {
@@ -202,7 +203,7 @@
             /* update centroids */
             Area = plus->Area[area];
             if (Area->centroid < 1) {
-                G_warning(_("Area %d without centroid"), area);
+                G_debug(3, "Area %d without centroid, skipped", area);
                 continue;
             }
             
@@ -217,74 +218,72 @@
                 return 0;
             }
         }
-    }
-    
-    if (build >= GV_BUILD_ATTACH_ISLES) {
-        /* insert isles as faces with negative face_id */
-        nisles = Vect_get_num_islands(Map);
-        for(isle = 1; isle <= nisles; isle++) {
-            Isle = plus->Isle[isle];
-            Vect__insert_face_pg(Map, -isle);
-        }
-    }
 
-    G_message(_("Updating TopoGeometry data..."));
-    for (line = 1; line <= plus->n_lines; line++) {
-        type = Vect_read_line(Map, NULL, NULL, line); 
-        G_percent(line, plus->n_lines, 3);
-        
-        Line = Map->plus.Line[line];
-        if (!Line) {
-            G_warning(_("Inconsistency in topology detected. "
-                        "Dead line found."));
-            return 0;
-        }
-    
-        if (build >= GV_BUILD_AREAS && type == GV_BOUNDARY) {
+        /* update edges (left and right face) */ 
+        for (line = 1; line <= plus->n_lines; line++) {
+            type = Vect_read_line(Map, NULL, NULL, line); 
+            if (type != GV_BOUNDARY)
+                continue;
+            
+            Line = Map->plus.Line[line];
+            if (!Line) {
+                G_warning(_("Inconsistency in topology detected. "
+                            "Dead line found."));
+                return 0;
+            }
+            
             topo_b = (struct P_topo_b *) Line->topo;
-
+            
             for (s = 0; s < 2; s++) { /* for both sides */
                 face[s] = s == 0 ? topo_b->left : topo_b->right;
                 if (face[s] < 0) {
+                    /* isle */
                     Isle = plus->Isle[abs(face[s])];
-                    if (Isle->area > 0) {
-                        face[s] = Isle->area;
-                    }
-                    else { /* -> universal face */
-                        face[s] = 0;
-                    }
+                    face[s] = Isle->area;
                 }
             }
+            G_debug(3, "update edge %d: left_face = %d, right_face = %d",
+                    (int)Line->offset, face[0], face[1]);
             
             sprintf(stmt, "UPDATE \"%s\".edge_data SET "
                     "left_face = %d, right_face = %d "
-                    "WHERE edge_id = %lu", pg_info->toposchema_name,
-                    face[0], face[1], Line->offset);
-            G_debug(2, "SQL: %s", stmt);
+                    "WHERE edge_id = %d", pg_info->toposchema_name,
+                    face[0], face[1], (int) Line->offset);
             
-            if(Vect__execute_pg(pg_info->conn, stmt) == -1) {
+            if (Vect__execute_pg(pg_info->conn, stmt) == -1) {
                 Vect__execute_pg(pg_info->conn, "ROLLBACK");
                 return 0;
             }
-            continue;
         }
-        
-        /* determine id */
-        if (type == GV_CENTROID) {
-            topo_c = (struct P_topo_c *) Line->topo;
-            topo_id = topo_c->area;
+    } /* build >= GV_BUILD_AREAS */
+    
+    if (build >= GV_BUILD_ATTACH_ISLES) {
+        /* insert isles as faces with negative face_id */
+        nisles = Vect_get_num_islands(Map);
+        for(isle = 1; isle <= nisles; isle++) {
+            Isle = plus->Isle[isle];
+            Vect__insert_face_pg(Map, -isle);
         }
-        else {
-            topo_id = line; /* GV_POINT | GV_LINE */
-        }
+    }
+
+    if (pg_info->feature_type == SF_POLYGON) {
+        int centroid;
         
-        if (build_topogeom_stmt(pg_info, topo_id, type, stmt) &&
-            Vect__execute_pg(pg_info->conn, stmt) == -1) {
-            Vect__execute_pg(pg_info->conn, "ROLLBACK");
-            return 0;
+        G_message(_("Updating TopoGeometry data..."));
+
+        for (area = 1; area <= plus->n_areas; area++) {
+            centroid = Vect_get_area_centroid(Map, area);
+            if (centroid < 1)
+                continue;
+        
+            if (build_topogeom_stmt(pg_info, GV_CENTROID, area, centroid, stmt) &&
+                Vect__execute_pg(pg_info->conn, stmt) == -1) {
+                Vect__execute_pg(pg_info->conn, "ROLLBACK");
+                return 0;
+            }
         }
     }
-    
+
     if (Vect__execute_pg(pg_info->conn, "COMMIT") == -1)
         return 0;
 
@@ -297,14 +296,15 @@
 
   \param pg_info so pointer to Format_info_pg
   \param type feature type (GV_POINT, ...)
-  \param id topology element id
+  \param topo_id topology element id
+  \param fid feature id
   \param[out] stmt string buffer
   
   \return 1 on success
   \return 0 on failure
 */
 int build_topogeom_stmt(const struct Format_info_pg *pg_info,
-                        int id, int type, char *stmt)
+                        int type, int topo_id, int fid, char *stmt)
 {
     int topogeom_type;
     
@@ -326,10 +326,10 @@
     
     sprintf(stmt, "UPDATE \"%s\".\"%s\" SET %s = "
             "'(%d, 1, %d, %d)'::topology.TopoGeometry "
-            "WHERE %s = %d",
+            "WHERE (%s).id = %d",
             pg_info->schema_name, pg_info->table_name,
             pg_info->topogeom_column, pg_info->toposchema_id,
-            id, topogeom_type, pg_info->fid_column, id);
+            topo_id, topogeom_type, pg_info->topogeom_column, fid);
 
     return 1;
 }

Modified: grass/trunk/lib/vector/Vlib/close.c
===================================================================
--- grass/trunk/lib/vector/Vlib/close.c	2013-04-13 18:58:13 UTC (rev 55763)
+++ grass/trunk/lib/vector/Vlib/close.c	2013-04-13 18:59:22 UTC (rev 55764)
@@ -93,14 +93,22 @@
             return 1;
         }
 
-        Vect_hist_command(&Out);
-            
-        /* TODO: how to determine field ? */
-        if (0 != Vect_copy_map_lines_field(Map, 1, &Out)) {
-            G_warning(_("Saving OGR data failed"));
+        /* copy metadata */
+        Vect_hist_copy(Map, &Out);
+        Vect_copy_head_data(Map, &Out);
+        /* copy dblinks (temporary map -> output map) to transfer
+           (input map -> output map) attributes */
+        Vect_copy_map_dblinks(Map, &Out, TRUE);
+        /* afterwords, dblinks must be removed from temporary map
+           otherwise when deleting temporary map also original
+           attribute tables would be deteled */
+        Vect_map_del_dblink(Map, -1); /* delete db links for all layers */
+        
+        if (0 != Vect_copy_map_lines_field(Map, 1, &Out)) { /* always layer = 1 for OGR/PG maps */
+            G_warning(_("Copying features failed"));
             return -1;
         }
-        
+
         Vect_build(&Out);
         
         Vect_close(&Out);

Modified: grass/trunk/lib/vector/Vlib/copy.c
===================================================================
--- grass/trunk/lib/vector/Vlib/copy.c	2013-04-13 18:58:13 UTC (rev 55763)
+++ grass/trunk/lib/vector/Vlib/copy.c	2013-04-13 18:59:22 UTC (rev 55764)
@@ -8,7 +8,7 @@
   (C) 2001-2009, 2012-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.
+  (>=v2). Read the file COPYING that comes with GRASS for details.
   
   \author Original author CERL, probably Dave Gerdes or Mike Higgins.
   \author Update to GRASS 5.7 Radim Blazek and David D. Gray.
@@ -75,31 +75,46 @@
     int ret, format, topo;
     
     if (Vect_level(In) < 1)
-        G_fatal_error("Vect_copy_map_lines(): %s",
-                      _("input vector map is not open"));
+        G_fatal_error(_("Unable to copy features. Input vector map <%s> is not open"),
+                      Vect_get_full_name(In));
 
     format = Vect_maptype(Out);
     topo = TOPO_NONE;
-    if (format == GV_FORMAT_NATIVE)
+    if (format == GV_FORMAT_NATIVE) {
         topo = TOPO_NATIVE;
-    else if (format == GV_FORMAT_POSTGIS && Out->fInfo.pg.toposchema_name)
+    }
+    else if (format == GV_FORMAT_POSTGIS && Out->fInfo.pg.toposchema_name) {
+        int type;
+        
         topo = TOPO_POSTGIS;
-    
+        
+        /* get type of first feature from input vector map */
+        Vect_rewind(In);
+        type = Vect_read_next_line(In, NULL, NULL);
+        if (!(type & (GV_POINTS | GV_LINES)))
+            G_fatal_error(_("Unsupported feature type %d"), type);
+            
+         /* create feature table with given feature type */
+        Vect_write_line(Out, type, NULL, NULL);
+    }
+  
     /* Note: sometimes is important to copy on level 2 (pseudotopo
        centroids) and sometimes on level 1 if build take too long time
     */
+    ret = 0;
     if (Vect_level(In) >= 2) {
         /* -> copy features on level 2 */
-        if (topo == TOPO_POSTGIS)
+        if (topo == TOPO_POSTGIS) {
             /* PostGIS topology - copy also nodes */
             copy_nodes(In, Out);
+        }
         
         /* copy features */
-        ret = copy_lines_2(In, field, topo, Out);
+        ret += copy_lines_2(In, field, topo, Out);
         
         if (topo == TOPO_NONE) {
             /* copy areas - external formats and simple features access only */
-            copy_areas(In, field, Out);
+            ret += copy_areas(In, field, Out);
         }
     }
     else {
@@ -108,10 +123,10 @@
             G_warning(_("Vector map <%s> not open on topological level. "
                         "Areas will be skipped!"), Vect_get_full_name(In));
         
-        ret = copy_lines_1(In, field, Out);
+        ret += copy_lines_1(In, field, Out);
     }
     
-    return ret;
+    return ret > 0 ? 1 : 0;
 }
 
 /*!
@@ -382,12 +397,9 @@
 int copy_areas(const struct Map_info *In, int field, struct Map_info *Out)
 {
     int i, area, nareas, cat, isle, nisles, nparts_alloc;
-    int ogr;
     struct line_pnts **Points;
     struct line_cats *Cats;
     
-    ogr = Vect_maptype(Out) == (GV_FORMAT_OGR || GV_FORMAT_OGR_DIRECT);
-    
     /* allocate points & cats */
     Points    = (struct line_pnts **) G_malloc(sizeof(struct line_pnts *));
     Points[0] = Vect_new_line_struct();

Modified: grass/trunk/lib/vector/Vlib/open.c
===================================================================
--- grass/trunk/lib/vector/Vlib/open.c	2013-04-13 18:58:13 UTC (rev 55763)
+++ grass/trunk/lib/vector/Vlib/open.c	2013-04-13 18:59:22 UTC (rev 55764)
@@ -975,10 +975,22 @@
    
   \param Map pointer to Map_info structure
   
-  \return maptype code
+  \return map format code
 */
 int Vect_maptype(const struct Map_info *Map)
 {
+    if (Map->temporary) {
+        const struct Format_info *finfo;
+        
+        finfo = &(Map->fInfo);
+        if (finfo->ogr.driver_name) {
+            return GV_FORMAT_OGR;
+        }
+        if (finfo->pg.conninfo) {
+            return GV_FORMAT_POSTGIS;
+        }
+    }
+    
     return Map->format;
 }
 
@@ -1243,7 +1255,6 @@
             G_warning(_("OGR output also detected, using OGR"));
         }
         else {
-            int topology;
             FILE *fp;
             const char *p;
             
@@ -1303,9 +1314,16 @@
             /* table name */
             Map->fInfo.pg.table_name = G_store(Map->name);
 
+            /* PostGIS topology enabled ? */
             p = G_find_key_value("topology", key_val);
-            topology = p && G_strcasecmp(p, "yes") == 0;
-        
+            if (p && G_strcasecmp(p, "yes") == 0) {
+                /* define topology name
+                   this should be configurable by the user
+                */
+                G_asprintf(&(pg_info->toposchema_name), "topo_%s",
+                           pg_info->table_name);
+            }
+            
             if (getenv("GRASS_VECTOR_EXTERNAL_IMMEDIATE")) {
                 /* vector features are written directly to PostGIS layer */
                 format = GV_FORMAT_POSTGIS;

Modified: grass/trunk/lib/vector/Vlib/write_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/write_pg.c	2013-04-13 18:58:13 UTC (rev 55763)
+++ grass/trunk/lib/vector/Vlib/write_pg.c	2013-04-13 18:59:22 UTC (rev 55764)
@@ -59,7 +59,7 @@
                          int, int, int);
 static int write_feature(struct Map_info *, int, int,
                          const struct line_pnts **, int, int, const struct field_info *);
-static char *build_insert_stmt(const struct Format_info_pg *, const char *,
+static char *build_insert_stmt(const struct Format_info_pg *, const char *, int, 
                                int, const struct field_info *);
 static int insert_topo_element(struct Map_info *, int, int, const char *);
 static int update_next_edge(struct Map_info*, int, int);
@@ -451,8 +451,12 @@
 
 #ifdef HAVE_POSTGRES
 /*!
-   \brief Writes node on topological level (PostGIS Topology interface, internal use only)
+   \brief Writes node on topological level (PostGIS Topology
+   interface, internal use only)
 
+   The vector map must be open on level 2 at least with
+   GV_BUILD_BASE. PostGIS Topology schema must be defined.
+
    \param Map pointer to Map_info structure
    \param points pointer to line_pnts structure
    
@@ -534,16 +538,6 @@
             p = G_find_key_value("primary_key", key_val);
             if (p && G_strcasecmp(p, "no") == 0)
                 primary_key = FALSE;
-            
-            /* PostGIS topology enabled ? */
-            p = G_find_key_value("topology", key_val);
-            if (p && G_strcasecmp(p, "yes") == 0) {
-                /* define topology name
-                   this should be configurable by the user
-                */
-                G_asprintf(&(pg_info->toposchema_name), "topo_%s",
-                           pg_info->table_name);
-            }
         }
     }
     
@@ -1180,8 +1174,6 @@
     G_debug(3, "write_line_pg(): type = %d n_points = %d",
             type, points->n_points);
 
-    line = -1; /* used only for topological access (lines, boundaries, and centroids) */
-    
     Fi = NULL; /* no attributes to be written */
     cat = -1;
     if (cats && cats->n_cats > 0) {
@@ -1203,22 +1195,25 @@
     }
 
     /* update GRASS topology before writing PostGIS feature */
-    if (is_node) {
-        dig_add_node(plus, points->x[0], points->y[0], points->z[0]);
-    }
-    else {
-        off_t offset;
-        
-        /* better is probably to check nextval directly */
-        if (type & GV_POINTS) {
-            offset = Vect_get_num_primitives(Map, GV_POINTS) + 1; /* next */
-            offset += Vect_get_num_nodes(Map); /* nodes are also stored in 'node' table */
+    line = 0;
+    if (plus->built >= GV_BUILD_BASE) {
+        if (is_node) {
+            dig_add_node(plus, points->x[0], points->y[0], points->z[0]);
         }
-        else { /* LINES */
-            offset = Vect_get_num_primitives(Map, GV_LINES) + 1; /* next */
+        else {
+            off_t offset;
+            
+            /* better is probably to check nextval directly */
+            if (type & GV_POINTS) {
+                offset = Vect_get_num_primitives(Map, GV_POINTS) + 1; /* next */
+                offset += Vect_get_num_nodes(Map); /* nodes are also stored in 'node' table */
+            }
+            else { /* LINES */
+                offset = Vect_get_num_primitives(Map, GV_LINES) + 1; /* next */
+            }
+            
+            line = add_line_to_topo_pg(Map, offset, type, points);
         }
-        
-        line = add_line_to_topo_pg(Map, offset, type, points);
     }
     
     /* write new feature to PostGIS
@@ -1630,7 +1625,7 @@
                   const struct line_pnts **points, int nparts,
                   int cat, const struct field_info *Fi)
 {
-    int with_z;
+    int with_z, topo_id;
     char *stmt, *geom_data;
 
     struct Format_info_pg *pg_info;
@@ -1654,43 +1649,44 @@
     if (!geom_data)
         return -1;
     
-    /* build INSERT statement
-       simple feature geometry + attributes
-    */
-    stmt = build_insert_stmt(pg_info, geom_data, cat, Fi);
-    G_debug(2, "SQL: %s", stmt);
-
+    /* start transaction */
     if (!pg_info->inTransaction) {
-        /* start transaction */
         pg_info->inTransaction = TRUE;
         if (Vect__execute_pg(pg_info->conn, "BEGIN") == -1) {
             G_free(geom_data);
+            return -1;
+        }
+    }
+
+    /* write feature in PostGIS topology schema if enabled */
+    topo_id = -1;
+    if (pg_info->toposchema_name) {
+        /* insert feature into topology schema (node or edge) */
+        topo_id = insert_topo_element(Map, line, type, geom_data);
+        if (topo_id < 0) {
+            G_warning(_("Unable to insert topological element into PostGIS Topology schema"));
+            G_free(geom_data);
             
             return -1;
         }
     }
 
+    /* build INSERT statement
+       simple feature geometry + attributes
+    */
+    stmt = build_insert_stmt(pg_info, geom_data, topo_id, cat, Fi);
+    G_debug(2, "SQL: %s", stmt);
+
     /* stmt can NULL when writing PostGIS topology with no attributes
      * attached */
     if (stmt && Vect__execute_pg(pg_info->conn, stmt) == -1) {
         /* rollback transaction */
         Vect__execute_pg(pg_info->conn, "ROLLBACK"); 
         G_free(geom_data);
+        G_free(stmt);
         
         return -1;
     }
-    G_free(stmt);
-    
-    /* write feature in PostGIS topology schema if enabled */
-    if (pg_info->toposchema_name) {
-        /* insert feature into topology schema (node or edge) */
-        if (insert_topo_element(Map, line, type, geom_data) != 0) {
-            G_warning(_("Unable to insert topological element into PostGIS Topology schema"));
-            G_free(geom_data);
-            
-            return -1;
-        }
-    }
     G_free(geom_data);
     
     return 0;
@@ -1704,17 +1700,39 @@
    
    \param pg_info pointer to Format_info_pg structure
    \param geom_data geometry data
+   \param type feature type (GV_POINT, GV_LINE, ...) - (only for PostGIS Topology)
+   \param id   topology element id (only for PostGIS Topology)
    \param cat category number (or -1 for no category)
    \param Fi pointer to field_info structure (NULL for no attributes)
 
    \return allocated string with INSERT statement
  */
 char *build_insert_stmt(const struct Format_info_pg *pg_info,
-                        const char *geom_data,
+                        const char *geom_data, int topo_id,
                         int cat, const struct field_info *Fi)
 {
+    int topogeom_type;
+    
     char *stmt, buf[DB_SQL_MAX];
 
+    topogeom_type = -1;
+    if (pg_info->toposchema_name) {
+        switch (pg_info->feature_type) {
+        case SF_POINT:
+            topogeom_type = 1;
+            break;
+        case SF_LINESTRING:
+            topogeom_type = 2;
+            break;
+        case SF_POLYGON:
+            topogeom_type = 3;
+            break;
+        default:
+            G_warning(_("Unsupported feature type %d"), pg_info->feature_type);
+            return NULL;
+        }
+    }
+
     stmt = NULL;
     if (Fi && cat > -1) { /* write attributes (simple features and topology elements) */
         int col, ncol, more;
@@ -1841,8 +1859,9 @@
 			buf[strlen(buf)-1] = '\0';
 			buf_val[strlen(buf_val)-1] = '\0';
 		    }
-                    G_asprintf(&stmt, "%s) VALUES (%s)",
-                               buf, buf_val);
+                    G_asprintf(&stmt, "%s, %s) VALUES (%s, '(%d, 1, %d, %d)'::topology.TopoGeometry)",
+                               buf, pg_info->topogeom_column, buf_val,
+                               pg_info->toposchema_id, topo_id, topogeom_type);
                 }
             }
         }
@@ -1856,11 +1875,15 @@
                        pg_info->schema_name, pg_info->table_name,
                        pg_info->geom_column, geom_data);
         }
-        else if (cat > 0) {
-            /* no attributes (topology elements) */
-            G_asprintf(&stmt, "INSERT INTO \"%s\".\"%s\" (%s) VALUES (NULL)",
-                       pg_info->schema_name, pg_info->table_name,
-                       pg_info->geom_column); 
+        else {
+            if (cat > 0) {
+                /* no attributes (topology elements) */
+                G_asprintf(&stmt, "INSERT INTO \"%s\".\"%s\" (%s,%s) VALUES "
+                           "(%d, '(%d, 1, %d, %d)'::topology.TopoGeometry)",
+                           pg_info->schema_name, pg_info->table_name,
+                           pg_info->fid_column, pg_info->topogeom_column, cat,
+                           pg_info->toposchema_id, topo_id, topogeom_type); 
+            }
 	}
     }
     
@@ -1870,122 +1893,142 @@
 /*!
   \brief Insert topological element into 'node' or 'edge' table
 
-  Negative id for nodes.
+  Negative id for nodes, 0 for next value.
   
   \param Map pointer to Map_info struct
-  \param id feature id (-1 for nodes/points)
+  \param id feature id (0 for next val)
   \param type feature type (GV_POINT, GV_LINE, ...)
   \param geom_data geometry in wkb
 
-  \return 0 on success
+  \return new topo id
   \return -1 on error
 */
 int insert_topo_element(struct Map_info *Map, int id, int type,
                         const char *geom_data)
 {
-    int ret;
-    char *stmt;
+    int ret, topo_id;
+    char *stmt, stmt_id[DB_SQL_MAX];
     struct Format_info_pg *pg_info;
+    struct Plus_head *plus;
     struct P_line *Line;
-    struct P_node *Node;
 
     pg_info = &(Map->fInfo.pg);
-
+    plus    = &(Map->plus);
+    
     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;
+    if (plus->built >= GV_BUILD_BASE) {
+        if (id > 0) { /* -> feature */
+            topo_id = id;
+            if (topo_id > Map->plus.n_lines) {
+                G_warning(_("Invalid line %d (%d)"), topo_id, Map->plus.n_lines);
+                return -1;
+            }
+            Line = Map->plus.Line[topo_id];
         }
-        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;
+        else if (id < 0) { /* node */
+            topo_id = abs(id);
+            if (type != GV_POINT) {
+                G_warning(_("Invalid feature type (%d) for node"), type);
+                return -1;
+            }
+            if (topo_id > Map->plus.n_nodes) {
+                G_warning(_("Invalid node %d (%d)"), topo_id, Map->plus.n_nodes);
+                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) {
     case GV_POINT: {
+        /* insert new node */
 #if USE_TOPO_STMT
         G_asprintf(&stmt, "SELECT topology.AddNode('%s', '%s'::GEOMETRY)",
                    pg_info->toposchema_name, geom_data);
 #else
-        G_asprintf(&stmt, "INSERT INTO \"%s\".node (node_id, geom) VALUES (%d, '%s'::GEOMETRY)",
-                   pg_info->toposchema_name, abs(id), geom_data);
+        if (id == 0) {
+            /* get node_id */
+            sprintf(stmt_id, "SELECT nextval('\"%s\".node_node_id_seq')",
+                    pg_info->toposchema_name);
+            topo_id = Vect__execute_get_value_pg(pg_info->conn, stmt_id);
+        }
+
+        /* build insert statement */
+        G_asprintf(&stmt, "INSERT INTO \"%s\".node (node_id, geom) VALUES "
+                   "(%d, '%s'::GEOMETRY)", pg_info->toposchema_name, topo_id, geom_data);
 #endif
         break;
     }
     case GV_LINE:
     case GV_BOUNDARY: {
+        /* insert new edge */
 #if USE_TOPO_STMT
         G_asprintf(&stmt, "SELECT topology.AddEdge('%s', '%s'::GEOMETRY)",
                    pg_info->toposchema_name, geom_data);
 #else
-        int nle, nre;
+        int n1, n2, nle, nre;
+
+        if (id == 0) {
+            /* get edge_id */
+            sprintf(stmt_id, "SELECT nextval('\"%s\".edge_data_edge_id_seq')",
+                    pg_info->toposchema_name);
+            topo_id = Vect__execute_get_value_pg(pg_info->conn, stmt_id);
+        }
         
-        if (!Line) {
-            G_warning(_("Topology not available. Unable to insert new edge."));
+        if (Line) {
+            struct P_topo_l *topo = (struct P_topo_l *) Line->topo;
+        
+            topo_id = (int)Line->offset;
+            n1 = topo->N1;
+            n2 = topo->N2;
+        }
+        else {
+            G_warning(_("Unable to insert new edge. Topology not available."));
             return -1;
         }
+        nle = -topo_id; /* assuming isolated lines */
+        nre = topo_id;
         
-        struct P_topo_l *topo = (struct P_topo_l *) Line->topo;
-        
-        /* assuming isolated lines */
-        nle = -Line->offset;
-        nre = Line->offset;
-        
         G_debug(3, "new edge: id=%d next_left_edge=%d next_right_edge=%d",
-                (int)Line->offset, nle, nre);
+                topo_id, nle, nre);
         
+        /* build insert statement */
         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, geom) "
-                   "VALUES (%d, %d, %d, %d, %d, %d, %d, 0, 0, '%s'::GEOMETRY)",
-                   pg_info->toposchema_name, (int) Line->offset, topo->N1, topo->N2,
+                   "left_face, right_face, geom) VALUES "
+                   "(%d, %d, %d, %d, %d, %d, %d, 0, 0, '%s'::GEOMETRY)",
+                   pg_info->toposchema_name, topo_id, n1, n2,
                    nle, abs(nle), nre, abs(nre), geom_data);
 #endif
         break;
     }
     case GV_CENTROID: {
+        /* insert new node (with containing_face) */
 #if USE_TOPO_STMT
         G_asprintf(&stmt, "SELECT topology.AddNode('%s', '%s'::GEOMETRY)",
                    pg_info->toposchema_name, geom_data);
 #else
-        if (!Line) {
-            G_warning(_("Topology not available. Unable to insert new node (centroid)"));
-            return -1;
+        int area;
+        
+        if (id == 0) {
+            /* get node_id */
+            sprintf(stmt_id, "SELECT nextval('\"%s\".node_node_id_seq')",
+                    pg_info->toposchema_name);
+            topo_id = Vect__execute_get_value_pg(pg_info->conn, stmt_id);
         }
         
-        struct P_topo_c *topo = (struct P_topo_c *) Line->topo;
+        if (Line) {
+            struct P_topo_c *topo = (struct P_topo_c *) Line->topo;
+            
+            area = topo->area;
+        }
+        else {
+            area = 0;
+        }
 
-        /* get id - see write_line_tp()
-           
-        sprintf(stmt_next, "SELECT nextval('\"%s\".node_node_id_seq')",
-                pg_info->toposchema_name);
-        Line->offset = Vect__execute_get_value_pg(pg_info->conn, stmt_next);
-        if (Line->offset < 1) {
-            G_warning(_("Invalid feature offset"));
-            return NULL;
-        }
-        */
-        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);
+        G_asprintf(&stmt, "INSERT INTO \"%s\".node (node_id, containing_face, geom) VALUES "
+                   "(%d, %d, '%s'::GEOMETRY)", pg_info->toposchema_name,
+                   topo_id, area, geom_data);
 #endif
         break;
     }
@@ -1993,7 +2036,8 @@
         G_warning(_("Unsupported feature type %d"), type);
         break;
     }
-    
+
+    /* execute insert statement */
     ret = Vect__execute_pg(pg_info->conn, stmt);
     G_free(stmt);
     
@@ -2002,8 +2046,8 @@
         Vect__execute_pg(pg_info->conn, "ROLLBACK");
         return -1;
     }
-
-    return 0;
+    
+    return topo_id;
 }
 
 /*!
@@ -2478,23 +2522,24 @@
 int delete_line_from_topo_pg(struct Map_info *Map, int line, int type,
                              const struct line_pnts *Points)
 {
+    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
+
     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;



More information about the grass-commit mailing list