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

svn_grass at osgeo.org svn_grass at osgeo.org
Thu Nov 29 00:18:21 PST 2012


Author: martinl
Date: 2012-11-29 00:18:21 -0800 (Thu, 29 Nov 2012)
New Revision: 54097

Modified:
   grass/trunk/lib/vector/Vlib/build_pg.c
   grass/trunk/lib/vector/Vlib/pg_local_proto.h
   grass/trunk/lib/vector/Vlib/read_pg.c
   grass/trunk/lib/vector/Vlib/write_pg.c
Log:
vlib/PostGIS Topo: handle isles as faces (work in progress)


Modified: grass/trunk/lib/vector/Vlib/build_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/build_pg.c	2012-11-28 22:43:25 UTC (rev 54096)
+++ grass/trunk/lib/vector/Vlib/build_pg.c	2012-11-29 08:18:21 UTC (rev 54097)
@@ -56,41 +56,40 @@
     pg_info = &(Map->fInfo.pg);
 
     G_debug(1, "Vect_build_pg(): db='%s' table='%s', build=%d",
-	    pg_info->db_name, pg_info->table_name, build);
+            pg_info->db_name, pg_info->table_name, build);
 
     if (build == plus->built)
-	return 1;		/* do nothing */
+        return 1;            /* do nothing */
 
     /* TODO move this init to better place (Vect_open_ ?), because in
        theory build may be reused on level2 */
     if (build >= plus->built && build > GV_BUILD_BASE) {
-	G_free((void *)pg_info->offset.array);
-	G_zero(&(pg_info->offset), sizeof(struct Format_info_offset));
+        G_free((void *)pg_info->offset.array);
+        G_zero(&(pg_info->offset), sizeof(struct Format_info_offset));
     }
 
     if (!pg_info->conn) {
-	G_warning(_("No DB connection"));
-	return 0;
+        G_warning(_("No DB connection"));
+        return 0;
     }
 
-    if (!pg_info->fid_column) {
-	G_warning(_("Feature table <%s> has no primary key defined"),
-		  pg_info->table_name);
-	G_warning(_("Random read is not supported for this layer. "
-		    "Unable to build topology."));
-	return 0;
+    if (!pg_info->fid_column && !pg_info->toposchema_name) {
+        G_warning(_("Feature table <%s> has no primary key defined"),
+                  pg_info->table_name);
+        G_warning(_("Random read is not supported for this layer. "
+                    "Unable to build topology."));
+        return 0;
     }
 
     /* commit transaction block (update mode only) */
     if (pg_info->inTransaction && Vect__execute_pg(pg_info->conn, "COMMIT") == -1)
-	return 0;
-
+        return 0;
     pg_info->inTransaction = FALSE;
-
+    
     if (build > GV_BUILD_NONE) {
-	G_message(_("Using external data format '%s' (feature type '%s')"),
-		  Vect_get_finfo_format_info(Map),
-		  Vect_get_finfo_geometry_type(Map)); 
+        G_message(_("Using external data format '%s' (feature type '%s')"),
+                  Vect_get_finfo_format_info(Map),
+                  Vect_get_finfo_geometry_type(Map)); 
         if (!pg_info->toposchema_name)
             G_message(_("Building pseudo-topology over simple features..."));
         else
@@ -98,9 +97,10 @@
                       pg_info->toposchema_name);
     }
 
-    if (!pg_info->toposchema_name)
+    if (!pg_info->toposchema_name) /* pseudo-topology for simple features */
         return Vect__build_sfa(Map, build);
     
+    /* PostGIS Topology */
     return build_topo(Map, build);
 #else
     G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
@@ -112,7 +112,7 @@
 /*!
   \brief Build from PostGIS topology schema
 
-  Currently only GV_BUILD_ALL is supported
+  \todo Attach isles
 
   \param Map pointer to Map_info struct
   \param build build level
@@ -122,13 +122,17 @@
 */
 int build_topo(struct Map_info *Map, int build)
 {
-    int line, nlines, type;
+    int line, type, topo_id, area, nareas, s;
+    int face[2];
     char stmt[DB_SQL_MAX];
     
     struct Plus_head *plus;
     struct Format_info_pg *pg_info;
     struct P_line *Line;
-    struct P_topo_c *topo;
+    struct P_area *Area;
+    struct P_topo_c *topo_c;
+    struct P_topo_b *topo_b;
+    struct P_isle *Isle;
     
     plus = &(Map->plus);
     pg_info = &(Map->fInfo.pg);
@@ -139,56 +143,133 @@
         Vect__build_downgrade(Map, build);
         return 1;
     }
+    /*     -> upgrade */
     
-    if (build != GV_BUILD_ALL) {
-        /* TODO: implement all build levels */
-        G_warning(_("Only %s is supported for PostGIS topology"),
-                  "GV_BUILD_ALL");
-        return 0;
-    }
-    
-    /* read topology from PostGIS ???
-    if (plus->built < GV_BUILD_BASE) {
-        if (load_plus(Map, FALSE) != 0)
-            return 0;
-    }
-    */
-
-    /* update TopoGeometry based on GRASS-like topology */
     if (build < GV_BUILD_BASE)
         return 1; /* nothing to print */
     
