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,
39 static void build_stmt_id(
const void *,
int,
int,
const struct Plus_head *,
41 static int create_simple_feature_from_topo(
struct Map_info *);
44 #define NOPG_UNUSED UNUSED
70 pg_info = &(Map->fInfo.pg);
72 G_debug(1,
"Vect_build_pg(): db='%s' table='%s', build=%d",
84 if (build == plus->
built)
101 G_warning(
_(
"Feature table <%s> has no primary key defined"),
103 G_warning(
_(
"Random read is not supported for this layer. "
104 "Unable to build topology."));
109 G_message(
_(
"Using external data format '%s' (feature type '%s')"),
113 G_message(
_(
"Building pseudo-topology over simple features..."));
116 _(
"Building topology from PostGIS topology schema <%s>..."),
124 return build_topo(Map, build);
126 G_fatal_error(
_(
"GRASS is not compiled with PostgreSQL support"));
143 int build_topo(
struct Map_info *Map,
int build)
145 int line, type, s, n_nodes = 0;
146 int area, nareas, isle, nisles;
163 if (build < plus->built) {
220 _(
"Inconsistency in topology: number of nodes %d (should be %d)"),
224 save_map_bbox(pg_info, &(plus->
box));
234 write_nodes(plus, pg_info);
235 write_lines(plus, pg_info);
245 G_message(
_(
"Cleaning-up topology schema..."));
248 "UPDATE \"%s\".node SET containing_face = 0 WHERE "
249 "containing_face IS NOT NULL",
259 "UPDATE \"%s\".edge_data SET left_face = 0, right_face = 0",
269 "DELETE FROM \"%s\".face WHERE "
312 G_debug(3,
"Area %d without centroid, skipped",
area);
318 "UPDATE \"%s\".node SET "
319 "containing_face = %d WHERE node_id = %d",
331 for (line = 1; line <= plus->
n_lines; line++) {
339 G_warning(
_(
"Inconsistency in topology detected. "
340 "Dead line found."));
346 for (s = 0; s < 2; s++) {
347 face[s] = s == 0 ? topo_b->
left : topo_b->
right;
350 Isle = plus->
Isle[abs(face[s])];
351 face[s] = Isle->
area;
354 G_debug(3,
"update edge %d: left_face = %d, right_face = %d",
355 (
int)Line->
offset, face[0], face[1]);
358 "UPDATE \"%s\".edge_data SET "
359 "left_face = %d, right_face = %d "
360 "WHERE edge_id = %d",
372 write_areas(plus, pg_info);
379 for (isle = 1; isle <= nisles; isle++) {
380 Isle = plus->
Isle[isle];
386 write_isles(plus, pg_info);
395 G_message(
_(
"Updating TopoGeometry data..."));
396 for (area = 1; area <= plus->
n_areas; area++) {
402 Line = plus->
Line[centroid];
407 if (build_topogeom_stmt(pg_info,
GV_CENTROID, area,
408 (
int)Line->
offset, stmt) &&
423 def_file = getenv(
"GRASS_VECTOR_PGFILE");
444 if (create_simple_feature_from_topo(Map) != 0)
467 int build_topogeom_stmt(
const struct Format_info_pg *pg_info,
int type,
468 int topo_id,
int fid,
char *stmt)
484 G_warning(
_(
"Unsupported topo geometry type %d"), type);
489 "UPDATE \"%s\".\"%s\" SET %s = "
490 "'(%d, 1, %d, %d)'::topology.TopoGeometry "
491 "WHERE (%s).id = %d",
514 if (create_topo_grass(pg_info) == -1) {
515 G_warning(
_(
"Unable to create <%s.%s>"), TOPO_SCHEMA, TOPO_TABLE);
520 if (has_topo_grass(pg_info)) {
523 "UPDATE \"%s\".\"%s\" SET %s = "
524 "'BOX3D(%.12f %.12f %.12f, %.12f %.12f %.12f)'::box3d WHERE %s "
526 TOPO_SCHEMA, TOPO_TABLE, TOPO_BBOX, box->
W, box->
S, box->
B,
533 "INSERT INTO \"%s\".\"%s\" (%s, %s) "
534 "VALUES(%d, 'BOX3D(%.12f %.12f %.12f, %.12f %.12f %.12f)'::box3d)",
535 TOPO_SCHEMA, TOPO_TABLE, TOPO_ID, TOPO_BBOX, pg_info->
toposchema_id,
536 box->
W, box->
S, box->
B, box->
E, box->
N, box->
T);
561 "SELECT COUNT(*) FROM information_schema.tables "
562 "WHERE table_schema = '%s' AND table_name = '%s'",
563 TOPO_SCHEMA, TOPO_TABLE);
564 result = PQexec(pg_info->
conn, stmt);
565 if (!result || PQresultStatus(result) != PGRES_TUPLES_OK) {
570 if (atoi(PQgetvalue(result, 0, 0)) == 1) {
577 G_debug(1,
"<%s.%s> created", TOPO_SCHEMA, TOPO_TABLE);
580 sprintf(stmt,
"CREATE TABLE \"%s\".\"%s\" (%s INTEGER, %s box3d)",
581 TOPO_SCHEMA, TOPO_TABLE, TOPO_ID, TOPO_BBOX);
586 sprintf(stmt,
"ALTER TABLE \"%s\".\"%s\" ADD PRIMARY KEY (%s)", TOPO_SCHEMA,
587 TOPO_TABLE, TOPO_ID);
595 "ALTER TABLE \"%s\".\"%s\" ADD CONSTRAINT \"%s_%s_fkey\" "
596 "FOREIGN KEY (%s) REFERENCES topology.topology(id) ON DELETE CASCADE",
597 TOPO_SCHEMA, TOPO_TABLE, TOPO_TABLE, TOPO_ID, TOPO_ID);
622 "SELECT COUNT(*) FROM \"%s\".\"%s\" "
625 result = PQexec(pg_info->
conn, stmt);
626 if (!result || PQresultStatus(result) != PGRES_TUPLES_OK) {
632 if (atoi(PQgetvalue(result, 0, 0)) == 1) {
657 int write_nodes(
const struct Plus_head *plus,
661 size_t stmt_lines_size, stmt_angles_size, stmt_size;
662 char *stmt_lines, *stmt_angles, *stmt;
664 const struct P_node *Node;
667 offset = &(pg_info->
offset);
673 G_warning(
_(
"Unable to write nodes, offset array mismatch"));
680 stmt_lines = stmt_angles =
NULL;
681 for (i = 1; i <= plus->
n_nodes; i++) {
682 Node = plus->
Node[i];
686 node_id = offset->
array[i - 1];
696 if (stmt_lines_size + stmt_angles_size + 512 > stmt_size) {
697 stmt_size = stmt_lines_size + stmt_angles_size + 512;
698 stmt = (
char *)
G_realloc(stmt, stmt_size);
701 "INSERT INTO \"%s\".%s VALUES ("
702 "%d, '{%s}', '{%s}')",
733 int write_lines(
const struct Plus_head *plus,
739 const struct P_line *Line;
745 "SELECT edge_id FROM \"%s\".edge_data WHERE "
746 "left_face != 0 OR right_face != 0 ORDER BY edge_id",
749 res = PQexec(pg_info->
conn, stmt);
750 if (!res || PQresultStatus(res) != PGRES_TUPLES_OK ||
751 (PQntuples(res) > 0 && PQntuples(res) != plus->
n_blines)) {
752 G_warning(
_(
"Inconsistency in topology: number of "
753 "boundaries %d (should be %d)"),
760 for (row = 0, i = 1; i <= plus->
n_lines; i++) {
761 Line = plus->
Line[i];
766 offset = atoi(PQgetvalue(res, row++, 0));
768 offset = (int)Line->
offset;
772 "INSERT INTO \"%s\".%s VALUES ("
799 int write_areas(
const struct Plus_head *plus,
803 size_t stmt_lines_size, stmt_isles_size, stmt_size;
804 char *stmt_lines, *stmt_isles, *stmt;
806 const struct P_line *Line;
807 const struct P_area *Area;
812 stmt_lines = stmt_isles =
NULL;
813 for (area = 1; area <= plus->
n_areas; area++) {
814 Area = plus->
Area[area];
816 G_debug(3,
"Area %d skipped (dead)", area);
830 G_warning(
_(
"Topology for centroid %d not available. Area %d "
842 if (stmt_lines_size + stmt_isles_size + 512 > stmt_size) {
843 stmt_size = stmt_lines_size + stmt_isles_size + 512;
844 stmt = (
char *)
G_realloc(stmt, stmt_size);
847 "INSERT INTO \"%s\".%s VALUES ("
848 "%d, '{%s}', %d, '{%s}')",
876 int write_isles(
const struct Plus_head *plus,
880 size_t stmt_lines_size, stmt_size;
881 char *stmt_lines, *stmt;
883 const struct P_isle *Isle;
889 for (isle = 1; isle <= plus->
n_isles; isle++) {
890 Isle = plus->
Isle[isle];
899 if (stmt_lines_size + 512 > stmt_size) {
900 stmt_size = stmt_lines_size + 512;
901 stmt = (
char *)
G_realloc(stmt, stmt_size);
904 "INSERT INTO \"%s\".%s VALUES ("
929 void build_stmt_id(
const void *array,
int nitems,
int is_int,
930 const struct Plus_head *plus,
char **stmt,
size_t *stmt_size)
937 char *stmt_id, buf_id[128];
942 iarray = (
int *)array;
944 farray = (
float *)array;
948 stmt_id = (
char *)
G_malloc(stmt_id_size);
951 stmt_id_size = *stmt_size;
958 for (i = 0; i < nitems; i++) {
960 if (strlen(stmt_id) + 100 > stmt_id_size) {
962 stmt_id = (
char *)
G_realloc(stmt_id, stmt_id_size);
967 Line = plus->
Line[abs(iarray[i])];
968 ivalue = (int)Line->
offset;
975 sprintf(buf_id,
"%d", ivalue);
978 sprintf(buf_id,
"%f", farray[i]);
982 strcat(stmt_id,
",");
983 strcat(stmt_id, buf_id);
987 *stmt_size = stmt_id_size;
1033 int create_simple_feature_from_topo(
struct Map_info *Map)
1043 G_message(
_(
"Create simple features topology from topogeometry data..."));
1048 "UPDATE \"%s\".\"%s\" SET %s = (SELECT geom FROM \"%s\".node "
1049 "WHERE node_id = (%s).id)",
1062 G_warning(
_(
"Unable to build simple features from topogeometry data. "
1063 "Unsupported type %d."),
int Vect__clean_grass_db_topo(struct Format_info_pg *pg_info)
Clean-up GRASS Topology tables.
int Vect_build_pg(struct Map_info *Map NOPG_UNUSED, int build NOPG_UNUSED)
Build topology for PostGIS layer.
void G_percent(long, long, int)
Print percent complete messages.
FILE * G_fopen_old(const char *, const char *, const char *)
Open a database file for reading.
void G_zero(void *, int)
Zero out a buffer, buf, of length i.
void G_free(void *)
Free allocated memory.
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
void G_warning(const char *,...) __attribute__((format(printf
const char * G_find_key_value(const char *, const struct Key_Value *)
Find given key (case sensitive)
void G_free_key_value(struct Key_Value *)
Free allocated Key_Value structure.
const char * G_mapset(void)
Get current mapset name.
struct Key_Value * G_fread_key_value(FILE *)
Read key/values pairs from file.
int int G_strcasecmp(const char *, const char *)
String compare ignoring case (upper or lower)
void G_message(const char *,...) __attribute__((format(printf
int G_debug(int, const char *,...) __attribute__((format(printf
plus_t Vect_get_num_islands(struct Map_info *)
Get number of islands in vector map.
plus_t Vect_get_num_areas(struct Map_info *)
Get number of areas in vector map.
void Vect__build_downgrade(struct Map_info *, int)
Downgrade build level (for internal use only)
int Vect_build_nat(struct Map_info *, int)
Build topology.
int Vect__build_sfa(struct Map_info *, int)
Build pseudo-topology (for simple features) - internal use only.
int Vect_read_line(struct Map_info *, struct line_pnts *, struct line_cats *, int)
Read vector feature (topological level required)
const char * Vect_get_finfo_format_info(struct Map_info *)
Get format info as string (relevant only for non-native formats)
int Vect_build_partial(struct Map_info *, int)
Build partial topology for vector map.
const char * Vect_get_finfo_geometry_type(struct Map_info *)
Get geometry type as string (relevant only for non-native formats)
int Vect_get_area_centroid(struct Map_info *, int)
Returns centroid id for given area.
#define GV_BUILD_NONE
Topology levels - nothing to build.
#define GV_POINT
Feature types used in memory on run time (may change)
#define GV_BUILD_ATTACH_ISLES
Topology levels - attach islands to areas.
#define GV_BUILD_BASE
Topology levels - basic level (without areas and isles)
#define GV_BUILD_AREAS
Topology levels - build areas.
#define GV_BUILD_CENTROIDS
Topology levels - assign centroids to areas.
#define LEVEL_2
Vector level - with 2D topology.
#define GV_MODE_RW
Read-write vector map open mode.
void dig_free_plus(struct Plus_head *)
Free Plus structure.
int dig_init_plus(struct Plus_head *)
Initialize Plus_head structure.
int Vect__load_map_nodes_pg(struct Map_info *Map, int geom_only)
Read nodes from DB.
int Vect__execute_pg(PGconn *conn, const char *stmt)
Execute SQL statement.
struct Format_info fInfo
Format info for non-native formats.
struct Plus_head plus
Plus info (topology, version, ...)
plus_t n_isles
Number of islands inside.
plus_t * isles
1st generation interior islands
plus_t n_lines
Number of boundary lines.
plus_t * lines
List of boundary lines.
plus_t centroid
Number of first centroid within area.
plus_t * lines
List of boundary lines.
plus_t n_lines
Number of boundary lines.
plus_t area
Area it exists w/in, if any.
off_t offset
Offset in coor file for line.
void * topo
Topology info.
Topological feature - node.
plus_t n_lines
Number of attached lines (size of lines, angle)
float * angles
List of angles of connected lines.
plus_t * lines
List of connected lines.
plus_t left
Area number to the left, negative for isle.
plus_t right
Area number to the right, negative for isle.
Basic topology-related info.
struct P_line ** Line
Array of vector geometries.
plus_t n_lines
Current number of lines.
int Spidx_new
Build new spatial index.
plus_t n_nodes
Current number of topological features derived from vector geometries.
plus_t n_blines
Current number of boundaries.
struct P_area ** Area
Array of areas.
int update_cidx
Update category index if vector is modified.
plus_t n_isles
Current number of isles.
struct bound_box box
Bounding box of features.
struct P_isle ** Isle
Array of isles.
struct P_node ** Node
Array of nodes.
plus_t n_areas
Current number of areas.
int built
Highest level of topology currently available.
void Vect__free_offset(struct Format_info_offset *offset)
void Vect__free_cache(struct Format_info_cache *cache)
int Vect__copy_areas(struct Map_info *In, int field, struct Map_info *Out)
Copy areas as polygons (OGR/PostGIS simple features access only)
int Vect__define_topo_relation(const struct Format_info_pg *pg_info, int topo_id, int element_id)
int Vect__insert_face_pg(struct Map_info *Map, int area)
Insert new face to the 'face' table (topo only)