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

svn_grass at osgeo.org svn_grass at osgeo.org
Wed Nov 28 08:51:26 PST 2012


Author: martinl
Date: 2012-11-28 08:51:25 -0800 (Wed, 28 Nov 2012)
New Revision: 54091

Modified:
   grass/trunk/lib/vector/Vlib/open_pg.c
   grass/trunk/lib/vector/Vlib/read_pg.c
   grass/trunk/lib/vector/Vlib/write_pg.c
Log:
vlib/PostGIS Topo: better support for areas (work in progress)


Modified: grass/trunk/lib/vector/Vlib/open_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/open_pg.c	2012-11-28 16:34:03 UTC (rev 54090)
+++ grass/trunk/lib/vector/Vlib/open_pg.c	2012-11-28 16:51:25 UTC (rev 54091)
@@ -43,7 +43,6 @@
 static void connect_db(struct Format_info_pg *);
 static int check_topo(struct Format_info_pg *, struct Plus_head *);
 static int parse_bbox(const char *, struct bound_box *);
-static int num_of_records(const struct Format_info_pg *, const char *);
 static struct P_node *read_p_node(struct Plus_head *, int, int,
                                   const char *, struct Format_info_pg *);
 static struct P_line *read_p_line(struct Plus_head *, int,
@@ -442,6 +441,7 @@
     
     /* free and init plus structure */
     dig_init_plus(plus);
+    plus->Spidx_new = TRUE;
     
     return Vect__load_plus_pg(Map, head_only);
 #else
@@ -1104,35 +1104,6 @@
 }
 
 /*!
-  \brief Get number of records for given SQL statement
-
-  \param stmt string buffer with SQL statement
-  
-  \return number of returned records
-  \return -1 on error
-*/
-int num_of_records(const struct Format_info_pg *pg_info,
-                   const char *stmt)
-{
-    int result;
-    PGresult *res;
-
-    G_debug(2, "SQL: %s", stmt);
-    res = PQexec(pg_info->conn, stmt);
-    if (!res || PQresultStatus(res) != PGRES_TUPLES_OK ||
-        PQntuples(res) != 1) {
-        G_warning(_("Unable to get number of records for:\n%s"), stmt);
-        if (res)
-            PQclear(res);
-        return -1;
-    }
-    result = atoi(PQgetvalue(res, 0, 0));
-    PQclear(res);
-    
-    return result;
-}
-
-/*!
   \brief Read P_node structure
   
   See dig_Rd_P_node() for reference.
@@ -1172,7 +1143,7 @@
     G_debug(2, "SQL: %s", stmt);
     res = PQexec(pg_info->conn, stmt);
     if (!res || PQresultStatus(res) != PGRES_TUPLES_OK) {
-        G_warning(_("Unable to read node %d"), id);
+        G_warning(_("Inconsistency in topology: unable to read node %d"), id);
         if (res)
             PQclear(res);
         return NULL;
@@ -1212,7 +1183,7 @@
     /* get node coordinates */
     if (SF_POINT != Vect__cache_feature_pg(wkb_data, FALSE, FALSE,
                                            &(pg_info->cache), NULL))
-        G_warning(_("Node %d: unexpected feature type %d"),
+        G_warning(_("Inconsistency in topology: node %d - unexpected feature type %d"),
                   n, pg_info->cache.sf_type);
     
     points = pg_info->cache.lines[0];
@@ -1226,6 +1197,10 @@
     /* update spatial index */
     dig_spidx_add_node(plus, n, node->x, node->y, node->z);
     
+    if (plus->uplist.do_uplist)
+        /* collect updated nodes if requested */
+        dig_node_add_updated(plus, n);
+    
     plus->Node[n] = node;
     
     return node;
@@ -1315,7 +1290,6 @@
             
             topo->area = data->left_face;
         }
-        /* TODO: faces | kernels */
     }
 
     /* update spatial index */