-    if (plus->built < GV_BUILD_BASE) {
-        Vect_build_nat(Map, build);
-    }
+    /* update TopoGeometry based on GRASS-like topology */
+    Vect_build_nat(Map, build);
     
     /* store map boundig box in DB */
     save_map_bbox(pg_info, &(plus->box));
     
+    /* begin transaction */
     if (Vect__execute_pg(pg_info->conn, "BEGIN"))
         return 0;
     
+    /* update faces from GRASS Topology */
+    if (build >= GV_BUILD_AREAS) {
+        /* reset centroids to '0' (universal face) */
+        sprintf(stmt, "UPDATE \"%s\".node SET containing_face = 0 WHERE "
+                "containing_face IS NOT NULL", pg_info->toposchema_name);
+        G_debug(2, "SQL: %s", stmt);
+        if(Vect__execute_pg(pg_info->conn, stmt) == -1) {
+            Vect__execute_pg(pg_info->conn, "ROLLBACK");
+            return -1;
+        }
+
+        /* reset left|right edges */
+        sprintf(stmt, "UPDATE \"%s\".edge_data SET left_face = 0, right_face = 0",
+                pg_info->toposchema_name);
+        G_debug(2, "SQL: %s", stmt);
+        if(Vect__execute_pg(pg_info->conn, stmt) == -1) {
+            Vect__execute_pg(pg_info->conn, "ROLLBACK");
+            return -1;
+        }
+
+        /* delete faces */        
+        sprintf(stmt, "DELETE FROM \"%s\".face WHERE "
+                "face_id > 0", pg_info->toposchema_name);
+        G_debug(2, "SQL: %s", stmt);
+        if(Vect__execute_pg(pg_info->conn, stmt) == -1) {
+            Vect__execute_pg(pg_info->conn, "ROLLBACK");
+            return -1;
+        }
+        
+        /* insert face from GRASS topology */
+        nareas = Vect_get_num_areas(Map);
+        for (area = 1; area <= nareas; area++) {
+            Vect__insert_face_pg(Map, area);
+            
+            if (build < GV_BUILD_CENTROIDS)
+                continue;
+            
+            /* update centroids */
+            Area = plus->Area[area];
+            if (Area->centroid < 1) {
+                G_warning(_("Area %d without centroid"), area);
+                continue;
+            }
+            
+            Line = plus->Line[Area->centroid];
+            sprintf(stmt, "UPDATE \"%s\".node SET "
+                    "containing_face = %d WHERE node_id = %lu",
+                    pg_info->toposchema_name, area, Line->offset);
+            G_debug(2, "SQL: %s", stmt);
+            
+            if(Vect__execute_pg(pg_info->conn, stmt) == -1) {
+                Vect__execute_pg(pg_info->conn, "ROLLBACK");
+                return -1;
+            }
+        }
+    }
+    
     G_message(_("Updating TopoGeometry data..."));
-    nlines = Vect_get_num_lines(Map);
-    for(line = 1; line <= nlines; line++) {
-        type = Vect_read_line(Map, NULL, NULL, line);
-        G_percent(line, nlines, 3);
+    for (line = 1; line <= plus->n_lines; line++) {
+        type = Vect_read_line(Map, NULL, NULL, line); 
+        G_percent(line, plus->n_lines, 3);
         
-        /* update topogeometry elements in feature table */
-        if (type == GV_POINT || type == GV_LINE || type == GV_CENTROID) {
-            Line = Map->plus.Line[line];
-            if (!Line) {
-                G_warning(_("Inconsistency in topology detected. "
-                            "Dead line found."));
+        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) {
+            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 = plus->Isle[abs(face[s])];
+                    if (Isle->area > 0) {
+                        face[s] = Isle->area;
+                    }
+                    else { /* -> universal face */
+                        face[s] = 0;
+                    }
+                }
             }
-            topo = (struct P_topo_c *) Line->topo;
             
-            if (build_topogeom_stmt(pg_info, topo->area, type, stmt) &&
-                Vect__execute_pg(pg_info->conn, stmt) == -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);
+            
+            if(Vect__execute_pg(pg_info->conn, stmt) == -1) {
                 Vect__execute_pg(pg_info->conn, "ROLLBACK");
-                return 0;
+                return -1;
             }
+            continue;
         }
+        
+        /* determine id */
+        if (type == GV_CENTROID) {
+            topo_c = (struct P_topo_c *) Line->topo;
+            topo_id = topo_c->area;
+        }
+        else {
+            topo_id = line; /* GV_POINT | GV_LINE */
+        }
+        
+        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;
+        }
     }
     
     if (Vect__execute_pg(pg_info->conn, "COMMIT") == -1)

