area_pg.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. /*!
  2. \file lib/vector/Vlib/area_pg.c
  3. \brief Vector library - area-related functions (PostGIS Topology)
  4. Higher level functions for reading/writing/manipulating vectors.
  5. (C) 2013 by the GRASS Development Team
  6. This program is free software under the GNU General Public License
  7. (>=v2). Read the file COPYING that comes with GRASS for details.
  8. \author Martin Landa <landa.martin gmail.com>
  9. */
  10. #include <grass/vector.h>
  11. #ifdef HAVE_POSTGRES
  12. #include "pg_local_proto.h"
  13. static PGresult *build_stmt(const struct Plus_head *, const struct Format_info_pg *, const plus_t *, int);
  14. /*!
  15. \brief Get area boundary points (PostGIS Topology)
  16. Used by Vect_build_line_area() and Vect_get_area_points().
  17. \param Map pointer to Map_info struct
  18. \param lines array of boundary lines
  19. \param n_lines number of lines in array
  20. \param[out] APoints pointer to output line_pnts struct
  21. \return number of points
  22. \return -1 on error
  23. */
  24. int Vect__get_area_points_pg(const struct Map_info *Map, const plus_t *lines, int n_lines,
  25. struct line_pnts *APoints)
  26. {
  27. int i, direction;
  28. struct Format_info_pg *pg_info;
  29. PGresult *res;
  30. pg_info = (struct Format_info_pg *)&(Map->fInfo.pg);
  31. Vect_reset_line(APoints);
  32. res = build_stmt(&(Map->plus), pg_info, lines, n_lines);
  33. if (!res)
  34. return -1;
  35. for (i = 0; i < n_lines; i++) {
  36. Vect__cache_feature_pg(PQgetvalue(res, i, 0), FALSE, FALSE,
  37. &(pg_info->cache), NULL); /* do caching in readable way */
  38. direction = lines[i] > 0 ? GV_FORWARD : GV_BACKWARD;
  39. Vect_append_points(APoints, pg_info->cache.lines[0], direction);
  40. APoints->n_points--; /* skip last point, avoids duplicates */
  41. }
  42. APoints->n_points++; /* close polygon */
  43. PQclear(res);
  44. return APoints->n_points;
  45. }
  46. PGresult *build_stmt(const struct Plus_head *plus, const struct Format_info_pg *pg_info,
  47. const plus_t *lines, int n_lines)
  48. {
  49. int i, line;
  50. size_t stmt_id_size;
  51. char *stmt, *stmt_id, buf_id[128];
  52. struct P_line *BLine;
  53. PGresult *res;
  54. stmt = NULL;
  55. stmt_id_size = DB_SQL_MAX;
  56. stmt_id = (char *) G_malloc(stmt_id_size);
  57. stmt_id[0] = '\0';
  58. for (i = 0; i < n_lines; i++) {
  59. if (strlen(stmt_id) + 100 > stmt_id_size) {
  60. stmt_id_size = strlen(stmt_id) + DB_SQL_MAX;
  61. stmt_id = (char *) G_realloc(stmt_id, stmt_id_size);
  62. }
  63. line = abs(lines[i]);
  64. BLine = plus->Line[line];
  65. if (i > 0)
  66. strcat(stmt_id, ",");
  67. sprintf(buf_id, "%d", (int) BLine->offset);
  68. strcat(stmt_id, buf_id);
  69. }
  70. /* Not really working - why?
  71. G_asprintf(&stmt, "SELECT geom FROM \"%s\".edge_data WHERE edge_id IN (%s) "
  72. "ORDER BY POSITION(edge_id::text in '%s')", pg_info->toposchema_name,
  73. stmt_id, stmt_id);
  74. */
  75. G_asprintf(&stmt, "SELECT geom FROM \"%s\".edge_data AS t "
  76. "JOIN (SELECT id, row_number() over() AS id_sorter FROM "
  77. "(SELECT UNNEST(ARRAY[%s]) AS id) AS y) x ON "
  78. "t.edge_id in (%s) AND x.id = t.edge_id "
  79. "ORDER BY x.id_sorter", pg_info->toposchema_name, stmt_id, stmt_id);
  80. G_free(stmt_id);
  81. G_debug(2, "SQL: %s", stmt);
  82. res = PQexec(pg_info->conn, stmt);
  83. G_free(stmt);
  84. if (!res || PQresultStatus(res) != PGRES_TUPLES_OK ||
  85. PQntuples(res) != n_lines) {
  86. if (res)
  87. PQclear(res);
  88. return NULL;
  89. }
  90. return res;
  91. }
  92. #endif