@@ -1323,11 +1297,17 @@
     itype = cache->lines_types[0];
     if ((line->type & GV_POINTS && itype != GV_POINT) ||
         (line->type & GV_LINES  && itype != GV_LINE))
-        G_warning(_("Line %d: unexpected feature type"), n);
+        G_warning(_("Inconsistency in topology: line %d - unexpected feature type"), n);
     
     points = cache->lines[0];
     dig_line_box(points, &box);
     dig_spidx_add_line(plus, n, &box);
+
+    if (plus->uplist.do_uplist) {
+        /* collect updated lines if requested */
+        dig_line_add_updated(plus, n);
+        plus->uplist.uplines_offset[plus->uplist.n_uplines - 1] = line->offset;
+    }
     
     plus->Line[n] = line;
     
@@ -1335,7 +1315,7 @@
 }
 
 /*!
-  \brief Read topo (from PostGIS topology schema) header info only
+  \brief Read topo from PostGIS topology schema -- header info only
 
   \param[in,out] plus pointer to Plus_head struct
 
@@ -1350,7 +1330,8 @@
     
     plus->off_t_size = -1;
     
-    /* fisrt try to get info from 'topology.grass */
+    /* get map bounding box
+       fisrt try to get info from 'topology.grass' table */
     sprintf(stmt,
             "SELECT %s FROM \"%s\".\"%s\" WHERE %s = %d",
             TOPO_BBOX, TOPO_SCHEMA, TOPO_TABLE, TOPO_ID, pg_info->toposchema_id);
@@ -1360,7 +1341,7 @@
         PQntuples(res) != 1) {
 	PQclear(res);
 	
-	/* try to calculate bbox from TopoGeometry elements */
+	/* otherwise try to calculate bbox from TopoGeometry elements */
 	sprintf(stmt,
 		"SELECT ST_3DExtent(%s) FROM \"%s\".\"%s\"",
 		pg_info->topogeom_column, pg_info->schema_name, pg_info->table_name);
@@ -1381,7 +1362,8 @@
     }
     PQclear(res);
     
-    /* number of topological primitives */
+    /* get number of topological elements */
+    
     /* nodes
        note: isolated nodes are registered in GRASS Topology model */
     sprintf(stmt,
@@ -1389,25 +1371,33 @@
             "FROM \"%s\".edge GROUP BY start_node UNION ALL SELECT end_node "
             "AS node FROM \"%s\".edge GROUP BY end_node) AS foo",
             pg_info->toposchema_name, pg_info->toposchema_name);
-    plus->n_nodes = num_of_records(pg_info, stmt);
+    plus->n_nodes = Vect__execute_get_value_pg(pg_info->conn, stmt);
     G_debug(3, "Vect_open_topo_pg(): n_nodes=%d", plus->n_nodes);
+    
     /* lines (edges in PostGIS Topology model) */
     sprintf(stmt,
             "SELECT COUNT(*) FROM \"%s\".edge",
             pg_info->toposchema_name);
     /* + isolated nodes as points
        + centroids */
-    plus->n_lines = num_of_records(pg_info, stmt); 
-    /* areas (faces in PostGIS Topology model)
+    plus->n_lines = Vect__execute_get_value_pg(pg_info->conn, stmt); 
+    
+    /* areas (faces with face_id > 0 in PostGIS Topology model) */
     sprintf(stmt,
-            "SELECT COUNT(*) FROM \"%s\".face WHERE mbr IS NOT NULL",
+            "SELECT COUNT(*) FROM \"%s\".face WHERE face_id > 0",
             pg_info->toposchema_name);
-    plus->n_areas = num_of_records(pg_info, stmt);
+    plus->n_areas = Vect__execute_get_value_pg(pg_info->conn, stmt);
     G_debug(3, "Vect_open_topo_pg(): n_areas=%d", plus->n_areas);
