write_sfa.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. /*!
  2. \file lib/vector/Vlib/write_sfa.c
  3. \brief Vector library - write vector feature - simple feature access (level 2)
  4. Higher level functions for reading/writing/manipulating vectors.
  5. See write_ogr.c (OGR interface) and write_pg.c (PostGIS interface)
  6. for imlementation issues.
  7. \todo SFA version of V2__delete_area_cats_from_cidx_nat()
  8. \todo function to delete corresponding entry in fidx
  9. \todo SFA version of V2__add_area_cats_to_cidx_nat
  10. \todo SFA version of V2__add_line_to_topo_nat
  11. (C) 2011-2012 by Martin Landa, and the GRASS Development Team
  12. This program is free software under the GNU General Public License
  13. (>=v2). Read the file COPYING that comes with GRASS for details.
  14. \author Martin Landa <landa.martin gmail.com>
  15. */
  16. #include <grass/vector.h>
  17. #include <grass/glocale.h>
  18. #include "local_proto.h"
  19. #ifdef HAVE_POSTGRES
  20. #include "pg_local_proto.h"
  21. #endif
  22. #if defined HAVE_OGR || defined HAVE_POSTGRES
  23. static void V2__add_line_to_topo_sfa(struct Map_info *, int, const struct line_pnts *,
  24. const struct line_cats *);
  25. #endif
  26. /*!
  27. \brief Writes feature on level 2 (OGR/PostGIS interface, pseudo-topological level)
  28. \param Map pointer to Map_info structure
  29. \param type feature type (see V1_write_line_ogr() for list of supported types)
  30. \param points pointer to line_pnts structure (feature geometry)
  31. \param cats pointer to line_cats structure (feature categories)
  32. \return feature index in offset array (related to pseudo-topology)
  33. \return -1 on error
  34. */
  35. off_t V2_write_line_sfa(struct Map_info *Map, int type,
  36. const struct line_pnts *points, const struct line_cats *cats)
  37. {
  38. #if defined HAVE_OGR || defined HAVE_POSTGRES
  39. int line;
  40. off_t offset;
  41. struct Plus_head *plus;
  42. struct bound_box box;
  43. struct Format_info_offset *offset_info;
  44. line = 0;
  45. plus = &(Map->plus);
  46. G_debug(3, "V2_write_line_sfa(): type = %d (format = %d)",
  47. type, Map->format);
  48. if (Map->format == GV_FORMAT_POSTGIS) {
  49. offset_info = &(Map->fInfo.pg.offset);
  50. offset = V1_write_line_pg(Map, type, points, cats);
  51. }
  52. else {
  53. offset_info = &(Map->fInfo.pg.offset);
  54. offset = V1_write_line_ogr(Map, type, points, cats);
  55. }
  56. if (offset < 0)
  57. return -1;
  58. if (!(plus->update_cidx)) {
  59. plus->cidx_up_to_date = FALSE; /* category index will be outdated */
  60. }
  61. /* Update topology */
  62. if (plus->built >= GV_BUILD_BASE) {
  63. dig_line_box(points, &box);
  64. line = dig_add_line(plus, type, points, &box, offset);
  65. G_debug(3, "\tline added to topo with line = %d", line);
  66. if (line == 1)
  67. Vect_box_copy(&(plus->box), &box);
  68. else
  69. Vect_box_extend(&(plus->box), &box);
  70. if (type == GV_BOUNDARY) {
  71. int ret, cline;
  72. long fid;
  73. double x, y;
  74. struct bound_box box;
  75. struct line_pnts *CPoints;
  76. /* add virtual centroid to pseudo-topology */
  77. ret = Vect_get_point_in_poly(points, &x, &y);
  78. if (ret == 0) {
  79. CPoints = Vect_new_line_struct();
  80. Vect_append_point(CPoints, x, y, 0.0);
  81. fid = offset_info->array[offset];
  82. dig_line_box(CPoints, &box);
  83. cline = dig_add_line(plus, GV_CENTROID,
  84. CPoints, &box, fid);
  85. G_debug(4, "\tCentroid: x = %f, y = %f, cat = %lu, line = %d",
  86. x, y, fid, cline);
  87. dig_cidx_add_cat(plus, 1, (int) fid,
  88. cline, GV_CENTROID);
  89. Vect_destroy_line_struct(CPoints);
  90. }
  91. else {
  92. G_warning(_("Unable to calculate centroid for area"));
  93. }
  94. }
  95. V2__add_line_to_topo_sfa(Map, line, points, cats);
  96. }
  97. G_debug(3, "updated lines : %d , updated nodes : %d", plus->uplist.n_uplines,
  98. plus->uplist.n_upnodes);
  99. /* returns int line, but is defined as off_t for compatibility with
  100. * Write_line_array in write.c */
  101. return line;
  102. #else
  103. G_fatal_error(_("GRASS is not compiled with OGR/PostgreSQL support"));
  104. return -1;
  105. #endif
  106. }
  107. /*!
  108. \brief Rewrites feature at the given offset on level 2 (OGR/PostGIS
  109. interface, pseudo-topological level)
  110. Note: Topology must be built at level >= GV_BUILD_BASE
  111. \param Map pointer to Map_info structure
  112. \param line feature id to be rewritten
  113. \param type feature type (see V1_write_line_ogr() for supported types)
  114. \param points pointer to line_pnts structure (feature geometry)
  115. \param cats pointer to line_cats structure feature categories
  116. \return feature index in offset array (related to pseudo-topology)
  117. \return -1 on error
  118. */
  119. off_t V2_rewrite_line_sfa(struct Map_info *Map, off_t line, int type,
  120. const struct line_pnts *points, const struct line_cats *cats)
  121. {
  122. G_debug(3, "V2_rewrite_line_sfa(): line=%d type=%d",
  123. (int)line, type);
  124. if (line < 1 || line > Map->plus.n_lines) {
  125. G_warning(_("Attempt to access feature with invalid id (%d)"), (int)line);
  126. return -1;
  127. }
  128. #if defined HAVE_OGR || defined HAVE_POSTGRES
  129. if (type != V2_read_line_sfa(Map, NULL, NULL, line)) {
  130. G_warning(_("Unable to rewrite feature (incompatible feature types)"));
  131. return -1;
  132. }
  133. if (V2_delete_line_sfa(Map, line) != 0)
  134. return -1;
  135. return V2_write_line_sfa(Map, type, points, cats);
  136. #else
  137. G_fatal_error(_("GRASS is not compiled with OGR/PostgreSQL support"));
  138. return -1;
  139. #endif
  140. }
  141. /*!
  142. \brief Deletes feature on level 2 (OGR/PostGIS interface)
  143. Note: Topology must be built at level >= GV_BUILD_BASE
  144. \todo Update fidx
  145. \param pointer to Map_info structure
  146. \param line feature id to be deleted
  147. \return 0 on success
  148. \return -1 on error
  149. */
  150. int V2_delete_line_sfa(struct Map_info *Map, off_t line)
  151. {
  152. #if defined HAVE_OGR || defined HAVE_POSTGRES
  153. int ret, i, type, first;
  154. struct P_line *Line;
  155. struct Plus_head *plus;
  156. static struct line_cats *Cats = NULL;
  157. static struct line_pnts *Points = NULL;
  158. G_debug(3, "V2_delete_line_sfa(): line = %d", (int)line);
  159. type = first = 0;
  160. Line = NULL;
  161. plus = &(Map->plus);
  162. if (line < 1 || line > Map->plus.n_lines) {
  163. G_warning(_("Attempt to access feature with invalid id (%d)"), (int)line);
  164. return -1;
  165. }
  166. if (!(plus->update_cidx)) {
  167. plus->cidx_up_to_date = FALSE; /* category index will be outdated */
  168. }
  169. if (plus->built >= GV_BUILD_BASE) {
  170. Line = Map->plus.Line[line];
  171. if (Line == NULL)
  172. G_fatal_error(_("Attempt to delete dead feature"));
  173. type = Line->type;
  174. }
  175. if (!Cats) {
  176. Cats = Vect_new_cats_struct();
  177. }
  178. if (!Points) {
  179. Points = Vect_new_line_struct();
  180. }
  181. type = V2_read_line_sfa(Map, Points, Cats, line);
  182. if (type < 0)
  183. return -1;
  184. /* Update category index */
  185. if (plus->update_cidx) {
  186. for (i = 0; i < Cats->n_cats; i++) {
  187. dig_cidx_del_cat(plus, Cats->field[i], Cats->cat[i], line, type);
  188. }
  189. }
  190. /* Update fidx */
  191. /* TODO */
  192. /* delete the line from coor */
  193. if (Map->format == GV_FORMAT_POSTGIS)
  194. ret = V1_delete_line_pg(Map, Line->offset);
  195. else
  196. ret = V1_delete_line_ogr(Map, Line->offset);
  197. if (ret == -1) {
  198. return ret;
  199. }
  200. /* Update topology */
  201. if (plus->built >= GV_BUILD_AREAS && type == GV_BOUNDARY) {
  202. /* TODO */
  203. /* remove centroid together with boundary (is really an OGR polygon) */
  204. }
  205. /* Delete reference from area */
  206. if (plus->built >= GV_BUILD_CENTROIDS && type == GV_CENTROID) {
  207. /* for OGR mapsets, virtual centroid will be removed when
  208. * polygon is removed */
  209. }
  210. /* delete the line from topo */
  211. dig_del_line(plus, line, Points->x[0], Points->y[0], Points->z[0]);
  212. /* Rebuild areas/isles and attach centroids and isles */
  213. if (plus->built >= GV_BUILD_AREAS && type == GV_BOUNDARY) {
  214. /* maybe not needed VERIFY */
  215. }
  216. return ret;
  217. #else
  218. G_fatal_error(_("GRASS is not compiled with OGR/PostgreSQL support"));
  219. return -1;
  220. #endif
  221. }
  222. /*!
  223. \brief Writes area on topological level (Simple Features interface,
  224. internal use only)
  225. \param Map pointer to Map_info structure
  226. \param points feature geometry (exterior + interior rings)
  227. \param nparts number of parts including exterior ring
  228. \param cats feature categories
  229. \return feature offset
  230. \return -1 on error
  231. */
  232. off_t V2__write_area_sfa(struct Map_info *Map,
  233. const struct line_pnts **points, int nparts,
  234. const struct line_cats *cats)
  235. {
  236. if (Map->format == GV_FORMAT_OGR) {
  237. #ifdef HAVE_OGR
  238. return V2__write_area_ogr(Map, points, nparts, cats);
  239. #else
  240. G_fatal_error(_("GRASS is not compiled with OGR support"));
  241. return -1;
  242. #endif
  243. }
  244. else if (Map->format == GV_FORMAT_POSTGIS) {
  245. #ifdef HAVE_POSTGRES
  246. return V2__write_area_pg(Map, points, nparts, cats);
  247. #else
  248. G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
  249. return -1;
  250. #endif
  251. }
  252. else {
  253. G_warning(_("Unsupported vector map format (%d)"), Map->format);
  254. }
  255. return -1;
  256. }
  257. #if defined HAVE_OGR || defined HAVE_POSTGRES
  258. /*!
  259. \brief Add feature to topo file (internal use only)
  260. \param Map pointer to Map_info structure
  261. \param line feature id
  262. \param points pointer to line_pnts structure (feature geometry)
  263. \param cats pointer to line_cats structure (feature categories)
  264. */
  265. void V2__add_line_to_topo_sfa(struct Map_info *Map, int line,
  266. const struct line_pnts *points,
  267. const struct line_cats *cats)
  268. {
  269. int first, s, i;
  270. int type, area, side;
  271. struct Plus_head *plus;
  272. struct P_line *Line;
  273. struct bound_box box, abox;
  274. G_debug(3, "V2__add_line_to_topo_sfa(): line = %d npoints = %d", line,
  275. points->n_points);
  276. plus = &(Map->plus);
  277. Line = plus->Line[line];
  278. type = Line->type;
  279. if (plus->built >= GV_BUILD_AREAS &&
  280. type == GV_BOUNDARY) {
  281. struct P_topo_b *topo = (struct P_topo_b *)Line->topo;
  282. if (topo->N1 != topo->N2) {
  283. G_warning(_("Boundary is not closed. Skipping."));
  284. return;
  285. }
  286. /* Build new areas/isles */
  287. for (s = 0; s < 2; s++) {
  288. side = (s == 0 ? GV_LEFT : GV_RIGHT);
  289. area = Vect_build_line_area(Map, line, side);
  290. if (area > 0) { /* area */
  291. Vect_get_area_box(Map, area, &box);
  292. if (first) {
  293. Vect_box_copy(&abox, &box);
  294. first = FALSE;
  295. }
  296. else
  297. Vect_box_extend(&abox, &box);
  298. }
  299. else if (area < 0) {
  300. /* isle -> must be attached -> add to abox */
  301. Vect_get_isle_box(Map, -area, &box);
  302. if (first) {
  303. Vect_box_copy(&abox, &box);
  304. first = FALSE;
  305. }
  306. else
  307. Vect_box_extend(&abox, &box);
  308. }
  309. G_debug(4, "Vect_build_line_area(): -> area = %d", area);
  310. }
  311. /* Attach centroid/isle to the new area */
  312. if (plus->built >= GV_BUILD_ATTACH_ISLES)
  313. Vect_attach_isles(Map, &abox);
  314. if (plus->built >= GV_BUILD_CENTROIDS)
  315. Vect_attach_centroids(Map, &abox);
  316. }
  317. /* Add category index */
  318. for (i = 0; i < cats->n_cats; i++) {
  319. dig_cidx_add_cat_sorted(plus, cats->field[i], cats->cat[i], line,
  320. type);
  321. }
  322. return;
  323. }
  324. #endif /* HAVE_OGR || HAVE_POSTGRES */