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

svn_grass at osgeo.org svn_grass at osgeo.org
Tue Nov 27 02:00:54 PST 2012


Author: martinl
Date: 2012-11-27 02:00:53 -0800 (Tue, 27 Nov 2012)
New Revision: 54072

Modified:
   grass/trunk/lib/vector/Vlib/copy.c
   grass/trunk/lib/vector/Vlib/open_pg.c
   grass/trunk/lib/vector/Vlib/pg_local_proto.h
   grass/trunk/lib/vector/Vlib/read_pg.c
   grass/trunk/lib/vector/Vlib/rewind_pg.c
   grass/trunk/lib/vector/Vlib/write_nat.c
   grass/trunk/lib/vector/Vlib/write_pg.c
   grass/trunk/lib/vector/diglib/plus_area.c
Log:
vlib (PostGIS Topo): better support for areas/faces (work in progress)


Modified: grass/trunk/lib/vector/Vlib/copy.c
===================================================================
--- grass/trunk/lib/vector/Vlib/copy.c	2012-11-27 09:15:53 UTC (rev 54071)
+++ grass/trunk/lib/vector/Vlib/copy.c	2012-11-27 10:00:53 UTC (rev 54072)
@@ -18,6 +18,17 @@
 #include <grass/vector.h>
 #include <grass/glocale.h>
 
+/*!
+  \brief Copy topological elements
+
+  - simple features (None)
+  - native topo (GRASS)
+  - PostGIS Topo
+*/
+#define TOPO_NONE   -1
+#define TOPO_NATIVE  1
+#define TOPO_POSTGIS 2
+
 #ifdef HAVE_POSTGRES
 #include "pg_local_proto.h"
 #endif