-    */
-    /* TODO: n_isles | n_volumes | n_holes */
+
+    /* isles (faces with face_id <=0 in PostGIS Topology model) */
+    sprintf(stmt,
+            "SELECT COUNT(*) FROM \"%s\".face WHERE face_id < 1",
+            pg_info->toposchema_name);
+    plus->n_isles = Vect__execute_get_value_pg(pg_info->conn, stmt);
+    G_debug(3, "Vect_open_topo_pg(): n_isles=%d", plus->n_isles);
     
-    /* number of features group by type */
+    /* number of features according the type */
+
     /* points */
     sprintf(stmt,
             "SELECT COUNT(*) FROM \"%s\".node WHERE containing_face "
@@ -1417,31 +1407,33 @@
             "\"%s\".edge GROUP BY end_node) AS foo)",
             pg_info->toposchema_name, pg_info->toposchema_name,
             pg_info->toposchema_name);
-    plus->n_plines = num_of_records(pg_info, stmt);
+    plus->n_plines = Vect__execute_get_value_pg(pg_info->conn, stmt);
     G_debug(3, "Vect_open_topo_pg(): n_plines=%d", plus->n_plines);
+    
     /* lines */
     sprintf(stmt,
             "SELECT COUNT(*) FROM \"%s\".edge WHERE "
             "left_face = 0 AND right_face = 0",
             pg_info->toposchema_name);
-    plus->n_llines = num_of_records(pg_info, stmt);
+    plus->n_llines = Vect__execute_get_value_pg(pg_info->conn, stmt);
     G_debug(3, "Vect_open_topo_pg(): n_llines=%d", plus->n_llines);
+
     /* boundaries */
     sprintf(stmt,
             "SELECT COUNT(*) FROM \"%s\".edge WHERE "
             "left_face != 0 OR right_face != 0",
             pg_info->toposchema_name);
-    plus->n_blines = num_of_records(pg_info, stmt);
+    plus->n_blines = Vect__execute_get_value_pg(pg_info->conn, stmt);
     G_debug(3, "Vect_open_topo_pg(): n_blines=%d", plus->n_blines);
+
     /* centroids */
     sprintf(stmt,
             "SELECT COUNT(*) FROM \"%s\".face WHERE mbr IS NOT NULL",
             pg_info->toposchema_name);
-    plus->n_clines = num_of_records(pg_info, stmt);
+    plus->n_clines = Vect__execute_get_value_pg(pg_info->conn, stmt);
     G_debug(3, "Vect_open_topo_pg(): n_clines=%d", plus->n_clines);
-    /* TODO: nflines | n_klines */
 
-    /* lines - register isolated nodes as points and centroids */
+    /* update number of lines - add points and centroids */
     plus->n_lines += plus->n_plines + plus->n_clines;
     G_debug(3, "Vect_open_topo_pg(): n_lines=%d", plus->n_lines);
 
