23 #include "local_proto.h" 26 #include "pg_local_proto.h" 28 static int build_topo(
struct Map_info *,
int);
29 static int build_topogeom_stmt(
const struct Format_info_pg *,
int,
int,
int,
char *);
37 static void build_stmt_id(
const void *,
int,
int,
const struct Plus_head *,
char **,
size_t *);
38 static int create_simple_feature_from_topo(
struct Map_info *);
66 G_debug(1,
"Vect_build_pg(): db='%s' table='%s', build=%d",
77 if (build == plus->
built)
93 G_warning(
_(
"Feature table <%s> has no primary key defined"),
95 G_warning(
_(
"Random read is not supported for this layer. " 96 "Unable to build topology."));
101 G_message(
_(
"Using external data format '%s' (feature type '%s')"),
105 G_message(
_(
"Building pseudo-topology over simple features..."));
107 G_message(
_(
"Building topology from PostGIS topology schema <%s>..."),
115 return build_topo(Map, build);
117 G_fatal_error(
_(
"GRASS is not compiled with PostgreSQL support"));
134 int build_topo(
struct Map_info *Map,
int build)
136 int line, type, s, n_nodes;
137 int area, nareas, isle, nisles;
154 if (build < plus->built) {
212 G_warning(
_(
"Inconsistency in topology: number of nodes %d (should be %d)"),
216 save_map_bbox(pg_info, &(plus->
box));
226 write_nodes(plus, pg_info);
227 write_lines(plus, pg_info);
237 G_message(
_(
"Cleaning-up topology schema..."));
239 sprintf(stmt,
"UPDATE \"%s\".node SET containing_face = 0 WHERE " 248 sprintf(stmt,
"UPDATE \"%s\".edge_data SET left_face = 0, right_face = 0",
257 sprintf(stmt,
"DELETE FROM \"%s\".face WHERE " 265 sprintf(stmt,
"DELETE FROM \"%s\".%s", pg_info->
toposchema_name, TOPO_TABLE_AREA);
272 sprintf(stmt,
"DELETE FROM \"%s\".%s", pg_info->
toposchema_name, TOPO_TABLE_ISLE);
284 for (area = 1; area <= nareas; area++) {
297 G_debug(3,
"Area %d without centroid, skipped", area);
302 sprintf(stmt,
"UPDATE \"%s\".node SET " 303 "containing_face = %d WHERE node_id = %d",
315 for (line = 1; line <= plus->
n_lines; line++) {
323 G_warning(
_(
"Inconsistency in topology detected. " 324 "Dead line found."));
330 for (s = 0; s < 2; s++) {
331 face[s] = s == 0 ? topo_b->
left : topo_b->
right;
334 Isle = plus->
Isle[abs(face[s])];
335 face[s] = Isle->
area;
338 G_debug(3,
"update edge %d: left_face = %d, right_face = %d",
339 (
int)Line->
offset, face[0], face[1]);
341 sprintf(stmt,
"UPDATE \"%s\".edge_data SET " 342 "left_face = %d, right_face = %d " 344 face[0], face[1], (
int) Line->
offset);
354 write_areas(plus, pg_info);
361 for(isle = 1; isle <= nisles; isle++) {
362 Isle = plus->
Isle[isle];
368 write_isles(plus, pg_info);
377 G_message(
_(
"Updating TopoGeometry data..."));
378 for (area = 1; area <= plus->
n_areas; area++) {
384 Line = plus->
Line[centroid];
404 def_file =
getenv(
"GRASS_VECTOR_PGFILE");
424 if (create_simple_feature_from_topo(Map) != 0)
448 int type,
int topo_id,
int fid,
char *stmt)
464 G_warning(
_(
"Unsupported topo geometry type %d"), type);
468 sprintf(stmt,
"UPDATE \"%s\".\"%s\" SET %s = " 469 "'(%d, 1, %d, %d)'::topology.TopoGeometry " 470 "WHERE (%s).id = %d",
492 if (create_topo_grass(pg_info) == -1) {
493 G_warning(
_(
"Unable to create <%s.%s>"), TOPO_SCHEMA, TOPO_TABLE);
498 if (has_topo_grass(pg_info)) {
500 sprintf(stmt,
"UPDATE \"%s\".\"%s\" SET %s = " 501 "'BOX3D(%.12f %.12f %.12f, %.12f %.12f %.12f)'::box3d WHERE %s = %d",
502 TOPO_SCHEMA, TOPO_TABLE, TOPO_BBOX,
503 box->
W, box->
S, box->
B, box->
E, box->
N, box->
T,
508 sprintf(stmt,
"INSERT INTO \"%s\".\"%s\" (%s, %s) " 509 "VALUES(%d, 'BOX3D(%.12f %.12f %.12f, %.12f %.12f %.12f)'::box3d)",
510 TOPO_SCHEMA, TOPO_TABLE, TOPO_ID, TOPO_BBOX, pg_info->
toposchema_id,
511 box->
W, box->
S, box->
B, box->
E, box->
N, box->
T);
535 sprintf(stmt,
"SELECT COUNT(*) FROM information_schema.tables " 536 "WHERE table_schema = '%s' AND table_name = '%s'",
537 TOPO_SCHEMA, TOPO_TABLE);
538 result = PQexec(pg_info->
conn, stmt);
539 if (!result || PQresultStatus(result) != PGRES_TUPLES_OK) {
544 if (atoi(PQgetvalue(result, 0, 0)) == 1) {
551 G_debug(1,
"<%s.%s> created", TOPO_SCHEMA, TOPO_TABLE);
554 sprintf(stmt,
"CREATE TABLE \"%s\".\"%s\" (%s INTEGER, %s box3d)",
555 TOPO_SCHEMA, TOPO_TABLE, TOPO_ID, TOPO_BBOX);
560 sprintf(stmt,
"ALTER TABLE \"%s\".\"%s\" ADD PRIMARY KEY (%s)",
561 TOPO_SCHEMA, TOPO_TABLE, TOPO_ID);
567 sprintf(stmt,
"ALTER TABLE \"%s\".\"%s\" ADD CONSTRAINT \"%s_%s_fkey\" " 568 "FOREIGN KEY (%s) REFERENCES topology.topology(id) ON DELETE CASCADE",
569 TOPO_SCHEMA, TOPO_TABLE, TOPO_TABLE, TOPO_ID, TOPO_ID);
593 sprintf(stmt,
"SELECT COUNT(*) FROM \"%s\".\"%s\" " 596 result = PQexec(pg_info->
conn, stmt);
597 if (!result || PQresultStatus(result) != PGRES_TUPLES_OK) {
603 if (atoi(PQgetvalue(result, 0, 0)) == 1) {
628 int write_nodes(
const struct Plus_head *plus,
632 size_t stmt_lines_size, stmt_angles_size, stmt_size;
633 char *stmt_lines, *stmt_angles, *stmt;
635 const struct P_node *Node;
638 offset = &(pg_info->
offset);
644 G_warning(
_(
"Unable to write nodes, offset array mismatch"));
649 stmt = (
char *)
G_malloc(stmt_size);
651 stmt_lines = stmt_angles =
NULL;
652 for (i = 1; i <= plus->
n_nodes; i++) {
653 Node = plus->
Node[i];
657 node_id = offset->
array[i-1];
660 build_stmt_id(Node->
lines, Node->
n_lines,
TRUE, plus, &stmt_lines, &stmt_lines_size);
665 if (stmt_lines_size + stmt_angles_size + 512 > stmt_size) {
666 stmt_size = stmt_lines_size + stmt_angles_size + 512;
667 stmt = (
char *)
G_realloc(stmt, stmt_size);
669 sprintf(stmt,
"INSERT INTO \"%s\".%s VALUES (" 671 node_id, stmt_lines, stmt_angles);
700 int write_lines(
const struct Plus_head *plus,
706 const struct P_line *Line;
711 sprintf(stmt,
"SELECT edge_id FROM \"%s\".edge_data WHERE " 712 "left_face != 0 OR right_face != 0 ORDER BY edge_id",
715 res = PQexec(pg_info->
conn, stmt);
716 if (!res || PQresultStatus(res) != PGRES_TUPLES_OK ||
717 (PQntuples(res) > 0 && PQntuples(res) != plus->
n_blines)) {
718 G_warning(
_(
"Inconsistency in topology: number of " 719 "boundaries %d (should be %d)"),
726 for (row = 0, i = 1; i <= plus->
n_lines; i++) {
727 Line = plus->
Line[i];
732 offset = atoi(PQgetvalue(res, row++, 0));
734 offset = (int)Line->
offset;
737 sprintf(stmt,
"INSERT INTO \"%s\".%s VALUES (" 763 int write_areas(
const struct Plus_head *plus,
767 size_t stmt_lines_size, stmt_isles_size, stmt_size;
768 char *stmt_lines, *stmt_isles, *stmt;
770 const struct P_line *Line;
771 const struct P_area *Area;
774 stmt = (
char *)
G_malloc(stmt_size);
776 stmt_lines = stmt_isles =
NULL;
777 for (area = 1; area <= plus->
n_areas; area++) {
778 Area = plus->
Area[area];
780 G_debug(3,
"Area %d skipped (dead)", area);
792 G_warning(
_(
"Topology for centroid %d not available. Area %d skipped"),
796 centroid = (int) Line->
offset;
803 if (stmt_lines_size + stmt_isles_size + 512 > stmt_size) {
804 stmt_size = stmt_lines_size + stmt_isles_size + 512;
805 stmt = (
char *)
G_realloc(stmt, stmt_size);
807 sprintf(stmt,
"INSERT INTO \"%s\".%s VALUES (" 809 area, stmt_lines, centroid, stmt_isles);
835 int write_isles(
const struct Plus_head *plus,
839 size_t stmt_lines_size, stmt_size;
840 char *stmt_lines, *stmt;
842 const struct P_isle *Isle;
845 stmt = (
char *)
G_malloc(stmt_size);
848 for (isle = 1; isle <= plus->
n_isles; isle++) {
849 Isle = plus->
Isle[isle];
857 if (stmt_lines_size + 512 > stmt_size) {
858 stmt_size = stmt_lines_size + 512;
859 stmt = (
char *)
G_realloc(stmt, stmt_size);
861 sprintf(stmt,
"INSERT INTO \"%s\".%s VALUES (" 863 isle, stmt_lines, Isle->
area);
885 void build_stmt_id(
const void *array,
int nitems,
int is_int,
const struct Plus_head *plus,
886 char **stmt,
size_t *stmt_size)
893 char *stmt_id, buf_id[128];
898 iarray = (
int *) array;
900 farray = (
float *) array;
904 stmt_id = (
char *)
G_malloc(stmt_id_size);
907 stmt_id_size = *stmt_size;
914 for (i = 0; i < nitems; i++) {
916 if (strlen(stmt_id) + 100 > stmt_id_size) {
918 stmt_id = (
char *)
G_realloc(stmt_id, stmt_id_size);
923 Line = plus->
Line[abs(iarray[i])];
924 ivalue = (int) Line->
offset;
931 sprintf(buf_id,
"%d", ivalue);
934 sprintf(buf_id,
"%f", farray[i]);
938 strcat(stmt_id,
",");
939 strcat(stmt_id, buf_id);
943 *stmt_size = stmt_id_size;
958 sprintf(stmt,
"DELETE FROM \"%s\".\"%s\"",
963 sprintf(stmt,
"DELETE FROM \"%s\".\"%s\"",
969 sprintf(stmt,
"DELETE FROM \"%s\".\"%s\"",
975 sprintf(stmt,
"DELETE FROM \"%s\".\"%s\"",
992 int create_simple_feature_from_topo(
struct Map_info *Map)
1002 G_message(
_(
"Create simple features topology from topogeometry data..."));
1006 sprintf(stmt,
"UPDATE \"%s\".\"%s\" SET %s = (SELECT geom FROM \"%s\".node " 1020 G_warning(
_(
"Unable to build simple features from topogeometry data. "
int Spidx_new
Build new spatial index.
plus_t n_areas
Current number of areas.
const char * G_find_file2(const char *, const char *, const char *)
Searches for a file from the mapset search list or in a specified mapset. (look but don't touch) ...
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
int built
Highest level of topology currently available.
off_t offset
Offset in coor file for line.
int Vect_build_nat(struct Map_info *, int)
Build topology.
int Vect__clean_grass_db_topo(struct Format_info_pg *pg_info)
Clean-up GRASS Topology tables.
struct P_line ** Line
Array of vector geometries.
int Vect_get_area_centroid(const struct Map_info *, int)
Returns centroid id for given area.
plus_t right
Area number to the right, negative for isle.
#define GV_BUILD_BASE
Topology levels - basic level (without areas and isles)
struct P_area ** Area
Array of areas.
struct P_node ** Node
Array of nodes.
struct Key_Value * G_fread_key_value(FILE *)
Read key/values pairs from file.
void Vect__free_cache(struct Format_info_cache *cache)
plus_t n_lines
Number of attached lines (size of lines, angle)
void G_free(void *)
Free allocated memory.
plus_t left
Area number to the left, negative for isle.
struct Format_info fInfo
Format info for non-native formats.
struct P_isle ** Isle
Array of isles.
plus_t * lines
List of connected lines.
plus_t * isles
1st generation interior islands
plus_t n_isles
Current number of isles.
plus_t centroid
Number of first centroid within area.
plus_t n_lines
Number of boundary lines.
void dig_free_plus(struct Plus_head *)
Free Plus structure.
#define GV_POINT
Feature types used in memory on run time (may change)
#define GV_BUILD_NONE
Topology levels - nothing to build.
#define GV_MODE_RW
Read-write vector map open mode.
plus_t n_lines
Current number of lines.
int Vect_build_pg(struct Map_info *Map, int build)
Build topology for PostGIS layer.
void G_message(const char *,...) __attribute__((format(printf
plus_t * lines
List of boundary lines.
void Vect__free_offset(struct Format_info_offset *offset)
int int G_strcasecmp(const char *, const char *)
String compare ignoring case (upper or lower)
Basic topology-related info.
#define GV_BUILD_AREAS
Topology levels - build areas.
void * topo
Topology info.
float * angles
List of angles of connected lines.
int Vect__load_map_nodes_pg(struct Map_info *Map, int geom_only)
Read nodes from DB.
plus_t * lines
List of boundary lines.
struct Plus_head plus
Plus info (topology, version, ...)
plus_t Vect_get_num_areas(const struct Map_info *)
Get number of areas in vector map.
FILE * G_fopen_old(const char *, const char *, const char *)
Open a database file for reading.
Topological feature - node.
int Vect__build_sfa(struct Map_info *, int)
Build pseudo-topology (for simple features) - internal use only.
struct bound_box box
Bounding box of features.
plus_t n_isles
Number of islands inside.
#define GV_BUILD_ATTACH_ISLES
Topology levels - attach islands to areas.
void G_percent(long, long, int)
Print percent complete messages.
int Vect__execute_pg(PGconn *conn, const char *stmt)
Execute SQL statement.
int Vect__insert_face_pg(struct Map_info *Map, int area)
Insert new face to the 'face' table (topo only)
const char * G_mapset(void)
Get current mapset name.
void G_zero(void *, int)
Zero out a buffer, buf, of length i.
#define LEVEL_2
Vector level - with 2D topology.
void G_warning(const char *,...) __attribute__((format(printf
const char * Vect_get_finfo_geometry_type(const struct Map_info *)
Get geometry type as string (relevant only for non-native formats)
int Vect_build_partial(struct Map_info *, int)
Build partial topology for vector map.
plus_t Vect_get_num_islands(const struct Map_info *)
Get number of islands in vector map.
const char * Vect_get_finfo_format_info(const struct Map_info *)
Get format info as string (relevant only for non-native formats)
#define GV_BUILD_CENTROIDS
Topology levels - assign centroids to areas.
int Vect__define_topo_relation(const struct Format_info_pg *pg_info, int topo_id, int element_id)
plus_t n_blines
Current number of boundaries.
int update_cidx
Update category index if vector is modified.
plus_t n_lines
Number of boundary lines.
int Vect_read_line(const struct Map_info *, struct line_pnts *, struct line_cats *, int)
Read vector feature (topological level required)
plus_t area
Area it exists w/in, if any.
int G_debug(int, const char *,...) __attribute__((format(printf
int Vect__copy_areas(const struct Map_info *In, int field, struct Map_info *Out)
Copy areas as polygons (OGR/PostGIS simple features access only)
int dig_init_plus(struct Plus_head *)
Initialize Plus_head structure.
void G_free_key_value(struct Key_Value *)
Free allocated Key_Value structure.
const char * G_find_key_value(const char *, const struct Key_Value *)
Find given key (case sensitive)
plus_t n_nodes
Current number of topological features derived from vector geometries.
void Vect__build_downgrade(struct Map_info *, int)
Downgrade build level (for internal use only)