Modified: grass/trunk/lib/vector/Vlib/pg_local_proto.h
===================================================================
--- grass/trunk/lib/vector/Vlib/pg_local_proto.h	2012-11-28 22:43:25 UTC (rev 54096)
+++ grass/trunk/lib/vector/Vlib/pg_local_proto.h	2012-11-29 08:18:21 UTC (rev 54097)
@@ -71,6 +71,8 @@
                         const struct line_cats *,
                         const struct line_pnts **, int);
 
+int Vect__insert_face_pg(struct Map_info *, int);
+
 #endif /* HAVE_POSTGRES */
 
 #endif /* __PG_LOCAL_PROTO_H__ */

Modified: grass/trunk/lib/vector/Vlib/read_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/read_pg.c	2012-11-28 22:43:25 UTC (rev 54096)
+++ grass/trunk/lib/vector/Vlib/read_pg.c	2012-11-29 08:18:21 UTC (rev 54097)
@@ -174,9 +174,11 @@
         else {
             /* ignore constraints */
             ret = read_next_line_pg(Map, line_p, line_c, TRUE);
-            if (ret != Line->type)
-                G_fatal_error(_("Unexpected feature type (%d) - should be (%d)"),
-                              ret, Line->type);
+            if (ret != Line->type) {
+                G_warning(_("Unexpected feature type (%d) - should be (%d)"),
+                          ret, Line->type);
+                return -1;
+            }
         }
 
         if (Map->constraint.region_flag) {
@@ -463,6 +465,7 @@
  */
 SF_FeatureType get_feature(struct Format_info_pg *pg_info, int fid, int type)
 {
+    int seq_type;
     int force_type; /* force type (GV_BOUNDARY or GV_CENTROID) for topo access only */
     char *data;
     char stmt[DB_SQL_MAX];
@@ -576,9 +579,11 @@
     if (pg_info->toposchema_name) {
         if (fid < 0) {
             /* sequatial access */
-            if (strcmp(PQgetvalue(pg_info->res, pg_info->next_line, 2), "b") == 0)
+            seq_type = atoi(PQgetvalue(pg_info->res, pg_info->next_line, 2));
+            if (seq_type == GV_BOUNDARY ||
+                (seq_type == GV_LINE && pg_info->feature_type == SF_POLYGON))
                 force_type = GV_BOUNDARY;
-            else if (strcmp(PQgetvalue(pg_info->res, pg_info->next_line, 2), "c") == 0)
+            else if (seq_type == GV_CENTROID)
                 force_type = GV_CENTROID;
         }
         else {
@@ -1172,23 +1177,23 @@
         sprintf(stmt,
                 "DECLARE %s_%s%p CURSOR FOR "
                 "SELECT geom,fid,type FROM ("
-                "SELECT node_id AS fid,geom, 'p' AS type FROM \"%s\".node WHERE "
+                "SELECT node_id AS fid,geom, %d 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 "
-                "node_id AS fid,geom, 'c' AS type FROM \"%s\".node WHERE "
+                "node_id AS fid,geom, %d 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); 
+                "UNION ALL SELECT edge_id AS fid, geom, %d AS type FROM \"%s\".edge WHERE "
+                "left_face = 0 AND right_face = 0 UNION ALL SELECT edge_id AS fid, geom, %d AS type FROM "
+                "\"%s\".edge WHERE left_face != 0 OR right_face != 0 ) AS foo ORDER BY type,fid",
+                pg_info->schema_name, pg_info->table_name, pg_info->conn, GV_POINT,
+                pg_info->toposchema_name, pg_info->toposchema_name, pg_info->toposchema_name,
+                GV_CENTROID, pg_info->toposchema_name, pg_info->toposchema_name,
+                GV_LINE, pg_info->toposchema_name, GV_BOUNDARY, pg_info->toposchema_name); 
     }
     G_debug(2, "SQL: %s", stmt);
     

Modified: grass/trunk/lib/vector/Vlib/write_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/write_pg.c	2012-11-28 22:43:25 UTC (rev 54096)
+++ grass/trunk/lib/vector/Vlib/write_pg.c	2012-11-29 08:18:21 UTC (rev 54097)
@@ -57,7 +57,6 @@
                                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);
-static int insert_face(struct Map_info *, int);
 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);
@@ -132,7 +131,7 @@
     }
     else {                          /* PostGIS topology */
         if (Map->plus.built < GV_BUILD_BASE)
-            Map->plus.built = GV_BUILD_ALL;
+            Map->plus.built = GV_BUILD_BASE; /* update build level */
         return write_line_tp(Map, type, FALSE, points, cats);
     }
 #else
@@ -1362,7 +1361,7 @@
   \return 0 on error
   \return area id on success (>0)
 */
-int insert_face(struct Map_info *Map, int area)
+int Vect__insert_face_pg(struct Map_info *Map, int area)
 {
     char *stmt;
     
@@ -1603,7 +1602,7 @@
         if (area <= 0) /* no area - skip */
             continue;
 
-        face[s] = insert_face(Map, area);
+        face[s] = Vect__insert_face_pg(Map, area);
         if (face[s] < 1) {
             G_warning(_("Unable to create new face"));
             return -1;



More information about the grass-commit mailing list