@@ -1449,7 +1441,7 @@
 }
 
 /*!
-  \brief Read topo info (from PostGIS topology schema)
+  \brief Read topo info from PostGIS topology schema
 
   \param pg_info pointer to Format_info_pg
   \param[in,out] plus pointer to Plus_head struct
@@ -1460,14 +1452,16 @@
 */
 int Vect__load_plus_pg(struct Map_info *Map, int head_only)
 {
-    int i, id, ntuples;
+    int i, side, line, id, ntuples, area;
     char stmt[DB_SQL_MAX];
     struct edge_data line_data;
     
     struct Format_info_pg *pg_info;
     struct Plus_head *plus;
-    struct P_line *line;
-    struct P_area *area;
+    struct P_line *Line;
+    struct P_area *Area;
+    struct line_pnts *Points;
+    struct ilist *List;
     
     PGresult *res;
   
@@ -1480,8 +1474,11 @@
     if (head_only)
         return 0;
     
+    Points = Vect_new_line_struct();
+    List = Vect_new_list();
+        
     /* read nodes (GRASS Topo)
-       note: standalone nodes are ignored
+       note: standalone nodes (ie. points/centroids) are ignored
     */
     sprintf(stmt,
             "SELECT node_id,geom FROM \"%s\".node WHERE node_id IN "
@@ -1494,7 +1491,9 @@
     res = PQexec(pg_info->conn, stmt);
     if (!res || PQresultStatus(res) != PGRES_TUPLES_OK ||
         PQntuples(res) != plus->n_nodes) {
-        G_warning(_("Unable to read nodes"));
+        G_warning(_("Inconsistency in topology: number of "
+                    "nodes %d (should be %d)"),
+                  PQntuples(res), plus->n_nodes);
         if (res)
             PQclear(res);
         return -1;
@@ -1510,17 +1509,19 @@
     PQclear(res);
 
     /* read lines (GRASS Topo)
-       - standalone nodes -> points
+       - standalone nodes -> points|centroids
        - edges -> lines/boundaries
     */
     G_debug(3, "load_plus(): n_lines = %d", plus->n_lines);
     dig_alloc_lines(plus, plus->n_lines); 
+    G_zero(plus->Line, sizeof(struct P_line *) * (plus->n_lines + 1)); /* index starts at 1 */
     
-    /* read PostGIS Topo standalone nodes
+    /* read PostGIS Topo standalone nodes (containing_face is null)
        -> points
     */
     sprintf(stmt,
-            "SELECT node_id,geom FROM \"%s\".node WHERE node_id NOT IN "
+            "SELECT node_id,geom 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) ORDER BY node_id",
@@ -1530,7 +1531,9 @@
     res = PQexec(pg_info->conn, stmt);
     if (!res || PQresultStatus(res) != PGRES_TUPLES_OK ||
         PQntuples(res) > plus->n_plines) {
-        G_warning(_("Unable to read lines"));
+        G_warning(_("Inconsistency in topology: number of "
+                    "points %d (should be %d)"),
+                  PQntuples(res), plus->n_plines);
         if (res)
             PQclear(res);
         return -1;
@@ -1558,15 +1561,17 @@
     res = PQexec(pg_info->conn, stmt);
     if (!res || PQresultStatus(res) != PGRES_TUPLES_OK ||
         PQntuples(res) > plus->n_lines) {
-        G_warning(_("Unable to read lines"));
+        G_warning(_("Inconsistency in topology: number of "
+                    "lines %d (should be %d)"),
+                  PQntuples(res), plus->n_lines);
         if (res)
             PQclear(res);
         return -1;
     }
 
+    /* process edges (PostGIS Topo) */
     ntuples = PQntuples(res);
     for (i = 0; i < ntuples; i++) {
-        /* process edges (PostGIS Topo) */
         line_data.id         = atoi(PQgetvalue(res, i, 0));
         line_data.start_node = atoi(PQgetvalue(res, i, 1));
         line_data.end_node   = atoi(PQgetvalue(res, i, 2));
@@ -1575,77 +1580,92 @@
         line_data.wkb_geom   = (char *) PQgetvalue(res, i, 5);
         
         id = plus->n_plines + i + 1; /* points already registered */
-        line = read_p_line(plus, id, &line_data, &(pg_info->cache));
-        if (line_data.left_face != 0 || line_data.right_face != 0) {
-            /* boundary detected -> build area/isle on left and right*/
-            
-            int s, side;
-            for (s = 0; s < 2; s++) {
-                if (s == 0)
-                    side = GV_LEFT;
-                else
-                    side = GV_RIGHT;
-                
-                G_debug(3, "Build area for line = %d, side = %d",
-                        id, side);
-                Vect_build_line_area(Map, id, side);
-            }
-        }
-        if (line->type == GV_BOUNDARY) {
-            struct P_topo_b *topo;
+        read_p_line(plus, id, &line_data, &(pg_info->cache));
+        /* TODO: update category index */
+    }
+    PQclear(res);
 
-            if (line_data.left_face == 0)
-                line_data.left_face = -1;
-            if (line_data.right_face == 0)
-                line_data.right_face = -1;
+    /* read PostGIS Topo standalone nodes (containing_face is not null)
+       -> centroids
+    */
+    sprintf(stmt,
+            "SELECT node_id,geom,containing_face 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 ||
+        PQntuples(res) > plus->n_clines) {
+        G_warning(_("Inconsistency in topology: number of "
+                    "centroids %d (should be %d)"),
+                  PQntuples(res), plus->n_clines);
+        if (res)
+            PQclear(res);
+        return -1;
+    }
+    
+    G_zero(&line_data, sizeof(struct edge_data));
+    id = plus->n_plines + plus->n_llines + plus->n_blines + 1;
+    for (i = 0; i < plus->n_clines; i++) {
+        line_data.id = atoi(PQgetvalue(res, i, 0)); 
+        line_data.wkb_geom = (char *)PQgetvalue(res, i, 1);
+        line_data.left_face = atoi(PQgetvalue(res, i, 2)); /* face id */
+        /* area id and face id can be different */
+        
+        read_p_line(plus, id + i, &line_data, &(pg_info->cache));
+    }
+    PQclear(res);
+
+    /* build areas for boundaries
+       reset values -> build from scratch */
+    plus->n_areas = plus->n_isles = 0;
+    for (line = 1; line <= plus->n_lines; line++) {
+        Line = plus->Line[line]; /* centroids: Line is NULL */
+        if (!Line || Line->type != GV_BOUNDARY)
+            continue;
+        
+        for (i = 0; i < 2; i++) { /* for both sides build an area/isle */
+            side = i == 0 ? GV_LEFT : GV_RIGHT;
             
-            /* check topo - left / right areas */
-            topo = (struct P_topo_b *)line->topo;
-            if (topo->left != line_data.left_face)
-                G_warning(_("Left area detected as %d (should be %d"),
-                          topo->left, line_data.left_face);
-            if (topo->right != line_data.right_face)
-                G_warning(_("Right area detected as %d (should be %d"),
-                          topo->right, line_data.right_face);
+            G_debug(3, "Build area for line = %d, side = %d",
+                    id, side);
+            Vect_build_line_area(Map, line, side);
         }
     }
-    PQclear(res);
+    plus->built = GV_BUILD_AREAS;
+
+    /* TODO: attach isles */
+    plus->built = GV_BUILD_ATTACH_ISLES;
     
-    /* read PostGIS Topo standalone nodes (containing_face is not null)
-       -> centroids
-    */
+    /* attach centroids */
     if (plus->n_areas > 0) {
-        sprintf(stmt,
-                "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 ||
-            PQntuples(res) > plus->n_areas) {
-            G_warning(_("Unable to attach centroids"));
-            if (res)
-                PQclear(res);
-            return -1;
-        }
+        struct P_topo_c *topo;
         
-        G_zero(&line_data, sizeof(struct edge_data));
-        for (i = 1; i <= plus->n_areas; i++) {
-            area = plus->Area[i];
+        for (line = 1; line <= plus->n_lines; line++) {
+            Line = plus->Line[line];
+            if (Line->type != GV_CENTROID)
+                continue;
             
-            id = plus->n_lines - plus->n_clines + i;
-            line_data.id = line_data.left_face = i;
-            line_data.wkb_geom = (char *)PQgetvalue(res, 0, 0);
-            
-            read_p_line(plus, id, &line_data, &(pg_info->cache));
-            area->centroid = line_data.id;
+            Vect_read_line(Map, Points, NULL, line);
+            area = Vect_find_area(Map, Points->x[0], Points->y[0]);
+            topo = (struct P_topo_c *)Line->topo;
+            topo->area = area;
+            Area = plus->Area[topo->area];
+            Area->centroid = Line->offset;
         }
     }
-
+    plus->built = GV_BUILD_CENTROIDS;
+    
+    /* done */
+    plus->built = GV_BUILD_ALL;
+    
+    Vect_destroy_line_struct(Points);
+    Vect_destroy_list(List);
+    
     return 0;
 }
 

Modified: grass/trunk/lib/vector/Vlib/read_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/read_pg.c	2012-11-28 16:34:03 UTC (rev 54090)
+++ grass/trunk/lib/vector/Vlib/read_pg.c	2012-11-28 16:51:25 UTC (rev 54091)
@@ -137,8 +137,6 @@
         if (Line->type == GV_CENTROID) {
             G_debug(4, "Centroid");
 
-            Map->next_line++;
-
             if (line_p != NULL) {
                 int i, found;
                 struct bound_box box;
@@ -174,10 +172,10 @@
             ret = GV_CENTROID;
         }
         else {
-            /* ignore constraints, Map->next_line incremented */
+            /* ignore constraints */
             ret = read_next_line_pg(Map, line_p, line_c, TRUE);
             if (ret != Line->type)
-                G_fatal_error(_("Unexpected feature type (%s) - should be (%d)"),
+                G_fatal_error(_("Unexpected feature type (%d) - should be (%d)"),
                               ret, Line->type);
         }
 
@@ -185,12 +183,15 @@
             /* skip by region */
             Vect_line_box(line_p, &lbox);
             if (!Vect_box_overlap(&lbox, &mbox)) {
+                Map->next_line++;
                 continue;
             }
         }
 
         /* skip by field ignored */
-
+        
+        Map->next_line++; /* read next */
+                    
         return ret;
     }
 #else
@@ -479,7 +480,7 @@
     }
     else {
         /* random access */
-        if (!pg_info->fid_column) {
+        if (!pg_info->fid_column && !pg_info->toposchema_name) {
             G_warning(_("Random access not supported. "
                         "Primary key not defined."));
             return -1;
@@ -1189,7 +1190,7 @@
                 pg_info->toposchema_name, pg_info->toposchema_name,
                 pg_info->toposchema_name, pg_info->toposchema_name, pg_info->toposchema_name); 
     }
-    G_debug(3, "SQL: %s", stmt);
+    G_debug(2, "SQL: %s", stmt);
     
     if (Vect__execute_pg(pg_info->conn, stmt) == -1) {
         Vect__execute_pg(pg_info->conn, "ROLLBACK");

Modified: grass/trunk/lib/vector/Vlib/write_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/write_pg.c	2012-11-28 16:34:03 UTC (rev 54090)
+++ grass/trunk/lib/vector/Vlib/write_pg.c	2012-11-28 16:51:25 UTC (rev 54091)
@@ -1487,12 +1487,12 @@
     pg_info = &(Map->fInfo.pg);
     
     if (line < 1 || line > Vect_get_num_lines(Map)) {
-        G_warning(_("Inconsistency in topology detected"));
+        G_warning(_("Inconsistency in topology: invalid feature id"));
         return -1;
     }
     Line = Map->plus.Line[line];
     if (!Line) {
-        G_warning(_("Inconsistency in topology detected"));
+        G_warning(_("Inconsistency in topology: dead line found"));
         return -1;
     }
     
@@ -1518,8 +1518,8 @@
                 nle = next_edge; /* update next left edge for end node */
         }
         else {
-            G_warning(_("Inconsistency in topology detected. "
-                        "Unable to determine next left/right edge."));
+            G_warning(_("Inconsistency in topology detected: "
+                        "unable to determine next left/right edge."));
             return -1;
         }
     }
@@ -1585,12 +1585,12 @@
     pg_info = &(Map->fInfo.pg);
     
     if (line < 1 || line > Vect_get_num_lines(Map)) {
-        G_warning(_("Inconsistency in topology detected"));
+        G_warning(_("Inconsistency in topology detected: invalid feature id"));
         return -1;
     }
     Line = Map->plus.Line[line];
     if (!Line) {
-        G_warning(_("Inconsistency in topology detected"));
+        G_warning(_("Inconsistency in topology detected: dead line found"));
         return -1;
     }
     



More information about the grass-commit mailing list