@@ -60,37 +71,39 @@
 int Vect_copy_map_lines_field(struct Map_info *In, int field,
                               struct Map_info *Out)
 {
-    int ret, native, pg_topo;
+    int ret, format, topo;
     
     if (Vect_level(In) < 1)
         G_fatal_error("Vect_copy_map_lines(): %s",
                       _("input vector map is not open"));
+
+    format = Vect_maptype(Out);
+    topo = TOPO_NONE;
+    if (format == GV_FORMAT_NATIVE)
+        topo = TOPO_NATIVE;
+    else if (format == GV_FORMAT_POSTGIS && Out->fInfo.pg.toposchema_name)
+        topo = TOPO_POSTGIS;
     
-    /* check for external formats - copy areas/isles as polygons with holes */
-    native = Vect_maptype(Out) == GV_FORMAT_NATIVE;
-    /* check for PostGIS topology */
-    pg_topo = Vect_maptype(Out) == GV_FORMAT_POSTGIS && Out->fInfo.pg.toposchema_name;
-    
     /* Note: sometimes is important to copy on level 2 (pseudotopo
-       centroids) and sometimes on level 1 if build take too
-       long time
+       centroids) and sometimes on level 1 if build take too long time
     */
     if (Vect_level(In) >= 2) {
         /* -> copy features on level 2 */
-        if (pg_topo)
+        if (topo == TOPO_POSTGIS)
             /* PostGIS topology - copy also nodes */
             copy_nodes(In, Out);
         
         /* copy features */
-        ret = copy_lines_2(In, field, native, Out);
+        ret = copy_lines_2(In, field, topo, Out);
         
-        if (!native) {
+        if (topo == TOPO_NONE) {
+            /* copy areas - external formats and simple features access only */
             copy_areas(In, field, Out);
         }
     }
     else {
         /* -> copy features on level 1 */
-        if (!native)
+        if (topo == TOPO_NONE)
             G_warning(_("Vector map <%s> not open on topological level. "
                         "Areas will be skipped!"), Vect_get_full_name(In));
         
@@ -157,12 +170,13 @@
 
   \param In input vector map
   \param field layer number (-1 for all layers)
+  \param topo topo access (none, native, postgis)
   \param Out output vector map
   
   \return 0 on success
   \return 1 on error
 */
-int copy_lines_2(struct Map_info *In, int field, int native, struct Map_info *Out)
+int copy_lines_2(struct Map_info *In, int field, int topo, struct Map_info *Out)
 {
     int i, type, nlines;
     int ret, left, rite, centroid;
@@ -177,11 +191,11 @@
     
     ret = 0;
     nlines = Vect_get_num_lines(In);
-    if (native)
-        G_message(_("Copying features..."));
-    else
+    if (topo == TOPO_NONE)
         G_message(_("Copying features (%s)..."),
                       Vect_get_finfo_geometry_type(Out));
+    else
+        G_message(_("Copying features..."));    
     
     for (i = 1; i <= nlines; i++) {
         if (!Vect_line_alive(In, i))
@@ -198,11 +212,13 @@
         if (type == 0)
             continue;       /* dead line */
         
-        if (!native && (type == GV_CENTROID || type == GV_BOUNDARY))
-            /* OGR/PostGIS layers: centroids are stored in topo */
-            /*             polygon defined by areas (topo required) */
+        if (topo == TOPO_NONE && (type == GV_CENTROID || type == GV_BOUNDARY)) {
+            /* OGR/PostGIS layers (simple features): centroids are
+               stored in topo polygon defined by areas (topo required)
+            */
             continue;
-        
+        }
+
         /* don't skips boundaries if field != -1 */
         if (field != -1) {
             if (type & GV_BOUNDARY) {

Modified: grass/trunk/lib/vector/Vlib/open_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/open_pg.c	2012-11-27 09:15:53 UTC (rev 54071)
+++ grass/trunk/lib/vector/Vlib/open_pg.c	2012-11-27 10:00:53 UTC (rev 54072)
@@ -1410,7 +1410,8 @@
     /* number of features group by type */
     /* points */
     sprintf(stmt,
-            "SELECT COUNT(*) FROM \"%s\".node WHERE node_id NOT IN "
+            "SELECT COUNT(*) FROM \"%s\".node WHERE containing_face "
+            "IS NULL AND node_id NOT IN "
             "(SELECT node FROM (SELECT start_node AS node FROM \"%s\".edge "
             "GROUP BY start_node UNION ALL SELECT end_node AS node FROM "
             "\"%s\".edge GROUP BY end_node) AS foo)",
@@ -1486,7 +1487,7 @@
             "SELECT node_id,geom FROM \"%s\".node WHERE node_id IN "
             "(SELECT node FROM (SELECT start_node AS node FROM \"%s\".edge "
             "GROUP BY start_node UNION ALL SELECT end_node AS node FROM "
-            "\"%s\".edge GROUP BY end_node) AS foo)",
+            "\"%s\".edge GROUP BY end_node) AS foo) ORDER BY node_id",
             pg_info->toposchema_name, pg_info->toposchema_name,
             pg_info->toposchema_name);
     G_debug(2, "SQL: %s", stmt);
@@ -1522,7 +1523,7 @@
             "SELECT node_id,geom FROM \"%s\".node WHERE node_id NOT IN "
             "(SELECT node FROM (SELECT start_node AS node FROM \"%s\".edge "
             "GROUP BY start_node UNION ALL SELECT end_node AS node FROM "
-            "\"%s\".edge GROUP BY end_node) AS foo)",
+            "\"%s\".edge GROUP BY end_node) AS foo) ORDER BY node_id",
             pg_info->toposchema_name, pg_info->toposchema_name,
             pg_info->toposchema_name);
     G_debug(2, "SQL: %s", stmt);
@@ -1551,7 +1552,7 @@
     */
     sprintf(stmt,
             "SELECT edge_id,start_node,end_node,left_face,right_face,geom "
-            "FROM \"%s\".edge",
+            "FROM \"%s\".edge ORDER BY edge_id",
             pg_info->toposchema_name);
     G_debug(2, "SQL: %s", stmt);
     res = PQexec(pg_info->conn, stmt);
@@ -1610,14 +1611,18 @@
     }
     PQclear(res);
     
-    /* attach centroids */
+    /* read PostGIS Topo standalone nodes (containing_face is not null)
+       -> centroids
+    */
     if (plus->n_areas > 0) {
         sprintf(stmt,
-                "SELECT ST_PointOnSurface(geom) AS geom FROM "
-                "ST_GetFaceGeometry('%s',"
-                "(SELECT face_id FROM \"%s\".face WHERE face_id > 0)) "
-                "AS geom",
-                pg_info->toposchema_name, pg_info->toposchema_name);
+                "SELECT node_id,geom FROM \"%s\".node WHERE containing_face "
+                "IS NOT NULL AND node_id NOT IN "
+                "(SELECT node FROM (SELECT start_node AS node FROM \"%s\".edge "
+                "GROUP BY start_node UNION ALL SELECT end_node AS node FROM "
+                "\"%s\".edge GROUP BY end_node) AS foo) ORDER BY node_id",
+                pg_info->toposchema_name, pg_info->toposchema_name,
+                pg_info->toposchema_name);
         G_debug(2, "SQL: %s", stmt);
         res = PQexec(pg_info->conn, stmt);
         if (!res || PQresultStatus(res) != PGRES_TUPLES_OK ||

Modified: grass/trunk/lib/vector/Vlib/pg_local_proto.h
===================================================================
--- grass/trunk/lib/vector/Vlib/pg_local_proto.h	2012-11-27 09:15:53 UTC (rev 54071)
+++ grass/trunk/lib/vector/Vlib/pg_local_proto.h	2012-11-27 10:00:53 UTC (rev 54072)
@@ -59,6 +59,7 @@
 
 /* functions used in *_pg.c files */
 int Vect__execute_pg(PGconn *, const char *);
+int Vect__execute_get_value_pg(PGconn *, const char *);
 SF_FeatureType Vect__cache_feature_pg(const char *, int, int,
                                       struct Format_info_cache *,
                                       struct feat_parts *);

Modified: grass/trunk/lib/vector/Vlib/read_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/read_pg.c	2012-11-27 09:15:53 UTC (rev 54071)
+++ grass/trunk/lib/vector/Vlib/read_pg.c	2012-11-27 10:00:53 UTC (rev 54072)
@@ -46,7 +46,6 @@
 static int error_corrupted_data(const char *);
 static void reallocate_cache(struct Format_info_cache *, int);
 static void add_fpart(struct feat_parts *, SF_FeatureType, int, int);
-static int get_centroid_topo(struct Format_info_pg *, int, struct line_pnts *);
 static int get_centroid(struct Map_info *, int, struct line_pnts *);
 #endif
 
@@ -314,11 +313,9 @@
     if (line_c)
         Vect_cat_set(line_c, 1, (int) Line->offset);
     
-    if (Line->type == GV_CENTROID) {
-        if (pg_info->toposchema_name)
-            return get_centroid_topo(pg_info, line, line_p);
-        else
-            return get_centroid(Map, line, line_p);
+    if (Line->type == GV_CENTROID && !pg_info->toposchema_name) {
+        /* simple features access: get centroid from sidx */
+        return get_centroid(Map, line, line_p);
     }
     
     /* get feature id */
@@ -370,7 +367,7 @@
                       struct line_pnts *line_p, struct line_cats *line_c,
                       int ignore_constraints)
 {
-    int line, itype;
+    int itype;
     SF_FeatureType sf_type;
 
     struct Format_info_pg *pg_info;
@@ -383,8 +380,6 @@
         Vect_get_constraint_box(Map, &mbox);
 
     while (TRUE) {
-        line = Map->next_line++;        /* level 2 only */
-
         /* reset data structures */
         if (line_p != NULL)
             Vect_reset_line(line_p);
@@ -395,9 +390,9 @@
         while (pg_info->cache.lines_next == pg_info->cache.lines_num) {
             /* cache feature -> line_p & line_c */
             sf_type = get_feature(pg_info, -1, -1);
-
+            
             if (sf_type == SF_NONE) {
-                G_warning(_("Feature %d without geometry skipped"), line);
+                G_warning(_("Feature %d without geometry skipped"), pg_info->cache.fid);
                 return -1;
             }
 
@@ -411,6 +406,8 @@
             }
 
             G_debug(4, "%d lines read to cache", pg_info->cache.lines_num);
+            /* store fid as offset to be used (used for topo access only */
+            Map->head.last_offset = pg_info->cache.fid;
         }
 
         /* get data from cache */
@@ -458,16 +455,16 @@
 
    \param[in,out] pg_info pointer to Format_info_pg struct
    \param fid feature id to be read (-1 for next)
-   \param topotable_name table name for topological access (NULL for pseudo-topological access) - "node" or "edge"
-
+   \param type feature type (GV_POINT, GV_LINE, ...) - use only for topological access
+   
    \return simple feature type (SF_POINT, SF_LINESTRING, ...)
    \return -1 on error
  */
 SF_FeatureType get_feature(struct Format_info_pg *pg_info, int fid, int type)
 {
+    int force_type; /* force type (GV_BOUNDARY or GV_CENTROID) for topo access only */
     char *data;
     char stmt[DB_SQL_MAX];
-    int left_face, right_face;
     
     if (!pg_info->geom_column && !pg_info->topogeom_column) {
         G_warning(_("No geometry or topo geometry column defined"));
@@ -481,6 +478,7 @@
         }
     }
     else {
+        /* random access */
         if (!pg_info->fid_column) {
             G_warning(_("Random access not supported. "
                         "Primary key not defined."));
@@ -495,31 +493,33 @@
             sprintf(stmt,
                     "DECLARE %s_%s%p CURSOR FOR SELECT %s FROM \"%s\".\"%s\" "
                     "WHERE %s = %d", pg_info->schema_name, pg_info->table_name,
-                    pg_info->conn, pg_info->geom_column, pg_info->schema_name,
-                    pg_info->table_name, pg_info->fid_column, fid);
+                    pg_info->conn, pg_info->geom_column,
+                    pg_info->schema_name, pg_info->table_name,
+                    pg_info->fid_column, fid);
         }
         else {
-            /* topological access */
-            char *topotable_name;
-            
-            if (type == GV_POINT)
-                topotable_name = "node";
-            else if (type & GV_LINES)
-                topotable_name = "edge";
-            else {
+            if (!(type & (GV_POINTS | GV_LINES))) {
                 G_warning(_("Unsupported feature type %d"), type);
                 Vect__execute_pg(pg_info->conn, "ROLLBACK");
                 return -1;
             }
             
-            sprintf(stmt,
-                    "DECLARE %s_%s%p CURSOR FOR SELECT geom,left_face,right_face "
-                    " FROM \"%s\".\"%s\" "
-                    "WHERE %s_id = %d", pg_info->schema_name, pg_info->table_name,
-                    pg_info->conn, pg_info->toposchema_name,
-                    topotable_name, topotable_name, fid);
+            if (type & GV_POINTS) {
+                sprintf(stmt,
+                        "DECLARE %s_%s%p CURSOR FOR SELECT geom,containing_face "
+                        " FROM \"%s\".node WHERE node_id = %d",
+                        pg_info->schema_name, pg_info->table_name, pg_info->conn,
+                        pg_info->toposchema_name, fid);
+            }
+            else {
+                sprintf(stmt,
+                        "DECLARE %s_%s%p CURSOR FOR SELECT geom,left_face,right_face "
+                        " FROM \"%s\".edge WHERE edge_id = %d",
+                        pg_info->schema_name, pg_info->table_name, pg_info->conn,
+                        pg_info->toposchema_name, fid);
+            }
         }
-
+        G_debug(3, "SQL: %s", stmt);
         if (Vect__execute_pg(pg_info->conn, stmt) == -1)
             return -1;
 
@@ -570,22 +570,45 @@
         }
         return -2;
     }
-    data = (char *)PQgetvalue(pg_info->res, pg_info->next_line, 0);
-    left_face = right_face = 0;
-    if (pg_info->toposchema_name) { /* -> PostGIS topology access */
-        if (fid < 0) { /* sequential access */
-            left_face  = atoi(PQgetvalue(pg_info->res, pg_info->next_line, 2));
-            right_face = atoi(PQgetvalue(pg_info->res, pg_info->next_line, 3));
+
+    force_type = -1;
+    if (pg_info->toposchema_name) {
+        if (fid < 0) {
+            /* sequatial access */
+            if (strcmp(PQgetvalue(pg_info->res, pg_info->next_line, 2), "b") == 0)
+                force_type = GV_BOUNDARY;
+            else if (strcmp(PQgetvalue(pg_info->res, pg_info->next_line, 2), "c") == 0)
+                force_type = GV_CENTROID;
         }
-        else {         /* random access */
-            left_face  = atoi(PQgetvalue(pg_info->res, pg_info->next_line, 1));
-            right_face = atoi(PQgetvalue(pg_info->res, pg_info->next_line, 2));
+        else {
+            /* random access: check topological elemenent type consistency */
+            if (type & GV_POINTS) {
+                if (type == GV_POINT &&
+                    strlen(PQgetvalue(pg_info->res, pg_info->next_line, 1)) != 0)
+                    G_warning(_("Inconsistency in topology: detected centroid (should be point)"));
+            }
+            else {
+                int left_face, right_face;
+                
+                left_face  = atoi(PQgetvalue(pg_info->res, pg_info->next_line, 1));
+                right_face = atoi(PQgetvalue(pg_info->res, pg_info->next_line, 2));
+                
+                if (type == GV_LINE &&
+                    (left_face != 0 || right_face != 0)) 
+                    G_warning(_("Inconsistency in topology: detected boundary (should be line)"));
+            }
         }
     }
-    pg_info->cache.sf_type =
-        Vect__cache_feature_pg(data, FALSE,
-                               left_face != 0 || right_face != 0 ? TRUE : FALSE,
-                               &(pg_info->cache), NULL);
+
+    /* get geometry data */
+    data = (char *)PQgetvalue(pg_info->res, pg_info->next_line, 0);
+    
+    /* load feature to the cache */
+    pg_info->cache.sf_type = Vect__cache_feature_pg(data,
+                                                    FALSE, force_type,
+                                                    &(pg_info->cache), NULL);
+    
+    /* set feature id */
     if (fid < 0) {
         pg_info->cache.fid =
             atoi(PQgetvalue(pg_info->res, pg_info->next_line, 1));
@@ -607,7 +630,7 @@
         if (Vect__execute_pg(pg_info->conn, "COMMIT") == -1)
             return -1;
     }
-
+    
     return pg_info->cache.sf_type;
 }
 
@@ -659,7 +682,7 @@
 
    \param data HEX data
    \param skip_polygon skip polygons (level 1)
-   \param force_boundary force GV_BOUNDARY feature type (for PostGIS topology)
+   \param force_type force GV_BOUNDARY or GV_CENTROID (used for PostGIS topology only)
    \param[out] cache lines cache
    \param[out] fparts used for building pseudo-topology (or NULL)
 
@@ -667,7 +690,7 @@
    \return SF_UNKNOWN on error
  */
 SF_FeatureType Vect__cache_feature_pg(const char *data, int skip_polygon,
-                                      int force_boundary,
+                                      int force_type,
                                       struct Format_info_cache *cache,
                                       struct feat_parts * fparts)
 {
@@ -759,17 +782,14 @@
     ret = -1;
     if (ftype == SF_POINT) {
         cache->lines_num = 1;
-        cache->lines_types[0] = GV_POINT;
+        cache->lines_types[0] = force_type == GV_CENTROID ? force_type : GV_POINT;
         ret = point_from_wkb(wkb_data, nbytes, byte_order,
                              is3D, cache->lines[0]);
         add_fpart(fparts, ftype, 0, 1);
     }
     else if (ftype == SF_LINESTRING) {
         cache->lines_num = 1;
-        if (force_boundary)
-            cache->lines_types[0] = GV_BOUNDARY;
-        else
-            cache->lines_types[0] = GV_LINE;
+        cache->lines_types[0] = force_type == GV_BOUNDARY ? force_type : GV_LINE;
         ret = linestring_from_wkb(wkb_data, nbytes, byte_order,
                                   is3D, cache->lines[0], FALSE);
         add_fpart(fparts, ftype, 0, 1);
@@ -1147,21 +1167,29 @@
     }
     else {
         /* topology access */
+        /* TODO: optimize SQL statement (for points/centroids) */
         sprintf(stmt,
                 "DECLARE %s_%s%p CURSOR FOR "
-                "SELECT geom,fid,left_face,right_face FROM ("
-                "SELECT node_id AS fid,geom,0 AS left_face,0 AS right_face FROM "
-                "\"%s\".node WHERE node_id NOT IN "
+                "SELECT geom,fid,type FROM ("
+                "SELECT node_id AS fid,geom, 'p' AS type FROM \"%s\".node WHERE "
+                "containing_face IS NULL AND node_id NOT IN "
                 "(SELECT node FROM (SELECT start_node AS node FROM \"%s\".edge "
                 "GROUP BY start_node UNION ALL SELECT end_node AS node FROM "
-                "\"%s\".edge GROUP BY end_node) AS foo) "
-                "UNION ALL SELECT edge_id AS fid,geom,left_face,right_face FROM \"%s\".edge "
-                "ORDER BY fid) AS foo",
+                "\"%s\".edge GROUP BY end_node) AS foo) UNION ALL SELECT "
+                "node_id AS fid,geom, 'c' AS type FROM \"%s\".node WHERE "
+                "containing_face IS NOT NULL AND node_id NOT IN "
+                "(SELECT node FROM (SELECT start_node AS node FROM \"%s\".edge "
+                "GROUP BY start_node UNION ALL SELECT end_node AS node FROM "
+                "\"topo_bridges\".edge GROUP BY end_node) AS foo) "
+                "UNION ALL SELECT edge_id AS fid, geom, 'l' AS type FROM \"%s\".edge WHERE "
+                "left_face = 0 AND right_face = 0 UNION ALL SELECT edge_id AS fid, geom, 'b' AS type FROM "
+                "\"%s\".edge WHERE left_face != 0 OR right_face != 0 ) AS foo ORDER BY fid, type",
                 pg_info->schema_name, pg_info->table_name, pg_info->conn,
                 pg_info->toposchema_name, pg_info->toposchema_name,
-                pg_info->toposchema_name, pg_info->toposchema_name); 
+                pg_info->toposchema_name, pg_info->toposchema_name,
+                pg_info->toposchema_name, pg_info->toposchema_name, pg_info->toposchema_name); 
     }
-    G_debug(2, "SQL: %s", stmt);
+    G_debug(3, "SQL: %s", stmt);
     
     if (Vect__execute_pg(pg_info->conn, stmt) == -1) {
         Vect__execute_pg(pg_info->conn, "ROLLBACK");
@@ -1216,6 +1244,38 @@
 }
 
 /*!
+   \brief Execute SQL statement and get value.
+
+   \param conn pointer to PGconn
+   \param stmt query
+
+   \return value on success
+   \return -1 on error
+ */
+int Vect__execute_get_value_pg(PGconn *conn, const char *stmt)
+{
+    int ret;
+    PGresult *result;
+
+    result = NULL;
+
+    G_debug(3, "Vect__execute_get_value_pg(): %s", stmt);
+    result = PQexec(conn, stmt);
+    if (!result || PQresultStatus(result) != PGRES_TUPLES_OK ||
+        PQntuples(result) != 1) {
+        PQclear(result);
+
+        G_warning(_("Execution failed: %s"), PQerrorMessage(conn));
+        return -1;
+    }
+
+    ret = atoi(PQgetvalue(result, 0, 0));
+    PQclear(result);
+    
+    return ret;
+}
+
+/*!
    \brief Reallocate lines cache
  */
 void reallocate_cache(struct Format_info_cache *cache, int num)
@@ -1280,49 +1340,6 @@
 }
 
 /*
-  \brief Get centroid from PostGIS topology
-  
-  \param pg_info pointer to Format_info_pg
-  \param centroid centroid id
-  \param[out] line_p output geometry
-
-  \return GV_CENTROID on success
-  \return -1 on error
-*/
-int get_centroid_topo(struct Format_info_pg *pg_info,
-                      int centroid, struct line_pnts *line_p)
-{
-    char stmt[DB_SQL_MAX];
-    char *data;
-
-    PGresult *res;
-    
-    sprintf(stmt,
-            "SELECT ST_PointOnSurface(geom) AS geom FROM "
-            "ST_GetFaceGeometry('%s', %d) AS geom",
-            pg_info->toposchema_name, centroid);
-    res = PQexec(pg_info->conn, stmt);
-    if (!res || PQresultStatus(res) != PGRES_TUPLES_OK ||
-        PQntuples(res) != 1) {
-        G_warning(_("Unable to read centroid %d: %s"),
-                  centroid, PQerrorMessage(pg_info->conn));
-        if (res)
-            PQclear(res);
-        return -1;
-    }
-    
-    data = (char *)PQgetvalue(res, 0, 0);
-    PQclear(res);
-    
-    if (GV_POINT != Vect__cache_feature_pg(data, FALSE, FALSE, &(pg_info->cache), NULL))
-        return -1;
-    
-    Vect_append_points(line_p, pg_info->cache.lines[0], GV_FORWARD);
-    
-    return GV_CENTROID;
-}
-
-/*
   \brief Get centroid
   
   \param pg_info pointer to Format_info_pg

Modified: grass/trunk/lib/vector/Vlib/rewind_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/rewind_pg.c	2012-11-27 09:15:53 UTC (rev 54071)
+++ grass/trunk/lib/vector/Vlib/rewind_pg.c	2012-11-27 10:00:53 UTC (rev 54072)
@@ -81,8 +81,9 @@
 {
     G_debug(2, "V2_rewind_pg(): name = %s", Map->name);
 #ifdef HAVE_POSTGRES
+    /* reset reading */
     Map->next_line = 1;
-
+    
     V1_rewind_pg(Map);
 
     return 0;

Modified: grass/trunk/lib/vector/Vlib/write_nat.c
===================================================================
--- grass/trunk/lib/vector/Vlib/write_nat.c	2012-11-27 09:15:53 UTC (rev 54071)
+++ grass/trunk/lib/vector/Vlib/write_nat.c	2012-11-27 10:00:53 UTC (rev 54072)
@@ -177,8 +177,8 @@
 	    if (n > 2) {
 		/* more than 2 boundaries at node ( >= 2 old + 1 new ) */
 		/* Line above (to the right), it is enough to check to
-		   the right, because if area/isle
-		   exists it is the same to the left */
+		   the right, because if area/isle exists it is the
+		   same to the left */
 		if (!s)
 		    next_line =
 			dig_angle_next_line(plus, line, GV_RIGHT,

Modified: grass/trunk/lib/vector/Vlib/write_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/write_pg.c	2012-11-27 09:15:53 UTC (rev 54071)
+++ grass/trunk/lib/vector/Vlib/write_pg.c	2012-11-27 10:00:53 UTC (rev 54072)
@@ -5,7 +5,7 @@
 
    Higher level functions for reading/writing/manipulating vectors.
 
-   Inspired by OGR PostgreSQL driver.
+   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()
@@ -50,16 +50,16 @@
                                         int, int *);
 static unsigned char *polygon_to_wkb(int, const struct line_pnts **, int,
                                      int, int *);
-static int write_feature(struct Map_info *,
-                         int, const struct line_pnts **, int, int,
-                         const struct P_line *,
+static int write_feature(struct Map_info *, int, int,
+                         const struct line_pnts **, int, int,
                          int, const struct field_info *);
 static char *build_insert_stmt(const struct Format_info_pg *, const char *,
-                               int, int, const struct field_info *);
-static char *build_topo_stmt(struct Map_info *, int,
-                             const struct P_line *, const char *);
-static int execute_topo(PGconn *, const char *);
-static int update_next_line(struct Map_info*, int, int, int*, 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, int*, int *);
+static int insert_face(struct Map_info *, int);
+static int update_topo_edge(struct Map_info *, int);
+static int update_topo_face(struct Map_info *, int);
 #endif
 
 /*!
@@ -131,7 +131,7 @@
     }
     else {                          /* PostGIS topology */
         if (Map->plus.built < GV_BUILD_BASE)
-            Map->plus.built = GV_BUILD_BASE;
+            Map->plus.built = GV_BUILD_ALL;
         return write_line_tp(Map, type, FALSE, points, cats);
     }
 #else
@@ -387,7 +387,7 @@
         }
     }
     else {
-        G_warning(_("Unsupported feature type (%d)"), type);
+        G_warning(_("Unsupported feature type %d"), type);
         return -1;
     }
     
@@ -410,8 +410,8 @@
     }
 
     /* write feature's geometry and fid */
-    if (-1 == write_feature(Map, type, points, nparts,
-                            Vect_is_3d(Map) ? WITH_Z : WITHOUT_Z, NULL, cat, Fi)) {
+    if (-1 == write_feature(Map, -1, type, points, nparts,
+                            Vect_is_3d(Map) ? WITH_Z : WITHOUT_Z, cat, Fi)) {
         Vect__execute_pg(pg_info->conn, "ROLLBACK");
         return -1;
     }
@@ -452,12 +452,11 @@
                     const struct line_pnts *points,
                     const struct line_cats *cats)
 {
-    int cat;
+    int line, cat;
 
     struct field_info *Fi;
     struct Format_info_pg *pg_info;
     struct Plus_head *plus;
-    struct P_line *Line;
     
     pg_info = &(Map->fInfo.pg);
     plus = &(Map->plus);
@@ -491,6 +490,8 @@
     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) {
@@ -511,30 +512,38 @@
         Vect_cat_get(cats, 1, &cat);
     }
 
-    /* update topology before writing feature */
-    Line = NULL;
+    /* update GRASS-like topology before writing feature */
     if (is_node) {
         dig_add_node(plus, points->x[0], points->y[0], points->z[0]);
     }
     else {
-        int line;
+        off_t offset;
         struct bound_box box;
         
         dig_line_box(points, &box);
-        line = dig_add_line(plus, type, points, &box, 0); /* 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 = dig_add_line(plus, type, points, &box, offset);
         G_debug(3, "  line added to topo with id = %d", line);
+        
         if (line == 1)
             Vect_box_copy(&(plus->box), &box);
         else
             Vect_box_extend(&(plus->box), &box);
-        V2__add_line_to_topo_nat(Map, line, points, NULL); /* cats ? */
-
-        Line = plus->Line[line];
     }
     
-    /* write feature geometry and fid */
-    if (-1 == write_feature(Map, type, &points, 1,
-                            Vect_is_3d(Map) ? WITH_Z : WITHOUT_Z, Line,
+    /* write new feature to PostGIS
+       - feature table for simple features
+       - feature table and topo schema for topological access 
+    */
+    if (-1 == write_feature(Map, line, type, &points, 1,
+                            Vect_is_3d(Map) ? WITH_Z : WITHOUT_Z,
                             cat, Fi)) {
         Vect__execute_pg(pg_info->conn, "ROLLBACK");
         return -1;
@@ -819,6 +828,7 @@
    \brief Insert feature into table
 
    \param Map pointer to Map_info structure
+   \param line feature id (topo access only)
    \param type feature type (GV_POINT, GV_LINE, ...)
    \param points pointer to line_pnts struct
    \param nparts number of parts (rings for polygon)
@@ -829,19 +839,17 @@
    \return -1 on error
    \retirn 0 on success
  */
-int write_feature(struct Map_info *Map, int type,
+int write_feature(struct Map_info *Map, int line, int type,
                   const struct line_pnts **points, int nparts, int with_z,
-                  const struct P_line *Line,
                   int cat, const struct field_info *Fi)
 {
-    int fid;
     int byte_order, nbytes, nsize;
     unsigned int sf_type;
     unsigned char *wkb_data;
     char *stmt, *text_data, *text_data_p, *hex_data;
 
     struct Format_info_pg *pg_info;
-
+    
     pg_info = &(Map->fInfo.pg);
     
     if (with_z && pg_info->coor_dim != 3) {
@@ -933,12 +941,7 @@
     /* build INSERT statement
        simple feature geometry + attributes
     */
-    fid = -1;
-    if (pg_info->toposchema_name) {
-        /* use defined fid (=line) for topological access */
-        fid = Vect_get_num_primitives(Map, type); /* write next fid */
-    }
-    stmt = build_insert_stmt(pg_info, text_data, fid, cat, Fi);
+    stmt = build_insert_stmt(pg_info, text_data, cat, Fi);
     G_debug(2, "SQL: %s", stmt);
 
     if (!pg_info->inTransaction) {
@@ -960,17 +963,20 @@
     /* write feature in PostGIS topology schema if enabled */
     if (pg_info->toposchema_name) {
         /* insert feature into topology schema (node or edge) */
-        stmt = build_topo_stmt(Map, type, Line, text_data);
-#if USE_TOPO_STMT
-        if (stmt && execute_topo(pg_info->conn, stmt) == -1) {
-#else
-        if (stmt && Vect__execute_pg(pg_info->conn, stmt) == -1) {
-#endif
-            /* rollback transaction */
-            Vect__execute_pg(pg_info->conn, "ROLLBACK");
+        if (insert_topo_element(Map, line, type, text_data) != 0) {
+            G_warning(_("Unable to insert topological element into PostGIS Topology schema"));
             return -1;
         }
-        G_free(stmt);
+        
+        /* update GRASS-like topo */
+        if (line > 0) /* skip nodes */
+            V2__add_line_to_topo_nat(Map, line, points[0], NULL); /* TODO: cats */
+        
+        /* update PostGIS-line topo */
+        if (type & GV_LINES)
+            update_topo_edge(Map, line);
+        if (type == GV_BOUNDARY)
+            update_topo_face(Map, line);
     }
 
     G_free(wkb_data);
@@ -987,14 +993,13 @@
    
    \param pg_info pointer to Format_info_pg structure
    \param geom_data geometry data
-   \param fid feature id (=line)
    \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, int fid,
+                        const char *geom_data,
                         int cat, const struct field_info *Fi)
 {
     char *stmt, buf[DB_SQL_MAX];
@@ -1113,8 +1118,8 @@
                 else {
                     /* PostGIS topology access, write geometry in
                      * topology schema, skip geometry at this point */
-                    G_asprintf(&stmt, "%s,%s) VALUES (%s,%d)",
-                               buf, pg_info->fid_column, buf_val, fid);
+                    G_asprintf(&stmt, "%s) VALUES (%s)",
+                               buf, buf_val);
                 }
             }
         }
@@ -1130,33 +1135,37 @@
         }
         else if (cat > 0)
             /* no attributes (topology elements) */
-            G_asprintf(&stmt, "INSERT INTO \"%s\".\"%s\" (%s) VALUES (%d)",
+            G_asprintf(&stmt, "INSERT INTO \"%s\".\"%s\" (%s) VALUES (NULL)",
                        pg_info->schema_name, pg_info->table_name,
-                       pg_info->fid_column, fid); 
+                       pg_info->geom_column); 
     }
     
     return stmt;
 }
 
 /*!
-  \brief Build SELECT statement to insert new element into PostGIS
-  topology schema
+  \brief Insert topological element into 'node' or 'edge' table
 
   \param Map pointer to Map_info struct
-  \param Line pointer to P_line struct (topo)
+  \param line feature id (-1 for nodes/points)
+  \param type feature type (GV_POINT, GV_LINE, ...)
   \param geom_data geometry in wkb
 
-  \return pointer to allocated string buffer with SQL statement
-  \return NULL on error
+  \return 0 on success
+  \return -1 on error
 */
-char *build_topo_stmt(struct Map_info *Map, int type,
-                      const struct P_line *Line, const char *geom_data)
+int insert_topo_element(struct Map_info *Map, int line, int type,
+                        const char *geom_data)
 {
     char *stmt;
     struct Format_info_pg *pg_info;
-
+    struct P_line *Line;
+    
     pg_info = &(Map->fInfo.pg);
     
+    if (line > 0)
+        Line = Map->plus.Line[line];
+
     stmt = NULL;
     switch(type) {
     case GV_POINT: {
@@ -1169,51 +1178,28 @@
 #endif
         break;
     }
-    case GV_LINE: {
-        int line;
-        int n1, n2;
-        int nle, nre; /* next left | right edge */
+    case GV_LINE:
+    case GV_BOUNDARY: {
+#if USE_TOPO_STMT
+        G_asprintf(&stmt, "SELECT topology.AddEdge('%s', '%s'::GEOMETRY)",
+                   pg_info->toposchema_name, geom_data);
+#else
+        int nle, nre;
         
-        /*
-         * isolated lines
-              next left  edge: -fid 
-              next right edge:  fid
-              
-         * connected lines
-             next left  edge: next line or -fid
-             next right edge: next line or  fid
-        */ 
         if (!Line) {
             G_warning(_("Topology not available. Unable to insert new edge."));
-            return NULL;
+            return -1;
         }
         
         struct P_topo_l *topo = (struct P_topo_l *) Line->topo;
-                
-#if USE_TOPO_STMT
-        G_asprintf(&stmt, "SELECT topology.AddEdge('%s', '%s'::GEOMETRY)",
-                   pg_info->toposchema_name, geom_data);
-#else
-        line = Vect_get_num_lines(Map);
         
-        /* get number of lines for each node */
-        n1 = Vect_get_node_n_lines(Map, topo->N1);
-        n2 = Vect_get_node_n_lines(Map, topo->N2);
-
         /* assuming isolated lines */
-        nle = -line;
-        nre = line;
+        nle = -Line->offset;
+        nre = Line->offset;
         
-        /* check for line connection */
-        if (n1 > 1) {
-            update_next_line(Map, n1, line, &nle, &nre);
-        }
-        if (n2 > 1) {
-            update_next_line(Map, n2, -line, &nle, &nre);
-        }
+        G_debug(3, "new edge: id=%lu next_left_edge=%d next_right_edge=%d",
+                Line->offset, nle, nre);
         
-        G_debug(3, "build_topo_stmt(): line=%d type=line nle=%d nre=%d", line, nle, nre);
-        
         G_asprintf(&stmt, "INSERT INTO \"%s\".edge_data (geom, start_node, end_node, "
                    "next_left_edge, abs_next_left_edge, next_right_edge, abs_next_right_edge, "
                    "left_face, right_face) "
@@ -1224,55 +1210,45 @@
         break;
     }
     case GV_CENTROID: {
-        /* TopoGeo_AddPoint ? */
-        G_asprintf(&stmt, "SELECT AddNode('%s', '%s'::GEOMETRY)",
+#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;
+        }
+        
+        struct P_topo_c *topo = (struct P_topo_c *) Line->topo;
+
+        /* 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 (containing_face, geom) "
+                   "VALUES (%d, '%s'::GEOMETRY)",
+                   pg_info->toposchema_name, topo->area, geom_data);
+#endif
         break;
     }
-    case GV_BOUNDARY: {
-        /* TopoGeo_AddLineString ? */
-        G_asprintf(&stmt, "SELECT AddEdge('%s', '%s'::GEOMETRY)",
-                   pg_info->toposchema_name, geom_data);
-        break;
-    }
     default:
         G_warning(_("Unsupported feature type %d"), type);
         break;
     }
     
-    return stmt;
-}
-
-/*!
-   \brief Execute SQL topo select statement
-
-   \param conn pointer to PGconn
-   \param stmt query
-
-   \return value on success
-   \return -1 on error
- */
-int execute_topo(PGconn *conn, const char *stmt)
-{
-    int ret;
-    PGresult *result;
-
-    result = NULL;
-
-    G_debug(3, "execute_topo(): %s", stmt);
-    result = PQexec(conn, stmt);
-    if (!result || PQresultStatus(result) != PGRES_TUPLES_OK ||
-        PQntuples(result) != 1) {
-        PQclear(result);
-
-        G_warning(_("Execution failed: %s"), PQerrorMessage(conn));
+    if(Vect__execute_pg(pg_info->conn, stmt) == -1) {
+        /* rollback transaction */
+        Vect__execute_pg(pg_info->conn, "ROLLBACK");
         return -1;
     }
 
-    ret = atoi(PQgetvalue(result, 0, 0));
-    PQclear(result);
-    
-    return ret;
+    return 0;
 }
 
 /*!
@@ -1280,66 +1256,299 @@
 
   \param Map pointer to Map_info struct
   \param nlines number of lines
-  \param line current line (negative for backward direction - ie. end node)
+  \param line current line
   \param[out] left left line
   \param[out] right right line
-  \return line id (left or right)
-
+  
   \return 0 on success
   \return -1 on failure
 */
-int update_next_line(struct Map_info* Map, int nlines, int line,
+int update_next_edge(struct Map_info* Map, int nlines, int line,
                      int *left, int *right)
 {
-    int next_line;
+    int next_line, edge;
     char stmt[DB_SQL_MAX];
     
-    struct Format_info_pg *pg_info;
+    const struct Format_info_pg *pg_info;
+    struct P_line *Line_next, *Line;
     
+    Line = Line_next = NULL;
+    
     pg_info = &(Map->fInfo.pg);
+
+    /* find next line
+       start node -> next on the left
+       end node   -> next on the right
+    */ 
+    next_line = dig_angle_next_line(&(Map->plus), line, GV_LEFT, GV_LINES, NULL);
+    G_debug(3, "line=%d next_line=%d", line, next_line);
+    if (next_line == 0) {
+        G_warning(_("Invalid topology"));
+        return -1; 
+    }
     
-    /* update left line side */
-    next_line = dig_angle_next_line(&(Map->plus), line,
-                                    line < 0 ? GV_LEFT : GV_RIGHT, GV_LINE, NULL);
-    if (line > 0)
-        *right = next_line;
-    else
-        *left  = next_line;
-    sprintf(stmt, "UPDATE \"%s\".edge_data SET next_left_edge = %d, "
-            "abs_next_left_edge = %d WHERE edge_id = %d",
-            pg_info->toposchema_name, line, abs(line), abs(next_line));
-    G_debug(4, "build_topo_stmt(): line=%d nle=%d | line=%d nle=%d",
-            line, next_line, abs(next_line), line);
+    Line      = Map->plus.Line[abs(line)];
+    Line_next = Map->plus.Line[abs(next_line)];
+    if (!Line || !Line_next) {
+        G_warning(_("Invalid topology"));
+        return -1;
+    }
     
+    if (line > 0) {
+        edge = Line->offset;
+        *right = next_line > 0 ? Line_next->offset : -Line_next->offset;
+    }
+    else {
+        edge = -Line->offset;
+        *left  = next_line > 0 ? Line_next->offset : -Line_next->offset;
+    }
+    
+    if (next_line < 0) {
+        sprintf(stmt, "UPDATE \"%s\".edge_data SET next_left_edge = %d, "
+                "abs_next_left_edge = %d WHERE edge_id = %lu",
+                pg_info->toposchema_name, edge, abs(edge), Line_next->offset);
+        G_debug(3, "update edge=%lu next_left_edge=%d", Line_next->offset, edge);
+    }
+    else {
+        sprintf(stmt, "UPDATE \"%s\".edge_data SET next_right_edge = %d, "
+                "abs_next_right_edge = %d WHERE edge_id = %lu AND abs_next_right_edge = %lu",
+                pg_info->toposchema_name, edge, abs(edge), Line_next->offset, Line_next->offset);
+        G_debug(3, "update edge=%lu next_right_edge=%d (?)", Line_next->offset, edge);
+    }
+    
     if(Vect__execute_pg(pg_info->conn, stmt) == -1) {
-        /* rollback transaction */
         Vect__execute_pg(pg_info->conn, "ROLLBACK");
         return -1;
     }
     
     if (nlines > 2) {
-        /* update right line side */
-        next_line = dig_angle_next_line(&(Map->plus), line,
-                                        line < 0 ? GV_RIGHT : GV_LEFT, GV_LINE, NULL);
-        if (line > 0)
-            *right = next_line;
-        else
-            *left  = next_line;
-        G_debug(4, "line=%d nre=%d", line, next_line);
-        /*
-        sprintf(stmt, "UPDATE \"%s\".edge_data SET next_right_edge = %d, "
-                "abs_next_right_edge = %d WHERE edge_id = %d",
-                pg_info->toposchema_name, line, abs(line), abs(next_line));
-        G_debug(0, "build_topo_stmt(): line=%d nre=%d", abs(next_line), line);
+        /* more lines connected to the node
 
+           start node -> next on the right
+           end node   -> next on the left
+        */
+        next_line = dig_angle_next_line(&(Map->plus), line, GV_RIGHT, GV_LINES, NULL);
+        Line_next = Map->plus.Line[abs(next_line)];
+        
+        if (next_line < 0) {
+            sprintf(stmt, "UPDATE \"%s\".edge_data SET next_left_edge = %d, "
+                    "abs_next_left_edge = %d WHERE edge_id = %lu",
+                    pg_info->toposchema_name, edge, abs(edge), Line_next->offset);
+            G_debug(3, "update edge=%lu next_left_edge=%d", Line_next->offset, edge);
+        }
+        else {
+            sprintf(stmt, "UPDATE \"%s\".edge_data SET next_right_edge = %d, "
+                    "abs_next_right_edge = %d WHERE edge_id = %lu AND abs_next_right_edge = %lu",
+                    pg_info->toposchema_name, edge, abs(edge), Line_next->offset, Line_next->offset);
+            G_debug(3, "update edge=%lu next_right_edge=%d (?)", Line_next->offset, edge);
+        }
+     
         if(Vect__execute_pg(pg_info->conn, stmt) == -1) {
-        Vect__execute_pg(pg_info->conn, "ROLLBACK");
+            Vect__execute_pg(pg_info->conn, "ROLLBACK");
             return -1;
         }
-        */
     }
     
     return 0;
 }
 
+/*!
+  \brief Insert new face to the 'face' table (topo only)
+
+  \param Map pointer to Map_info struct
+  \param area area id
+
+  \return 0 on error
+  \return area id on success (>0)
+*/
+int insert_face(struct Map_info *Map, int area)
+{
+    char *stmt;
+    
+    struct Format_info_pg *pg_info;
+    struct bound_box box;
+    
+    if (area <= 0)
+        return 0; /* universal face has id '0' in PostGIS Topology */
+
+    stmt = NULL;
+    pg_info = &(Map->fInfo.pg);
+
+    /* check if face exists */
+    
+    /* get mbr of the area */
+    Vect_get_area_box(Map, area, &box);
+    
+    /* insert face if not exists */
+    G_asprintf(&stmt, "INSERT INTO \"%s\".face (face_id, mbr) VALUES "
+               "(%d, 'POLYGON((%.12f %.12f, %.12f %.12f, %.12f %.12f, %.12f %.12f, "
+               "%.12f %.12f))'::GEOMETRY)", pg_info->toposchema_name, area,
+               box.W, box.S, box.W, box.N, box.E, box.N,
+               box.E, box.S, box.W, box.S);
+    G_debug(3, "new face id=%d", area);
+    if (Vect__execute_pg(pg_info->conn, stmt) == -1) {
+        Vect__execute_pg(pg_info->conn, "ROLLBACK");
+        return 0;
+    }
+    G_free(stmt);
+
+    return area;
+}
+
+
+/*!
+  \brief Update lines (next left and right edges)
+  
+  - isolated edges
+  next left  edge: -edge 
+  next right edge:  edge
+  
+  - connected edges
+  next left  edge: next edge or -edge
+  next right edge: next edge or  edge
+
+  \param Map pointer to Map_info struct
+  \param line feature id 
+
+  \return 0  on success
+  \return -1 on error
+*/ 
+int update_topo_edge(struct Map_info *Map, int line)
+{
+    int n1, n2;
+    int nle, nre;
+    char stmt[DB_SQL_MAX];
+    
+    struct Format_info_pg *pg_info;
+    struct P_line *Line;
+
+    pg_info = &(Map->fInfo.pg);
+    
+    if (line < 1 || line > Vect_get_num_lines(Map)) {
+        G_warning(_("Inconsistency in topology detected"));
+        return -1;
+    }
+    Line = Map->plus.Line[line];
+    if (!Line) {
+        G_warning(_("Inconsistency in topology detected"));
+        return -1;
+    }
+    
+    struct P_topo_l *topo = (struct P_topo_l *) Line->topo;
+    
+    /* get number of lines for each node */
+    n1 = Vect_get_node_n_lines(Map, topo->N1);
+    n2 = Vect_get_node_n_lines(Map, topo->N2);
+    
+    nre = nle = 0;
+    
+    /* check for line connection */
+    if (n1 > 1) {
+        update_next_edge(Map, n1, line, &nle, &nre);
+    }
+    if (n2 > 1) {
+        update_next_edge(Map, n2, -line, &nle, &nre);
+    }
+
+    if (nle == 0 && nre == 0) /* nothing changed */
+        return 0;
+    
+    sprintf(stmt, "UPDATE \"%s\".edge_data SET "
+            "next_left_edge = %d, abs_next_left_edge = %d, "
+            "next_right_edge = %d, abs_next_right_edge = %d "
+            "WHERE edge_id = %lu", pg_info->toposchema_name,
+            nle, abs(nle), nre, abs(nre), Line->offset);
+    G_debug(3, "update edge=%lu next_left_edge=%d next_right_edge=%d",
+            Line->offset, nle, nre);
+    
+    if(Vect__execute_pg(pg_info->conn, stmt) == -1) {
+        /* rollback transaction */
+        Vect__execute_pg(pg_info->conn, "ROLLBACK");
+        return -1;
+    }
+    
+    return 0;
+}
+
+/*!
+  \brief Update lines (left and right faces)
+
+  TODO: handle isles
+  
+  \param Map pointer to Map_info struct
+  \param line feature id 
+
+  \return 0  on success
+  \return -1 on error
+*/  
+int update_topo_face(struct Map_info *Map, int line)
+{
+    int i, s, area, face;
+    char stmt[DB_SQL_MAX];
+    
+    struct Format_info_pg *pg_info;
+    struct P_line *Line;
+    struct P_area *Area;
+    struct P_topo_b *topo;
+    
+    pg_info = &(Map->fInfo.pg);
+    
+    if (line < 1 || line > Vect_get_num_lines(Map)) {
+        G_warning(_("Inconsistency in topology detected"));
+        return -1;
+    }
+    Line = Map->plus.Line[line];
+    if (!Line) {
+        G_warning(_("Inconsistency in topology detected"));
+        return -1;
+    }
+    
+    topo = (struct P_topo_b *)Line->topo;
+    
+    for (s = 0; s < 2; s++) { /* for each side */
+        area = s == 0 ? topo->left : topo->right;
+        if (area <= 0) /* no area - skip */
+            continue;
+        Area = Map->plus.Area[area];
+        
+        face = insert_face(Map, area); /* TODO: update */
+        
+        for (i = 0; i < Area->n_lines; i++) { /* update all boundaries */
+            Line = Map->plus.Line[abs(Area->lines[i])];
+            topo = (struct P_topo_b *)Line->topo;
+            
+            sprintf(stmt, "UPDATE \"%s\".edge_data SET "
+                    "left_face = %d, right_face = %d "
+                    "WHERE edge_id = %lu", pg_info->toposchema_name,
+                    topo->left > 0 ? topo->left : 0,
+                    topo->right > 0 ? topo->right : 0,
+                    Line->offset);
+            G_debug(2, "SQL: %s", stmt);
+            
+            if(Vect__execute_pg(pg_info->conn, stmt) == -1) {
+                /* rollback transaction */
+                Vect__execute_pg(pg_info->conn, "ROLLBACK");
+                return -1;
+            }
+        }
+        
+        /* update also centroids */
+        if (Area->centroid > 0) {
+            Line = Map->plus.Line[Area->centroid];
+            sprintf(stmt, "UPDATE \"%s\".node SET containing_face = %d "
+                    "WHERE node_id = %lu", pg_info->toposchema_name,
+                    face, Line->offset);
+            G_debug(2, "SQL: %s", stmt);
+            
+            if(Vect__execute_pg(pg_info->conn, stmt) == -1) {
+                /* rollback transaction */
+                Vect__execute_pg(pg_info->conn, "ROLLBACK");
+                return -1;
+            }
+        }
+    }
+    
+    return 0;
+}
+
 #endif

Modified: grass/trunk/lib/vector/diglib/plus_area.c
===================================================================
--- grass/trunk/lib/vector/diglib/plus_area.c	2012-11-27 09:15:53 UTC (rev 54071)
+++ grass/trunk/lib/vector/diglib/plus_area.c	2012-11-27 10:00:53 UTC (rev 54072)
@@ -457,12 +457,12 @@
  * of points and degenerated lines are set to -9 (ignored).
  *
  * \param[in] plus pointer to Plus_head structure
- * \param[in] current_line current line id, negative if request for node 2
+ * \param[in] current_line current line id, negative if request for end node
  * \param[in] side side GV_RIGHT or GV_LEFT
  * \param[in] type line type (GV_LINE, GV_BOUNDARY or both)
  * \param[in] angle
  *
- * \return line number of next angle to follow an line (negative if connected by node2)
+ * \return line number of next angle to follow an line (negative if connected by end node)
  *               (number of current line may be return if dangle - this is used in build)
  * \return 0 on error or not found
  */



More information about the grass-commit mailing list