[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