[GRASS-SVN] r58363 - grass/trunk/lib/vector/Vlib
svn_grass at osgeo.org
svn_grass at osgeo.org
Tue Dec 3 02:47:15 PST 2013
Author: martinl
Date: 2013-12-03 02:47:15 -0800 (Tue, 03 Dec 2013)
New Revision: 58363
Modified:
grass/trunk/lib/vector/Vlib/build_pg.c
grass/trunk/lib/vector/Vlib/build_sfa.c
grass/trunk/lib/vector/Vlib/copy.c
grass/trunk/lib/vector/Vlib/local_proto.h
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/pg: implement creating simple features from topogeometry data
Modified: grass/trunk/lib/vector/Vlib/build_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/build_pg.c 2013-12-02 19:05:50 UTC (rev 58362)
+++ grass/trunk/lib/vector/Vlib/build_pg.c 2013-12-03 10:47:15 UTC (rev 58363)
@@ -35,6 +35,7 @@
static int write_areas(const struct Plus_head *, const struct Format_info_pg *);
static int write_isles(const struct Plus_head *, const struct Format_info_pg *);
static void build_stmt_id(const void *, int, int, const struct Plus_head *, char **, size_t *);
+static int create_simple_feature_from_topo(struct Map_info *);
#endif
/*!
@@ -136,6 +137,7 @@
int area, nareas, isle, nisles;
int face[2];
char stmt[DB_SQL_MAX];
+ char *def_file;
struct Plus_head *plus;
struct Format_info_pg *pg_info;
@@ -395,6 +397,31 @@
if (Vect__execute_pg(pg_info->conn, "COMMIT") == -1)
return 0;
+ /* check if we want to create simple features from topogeometry
+ data */
+ def_file = getenv("GRASS_VECTOR_PGFILE");
+
+ if (G_find_file2("", def_file ? def_file : "PG", G_mapset())) {
+ FILE *fp;
+ const char *p;
+
+ struct Key_Value *key_val;
+ fp = G_fopen_old("", def_file ? def_file : "PG", G_mapset());
+ if (!fp) {
+ G_fatal_error(_("Unable to open PG file"));
+ }
+ key_val = G_fread_key_value(fp);
+ fclose(fp);
+
+ /* build simple features from topogeometry data */
+ p = G_find_key_value("simple_feature", key_val);
+ if (p && G_strcasecmp(p, "yes") == 0)
+ if (create_simple_feature_from_topo(Map) != 0)
+ return 0;
+
+ G_free_key_value(key_val);
+ }
+
return 1;
}
@@ -948,4 +975,48 @@
return 0;
}
+/*!
+ \brief Create simple features geometry from topogeometry data
+
+ \param Map pointer to Map_info struct
+
+ \return 0 on success
+ \return -1 on error
+*/
+int create_simple_feature_from_topo(struct Map_info *Map)
+{
+ char stmt[DB_SQL_MAX];
+
+ struct Format_info_pg *pg_info;
+
+ pg_info = &(Map->fInfo.pg);
+
+ G_debug(1, "build_simple_feature_from_topo(): %d", pg_info->feature_type);
+
+ G_message(_("Create simple features topology from topogeometry data..."));
+ Vect__execute_pg(pg_info->conn, "BEGIN");
+ if (pg_info->feature_type == SF_POINT ||
+ pg_info->feature_type == SF_LINESTRING) {
+ sprintf(stmt, "UPDATE \"%s\".\"%s\" SET %s = (SELECT geom FROM \"%s\".node "
+ "WHERE node_id = (%s).id)", pg_info->schema_name, pg_info->table_name,
+ pg_info->geom_column, pg_info->toposchema_name, pg_info->topogeom_column);
+
+ if(Vect__execute_pg(pg_info->conn, stmt) == -1) {
+ Vect__execute_pg(pg_info->conn, "ROLLBACK");
+ return -1;
+
+ }
+ }
+ else if (pg_info->feature_type == SF_POLYGON) {
+ Vect__copy_areas(Map, 1, Map);
+ }
+ else {
+ G_warning(_("Unable to build simple features from topogeometry data. "
+ "Unsupported type %d."), pg_info->feature_type);
+ }
+
+ Vect__execute_pg(pg_info->conn, "COMMIT");
+
+ return 0;
+}
#endif
Modified: grass/trunk/lib/vector/Vlib/build_sfa.c
===================================================================
--- grass/trunk/lib/vector/Vlib/build_sfa.c 2013-12-02 19:05:50 UTC (rev 58362)
+++ grass/trunk/lib/vector/Vlib/build_sfa.c 2013-12-03 10:47:15 UTC (rev 58363)
@@ -329,7 +329,7 @@
G_zero(&fparts, sizeof(struct feat_parts));
/* get all features */
- if (Vect__open_cursor_next_line_pg(pg_info, TRUE) != 0)
+ if (Vect__open_cursor_next_line_pg(pg_info, TRUE, Map->plus.built) != 0)
return;
/* scan records */
Modified: grass/trunk/lib/vector/Vlib/copy.c
===================================================================
--- grass/trunk/lib/vector/Vlib/copy.c 2013-12-02 19:05:50 UTC (rev 58362)
+++ grass/trunk/lib/vector/Vlib/copy.c 2013-12-03 10:47:15 UTC (rev 58363)
@@ -43,7 +43,6 @@
static int copy_line_nodes(const struct Map_info *, int, int, struct line_pnts *,
struct Map_info *);
static int is_isle(const struct Map_info *, int);
-static int copy_areas(const struct Map_info *, int, struct Map_info *);
/*!
\brief Copy all alive vector features from input vector map to
@@ -125,7 +124,7 @@
if (topo == TOPO_NONE) {
/* copy areas - external formats and simple features access only */
- ret += copy_areas(In, field, Out);
+ ret += Vect__copy_areas(In, field, Out);
}
}
else {
@@ -460,7 +459,7 @@
\return 0 on success
\return 1 on error
*/
-int copy_areas(const struct Map_info *In, int field, struct Map_info *Out)
+int Vect__copy_areas(const struct Map_info *In, int field, struct Map_info *Out)
{
int i, area, nareas, cat, isle, nisles, nparts_alloc, nskipped;
struct line_pnts **Points;
@@ -526,11 +525,22 @@
Vect_get_isle_points(In, isle, Points[i + 1]);
}
- if (0 > V2__write_area_sfa(Out, (const struct line_pnts **) Points,
- nisles + 1, Cats)) {
- G_warning(_("Writing area %d failed"), area);
- return -1;
+ if (In != Out) {
+ if (0 > V2__write_area_sfa(Out, (const struct line_pnts **) Points,
+ nisles + 1, Cats)) {
+ G_warning(_("Writing area %d failed"), area);
+ return -1;
+ }
}
+#ifdef HAVE_POSTGRES
+ else { /* building simple features geometry from topogeometry data */
+ if (0 > V2__update_area_pg(Out, (const struct line_pnts **) Points,
+ nisles + 1, cat)) {
+ G_warning(_("Writing area %d failed"), area);
+ return -1;
+ }
+ }
+#endif
}
if (nskipped > 0)
Modified: grass/trunk/lib/vector/Vlib/local_proto.h
===================================================================
--- grass/trunk/lib/vector/Vlib/local_proto.h 2013-12-02 19:05:50 UTC (rev 58362)
+++ grass/trunk/lib/vector/Vlib/local_proto.h 2013-12-03 10:47:15 UTC (rev 58363)
@@ -18,6 +18,9 @@
void Vect__free_cache(struct Format_info_cache *);
void Vect__free_offset(struct Format_info_offset *);
+/* copy.c */
+int Vect__copy_areas(const struct Map_info *, int, struct Map_info *);
+
/* map.c */
int Vect__delete(const char *, int);
Modified: grass/trunk/lib/vector/Vlib/pg_local_proto.h
===================================================================
--- grass/trunk/lib/vector/Vlib/pg_local_proto.h 2013-12-02 19:05:50 UTC (rev 58362)
+++ grass/trunk/lib/vector/Vlib/pg_local_proto.h 2013-12-03 10:47:15 UTC (rev 58363)
@@ -68,7 +68,7 @@
SF_FeatureType Vect__cache_feature_pg(const char *, int, int,
struct Format_info_cache *,
struct feat_parts *);
-int Vect__open_cursor_next_line_pg(struct Format_info_pg *, int);
+int Vect__open_cursor_next_line_pg(struct Format_info_pg *, int, int);
int Vect__open_cursor_line_pg(struct Format_info_pg *, int, int);
int Vect__close_cursor_pg(struct Format_info_pg *);
int Vect__select_line_pg(struct Format_info_pg *, int, int);
@@ -80,6 +80,9 @@
off_t V2__write_node_pg(struct Map_info *, const struct line_pnts *);
off_t V2__write_area_pg(struct Map_info *, const struct line_pnts **, int,
const struct line_cats *);
+int V2__update_area_pg(struct Map_info *, const struct line_pnts **, int,
+ int);
+
int Vect__insert_face_pg(struct Map_info *, int);
/* open_pg.c */
Modified: grass/trunk/lib/vector/Vlib/read_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/read_pg.c 2013-12-02 19:05:50 UTC (rev 58362)
+++ grass/trunk/lib/vector/Vlib/read_pg.c 2013-12-03 10:47:15 UTC (rev 58363)
@@ -41,7 +41,7 @@
static int read_next_line_pg(struct Map_info *,
struct line_pnts *, struct line_cats *, int);
-SF_FeatureType get_feature(struct Format_info_pg *, int, int);
+SF_FeatureType get_feature(struct Map_info *, int, int);
static unsigned char *hex_to_wkb(const char *, int *);
static int point_from_wkb(const unsigned char *, int, int, int,
struct line_pnts *);
@@ -266,7 +266,7 @@
G_debug(3, "read (%s) feature (fid = %ld) to cache",
pg_info->table_name, fid);
- get_feature(pg_info, fid, -1);
+ get_feature(Map, fid, -1);
if (pg_info->cache.sf_type == SF_NONE) {
G_warning(_("Feature %ld without geometry skipped"), fid);
@@ -369,7 +369,7 @@
line, pg_info->cache.lines_types[cache_idx], Line->type);
}
else {
- get_feature(pg_info, fid, Line->type);
+ get_feature(Map, fid, Line->type);
cache_idx = 0;
}
@@ -465,7 +465,7 @@
}
/* cache feature -> line_p & line_c */
- sf_type = get_feature(pg_info, -1, -1);
+ sf_type = get_feature(Map, -1, -1);
if (sf_type == SF_NONE) {
G_warning(_("Feature %ld without geometry skipped"), pg_info->cache.fid);
@@ -554,26 +554,30 @@
Geometry is stored in lines cache.
- \param[in,out] pg_info pointer to Format_info_pg struct
+ \param[in,out] Map pointer to Map_info struct
\param fid feature id to be read (-1 for next)
\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)
+SF_FeatureType get_feature(struct Map_info *Map, int fid, int type)
{
int seq_type;
int force_type; /* force type (GV_BOUNDARY or GV_CENTROID) for topo access only */
char *data;
+ struct Format_info_pg *pg_info;
+
+ pg_info = &(Map->fInfo.pg);
+
if (!pg_info->geom_column && !pg_info->topogeom_column) {
G_warning(_("No geometry or topo geometry column defined"));
return -1;
}
if (fid < 1) { /* sequantial access */
if (pg_info->cursor_name == NULL &&
- Vect__open_cursor_next_line_pg(pg_info, FALSE) != 0)
+ Vect__open_cursor_next_line_pg(pg_info, FALSE, Map->plus.built) != 0)
return -1;
}
else { /* random access */
@@ -670,15 +674,17 @@
/* cache also categories (only for PostGIS Topology) */
if (pg_info->toposchema_name) {
- int col_idx;
+ int cat, col_idx;
- col_idx = type & GV_POINTS ? 2 : 3;
+ col_idx = fid < 0 ? 3 : 2; /* TODO: dermine col_idx for random access */
if (!PQgetisnull(pg_info->res, pg_info->next_line, col_idx))
- pg_info->cache.lines_cats[pg_info->cache.lines_next] =
- atoi(PQgetvalue(pg_info->res, pg_info->next_line, col_idx));
+ cat = atoi(PQgetvalue(pg_info->res, pg_info->next_line, col_idx));
else
- pg_info->cache.lines_cats[pg_info->cache.lines_next] = -1; /* no cat */
+ cat = -1; /* no cat */
+ pg_info->cache.lines_cats[pg_info->cache.lines_next] = cat;
+ G_debug(3, "line=%d, type=%d -> cat=%d", pg_info->cache.lines_next+1,
+ pg_info->cache.lines_types[pg_info->cache.lines_next], cat);
}
/* set feature id */
@@ -1223,7 +1229,7 @@
\return 0 on success
\return -1 on failure
*/
-int Vect__open_cursor_next_line_pg(struct Format_info_pg *pg_info, int fetch_all)
+int Vect__open_cursor_next_line_pg(struct Format_info_pg *pg_info, int fetch_all, int built_level)
{
char stmt[DB_SQL_MAX];
@@ -1243,7 +1249,7 @@
pg_info->table_name, pg_info->fid_column);
}
else {
- /* topology access (geom,fid,type) */
+ /* topology access (geom,id,fid,type) */
/* TODO: optimize SQL statement (for points/centroids) */
sprintf(stmt,
"DECLARE %s CURSOR FOR "
@@ -1254,7 +1260,7 @@
"(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 tt.node_id AS id,tt.geom, %d AS type, ft.%s AS fid FROM \"%s\".node AS tt "
- "LEFT JOIN \"%s\".\"%s\" AS ft ON (%s).type = 3 AND (%s).id = containing_face "
+ "LEFT JOIN \"%s\".\"%s\" AS ft ON (%s).type = 3 AND (%s).id = %s "
"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) UNION ALL "
@@ -1268,7 +1274,9 @@
GV_POINT, pg_info->fid_column, pg_info->toposchema_name, pg_info->schema_name, pg_info->table_name,
pg_info->topogeom_column, pg_info->topogeom_column, pg_info->toposchema_name, pg_info->toposchema_name,
GV_CENTROID, pg_info->fid_column, pg_info->toposchema_name, pg_info->schema_name, pg_info->table_name,
- pg_info->topogeom_column, pg_info->topogeom_column, pg_info->toposchema_name, pg_info->toposchema_name,
+ pg_info->topogeom_column, pg_info->topogeom_column,
+ built_level >= GV_BUILD_CENTROIDS ? "containing_face" : "node_id",
+ pg_info->toposchema_name, pg_info->toposchema_name,
GV_LINE, pg_info->fid_column, pg_info->toposchema_name, pg_info->schema_name, pg_info->table_name,
pg_info->topogeom_column, pg_info->topogeom_column,
GV_BOUNDARY, pg_info->fid_column, pg_info->toposchema_name, pg_info->schema_name, pg_info->table_name,
Modified: grass/trunk/lib/vector/Vlib/write_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/write_pg.c 2013-12-02 19:05:50 UTC (rev 58362)
+++ grass/trunk/lib/vector/Vlib/write_pg.c 2013-12-03 10:47:15 UTC (rev 58363)
@@ -516,6 +516,61 @@
}
/*!
+ \brief Updates simple features geometry from GRASS-like topo
+
+ \param Map pointer to Map_info structure
+ \param points feature geometry (exterior + interior rings)
+ \param nparts number of parts including exterior ring
+ \param cat area category
+
+ \return 0 on success
+ \return -1 on error
+*/
+int V2__update_area_pg(struct Map_info *Map,
+ const struct line_pnts **points, int nparts,
+ int cat)
+{
+ int part, npoints;
+ char *stmt, *geom_data;
+
+ struct Format_info_pg *pg_info;
+
+ pg_info = &(Map->fInfo.pg);
+
+ for (part = 0; part < nparts; part++) {
+ npoints = points[part]->n_points - 1;
+ if (points[part]->x[0] != points[part]->x[npoints] ||
+ points[part]->y[0] != points[part]->y[npoints] ||
+ points[part]->z[0] != points[part]->z[npoints]) {
+ G_warning(_("Boundary is not closed. Skipping."));
+ return -1;
+ }
+ }
+
+ geom_data = line_to_wkb(pg_info, points, nparts, GV_AREA, Vect_is_3d(Map));
+ if (!geom_data)
+ return -1;
+
+ stmt = NULL;
+ G_asprintf(&stmt, "UPDATE \"%s\".\"%s\" SET %s = '%s'::GEOMETRY WHERE %s = %d",
+ pg_info->schema_name, pg_info->table_name, pg_info->geom_column,
+ geom_data, pg_info->fid_column,
+ cat);
+ if (Vect__execute_pg(pg_info->conn, stmt) == -1) {
+ /* rollback transaction */
+ Vect__execute_pg(pg_info->conn, "ROLLBACK");
+ G_free(geom_data);
+ G_free(stmt);
+ return -1;
+ }
+
+ G_free(geom_data);
+ G_free(stmt);
+
+ return 0;
+}
+
+/*!
\brief Create new feature table
\param pg_info pointer to Format_info_pg
@@ -559,6 +614,8 @@
p = G_find_key_value("primary_key", key_val);
if (p && G_strcasecmp(p, "no") == 0)
primary_key = FALSE;
+
+ G_free_key_value(key_val);
}
}
@@ -824,6 +881,14 @@
if (p && G_strcasecmp(p, "yes") == 0)
pg_info->topo_geo_only = TRUE;
G_debug(1, "PG: topo_geo_only :%d", pg_info->topo_geo_only);
+
+ /* build simple features from topogeometry data */
+ p = G_find_key_value("simple_feature", key_val);
+ if (p && G_strcasecmp(p, "yes") == 0)
+ pg_info->topo_geo_only = TRUE;
+ G_debug(1, "PG: topo_geo_only :%d", pg_info->topo_geo_only);
+
+ G_free_key_value(key_val);
}
/* begin transaction (create topo schema) */
@@ -1689,8 +1754,8 @@
wkb_data = point_to_wkb(byte_order, points[0], with_z, &nbytes);
else if (type == GV_LINE)
wkb_data = linestring_to_wkb(byte_order, points[0], with_z, &nbytes);
- else if (type & (GV_BOUNDARY | GV_FACE)) {
- if (!pg_info->toposchema_name) {
+ else if (type & (GV_BOUNDARY | GV_FACE | GV_AREA)) {
+ if (!pg_info->toposchema_name || type == GV_AREA) {
/* PostGIS simple feature access */
wkb_data = polygon_to_wkb(byte_order, points, nparts,
with_z, &nbytes);
@@ -1839,6 +1904,7 @@
return -1;
}
G_free(geom_data);
+ G_free(stmt);
return pg_info->toposchema_name ? topo_id : 0;
}
More information about the grass-commit
mailing list