write.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  1. /*!
  2. \file lib/vector/Vlib/write.c
  3. \brief Vector library - write vector features
  4. Higher level functions for reading/writing/manipulating vectors.
  5. (C) 2001-2009 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 Radim Blazek
  9. \author Updated by Martin Landa <landa.martin gmail.com> (restore lines, OGR support)
  10. */
  11. #include <grass/config.h>
  12. #include <sys/types.h>
  13. #include <grass/gis.h>
  14. #include <grass/glocale.h>
  15. #include <grass/vector.h>
  16. static off_t write_dummy()
  17. {
  18. G_warning("Vect_write_line() %s",
  19. _("for this format/level not supported"));
  20. return -1;
  21. }
  22. static int rewrite_dummy()
  23. {
  24. G_warning("Vect_rewrite_line() %s",
  25. _("for this format/level not supported"));
  26. return -1;
  27. }
  28. static int delete_dummy()
  29. {
  30. G_warning("Vect_delete_line() %s",
  31. _("for this format/level not supported"));
  32. return -1;
  33. }
  34. static int restore_dummy()
  35. {
  36. G_warning("Vect_restore_line() %s",
  37. _("for this format/level not supported"));
  38. return -1;
  39. }
  40. #ifndef HAVE_OGR
  41. static int format()
  42. {
  43. G_fatal_error(_("Requested format is not compiled in this version"));
  44. return 0;
  45. }
  46. static off_t format_l()
  47. {
  48. G_fatal_error(_("Requested format is not compiled in this version"));
  49. return 0;
  50. }
  51. #endif
  52. static off_t (*Write_line_array[][3]) () = {
  53. {
  54. write_dummy, V1_write_line_nat, V2_write_line_nat}
  55. #ifdef HAVE_OGR
  56. , {
  57. write_dummy, V1_write_line_ogr, write_dummy}
  58. , {
  59. write_dummy, V1_write_line_ogr, write_dummy}
  60. #else
  61. , {
  62. write_dummy, format_l, format_l}
  63. , {
  64. write_dummy, format_l, format_l}
  65. #endif
  66. };
  67. static int (*Vect_rewrite_line_array[][3]) () = {
  68. {
  69. rewrite_dummy, rewrite_dummy, V2_rewrite_line_nat}
  70. #ifdef HAVE_OGR
  71. , {
  72. rewrite_dummy, rewrite_dummy, rewrite_dummy}
  73. , {
  74. rewrite_dummy, rewrite_dummy, rewrite_dummy}
  75. #else
  76. , {
  77. rewrite_dummy, format, format}
  78. , {
  79. rewrite_dummy, format, format}
  80. #endif
  81. };
  82. static int (*Vect_delete_line_array[][3]) () = {
  83. {
  84. delete_dummy, V1_delete_line_nat, V2_delete_line_nat}
  85. #ifdef HAVE_OGR
  86. , {
  87. delete_dummy, V1_delete_line_ogr, V2_delete_line_ogr}
  88. , {
  89. delete_dummy, V1_delete_line_ogr, V2_delete_line_ogr}
  90. #else
  91. , {
  92. delete_dummy, format, format}
  93. , {
  94. delete_dummy, format, format}
  95. #endif
  96. };
  97. static int (*Vect_restore_line_array[][3]) () = {
  98. {
  99. restore_dummy, restore_dummy, V2_restore_line_nat}
  100. #ifdef HAVE_OGR
  101. , {
  102. restore_dummy, restore_dummy, restore_dummy}
  103. , {
  104. restore_dummy, restore_dummy, restore_dummy}
  105. #else
  106. , {
  107. restore_dummy, format, format}
  108. , {
  109. restore_dummy, format, format}
  110. #endif
  111. };
  112. /*!
  113. \brief Deletes area (i.e. centroid) categories from category
  114. index (internal use only)
  115. \param Map pointer to Map_info structure
  116. \param area area id
  117. */
  118. void Vect__delete_area_cats_from_cidx(struct Map_info *Map, int area)
  119. {
  120. int i;
  121. struct P_area *Area;
  122. static struct line_cats *Cats = NULL;
  123. G_debug(3, "Vect__delete_area_cats_from_cidx() area = %d", area);
  124. Area = Map->plus.Area[area];
  125. if (!Area)
  126. G_fatal_error(_("%s: Area %d does not exist"),
  127. "delete_area_cats_from_cidx()", area);
  128. if (Area->centroid == 0) /* no centroid found */
  129. return;
  130. if (!Cats)
  131. Cats = Vect_new_cats_struct();
  132. V2_read_line_nat(Map, NULL, Cats, Area->centroid);
  133. for (i = 0; i < Cats->n_cats; i++) {
  134. dig_cidx_del_cat(&(Map->plus), Cats->field[i], Cats->cat[i], area,
  135. GV_AREA);
  136. }
  137. }
  138. /*!
  139. \brief Adds area (i.e. centroid) categories from category index
  140. (internal use only)
  141. \param Map pointer to Map_info structure
  142. \param area area id
  143. */
  144. void Vect__add_area_cats_to_cidx(struct Map_info *Map, int area)
  145. {
  146. int i;
  147. struct P_area *Area;
  148. static struct line_cats *Cats = NULL;
  149. G_debug(3, "Vect__add_area_cats_to_cidx() area = %d", area);
  150. Area = Map->plus.Area[area];
  151. if (!Area)
  152. G_fatal_error(_("%s: Area %d does not exist"),
  153. "add_area_cats_to_cidx():", area);
  154. if (Area->centroid == 0) /* no centroid found */
  155. return;
  156. if (!Cats)
  157. Cats = Vect_new_cats_struct();
  158. V2_read_line_nat(Map, NULL, Cats, Area->centroid);
  159. for (i = 0; i < Cats->n_cats; i++) {
  160. dig_cidx_add_cat_sorted(&(Map->plus), Cats->field[i], Cats->cat[i],
  161. area, GV_AREA);
  162. }
  163. }
  164. /*!
  165. \brief Deletes feature (topology level) -- internal use only
  166. \param pointer to Map_info structure
  167. \param line feature id
  168. \param fn function to delete feature (native or ogr)
  169. \return 0 on success
  170. \return -1 on error
  171. */
  172. int V2__delete_line(struct Map_info *Map, int line, int (*fn_delete) (struct Map_info *, off_t))
  173. {
  174. int ret, i, side, type, first, next_line, area;
  175. struct P_line *Line;
  176. struct P_area *Area;
  177. struct Plus_head *plus;
  178. struct bound_box box, abox;
  179. int adjacent[4], n_adjacent;
  180. static struct line_cats *Cats = NULL;
  181. G_debug(3, "V2__delete_line(), line = %d", line);
  182. type = first = n_adjacent = 0;
  183. Line = NULL;
  184. plus = &(Map->plus);
  185. if (plus->built >= GV_BUILD_BASE) {
  186. Line = Map->plus.Line[line];
  187. if (Line == NULL)
  188. G_fatal_error(_("Attempt to delete dead feature"));
  189. type = Line->type;
  190. }
  191. if (!Cats) {
  192. Cats = Vect_new_cats_struct();
  193. }
  194. /* Update category index */
  195. if (plus->update_cidx) {
  196. type = V2_read_line_nat(Map, NULL, Cats, line);
  197. for (i = 0; i < Cats->n_cats; i++) {
  198. dig_cidx_del_cat(plus, Cats->field[i], Cats->cat[i], line, type);
  199. }
  200. }
  201. /* delete the line from coor */
  202. ret = fn_delete(Map, Line->offset);
  203. if (ret == -1) {
  204. return ret;
  205. }
  206. /* Update topology */
  207. if (plus->built >= GV_BUILD_AREAS && type == GV_BOUNDARY) {
  208. /* Store adjacent boundaries at nodes (will be used to rebuild area/isle) */
  209. /* Adjacent are stored: > 0 - we want right side; < 0 - we want left side */
  210. n_adjacent = 0;
  211. next_line = dig_angle_next_line(plus, line, GV_RIGHT, GV_BOUNDARY);
  212. if (next_line != 0 && abs(next_line) != line) {
  213. /* N1, to the right -> we want the right side for > 0 and left for < 0 */
  214. adjacent[n_adjacent] = next_line;
  215. n_adjacent++;
  216. }
  217. next_line = dig_angle_next_line(plus, line, GV_LEFT, GV_BOUNDARY);
  218. if (next_line != 0 && abs(next_line) != line) {
  219. /* N1, to the left -> we want the left side for > 0 and right for < 0 */
  220. adjacent[n_adjacent] = -next_line;
  221. n_adjacent++;
  222. }
  223. next_line = dig_angle_next_line(plus, -line, GV_RIGHT, GV_BOUNDARY);
  224. if (next_line != 0 && abs(next_line) != line) {
  225. /* N2, to the right -> we want the right side for > 0 and left for < 0 */
  226. adjacent[n_adjacent] = next_line;
  227. n_adjacent++;
  228. }
  229. next_line = dig_angle_next_line(plus, -line, GV_LEFT, GV_BOUNDARY);
  230. if (next_line != 0 && abs(next_line) != line) {
  231. /* N2, to the left -> we want the left side for > 0 and right for < 0 */
  232. adjacent[n_adjacent] = -next_line;
  233. n_adjacent++;
  234. }
  235. /* Delete area(s) and islands this line forms */
  236. first = 1;
  237. if (Line->left > 0) { /* delete area */
  238. Vect_get_area_box(Map, Line->left, &box);
  239. if (first) {
  240. Vect_box_copy(&abox, &box);
  241. first = 0;
  242. }
  243. else
  244. Vect_box_extend(&abox, &box);
  245. if (plus->update_cidx) {
  246. Vect__delete_area_cats_from_cidx(Map, Line->left);
  247. }
  248. dig_del_area(plus, Line->left);
  249. }
  250. else if (Line->left < 0) { /* delete isle */
  251. dig_del_isle(plus, -Line->left);
  252. }
  253. if (Line->right > 0) { /* delete area */
  254. Vect_get_area_box(Map, Line->right, &box);
  255. if (first) {
  256. Vect_box_copy(&abox, &box);
  257. first = 0;
  258. }
  259. else
  260. Vect_box_extend(&abox, &box);
  261. if (plus->update_cidx) {
  262. Vect__delete_area_cats_from_cidx(Map, Line->right);
  263. }
  264. dig_del_area(plus, Line->right);
  265. }
  266. else if (Line->right < 0) { /* delete isle */
  267. dig_del_isle(plus, -Line->right);
  268. }
  269. }
  270. /* Delete reference from area */
  271. if (plus->built >= GV_BUILD_CENTROIDS && type == GV_CENTROID) {
  272. if (Line->left > 0) {
  273. G_debug(3, "Remove centroid %d from area %d", line, Line->left);
  274. if (plus->update_cidx) {
  275. Vect__delete_area_cats_from_cidx(Map, Line->left);
  276. }
  277. Area = Map->plus.Area[Line->left];
  278. Area->centroid = 0;
  279. }
  280. }
  281. /* delete the line from topo */
  282. dig_del_line(plus, line);
  283. /* Rebuild areas/isles and attach centroids and isles */
  284. if (plus->built >= GV_BUILD_AREAS && type == GV_BOUNDARY) {
  285. int *new_areas, nnew_areas;
  286. nnew_areas = 0;
  287. new_areas = (int *)G_malloc(2 * n_adjacent * sizeof(int));
  288. /* Rebuild areas/isles */
  289. for (i = 0; i < n_adjacent; i++) {
  290. if (adjacent[i] > 0)
  291. side = GV_RIGHT;
  292. else
  293. side = GV_LEFT;
  294. G_debug(3, "Build area for line = %d, side = %d", adjacent[i],
  295. side);
  296. area = Vect_build_line_area(Map, abs(adjacent[i]), side);
  297. if (area > 0) { /* area */
  298. Vect_get_area_box(Map, area, &box);
  299. if (first) {
  300. Vect_box_copy(&abox, &box);
  301. first = 0;
  302. }
  303. else
  304. Vect_box_extend(&abox, &box);
  305. new_areas[nnew_areas] = area;
  306. nnew_areas++;
  307. }
  308. else if (area < 0) {
  309. /* isle -> must be attached -> add to abox */
  310. Vect_get_isle_box(Map, -area, &box);
  311. if (first) {
  312. Vect_box_copy(&abox, &box);
  313. first = 0;
  314. }
  315. else
  316. Vect_box_extend(&abox, &box);
  317. }
  318. }
  319. /* Reattach all centroids/isles in deleted areas + new area.
  320. * Because isles are selected by box it covers also possible new isle created above */
  321. if (!first) { /* i.e. old area/isle was deleted or new one created */
  322. /* Reattache isles */
  323. if (plus->built >= GV_BUILD_ATTACH_ISLES)
  324. Vect_attach_isles(Map, &abox);
  325. /* Reattach centroids */
  326. if (plus->built >= GV_BUILD_CENTROIDS)
  327. Vect_attach_centroids(Map, &abox);
  328. }
  329. if (plus->update_cidx) {
  330. for (i = 0; i < nnew_areas; i++) {
  331. Vect__add_area_cats_to_cidx(Map, new_areas[i]);
  332. }
  333. }
  334. }
  335. G_debug(3, "updated lines : %d , updated nodes : %d", plus->n_uplines,
  336. plus->n_upnodes);
  337. return ret;
  338. }
  339. /*!
  340. \brief Writes new feature to the end of file
  341. The function calls G_fatal_error() on error.
  342. \param Map pointer to vector map
  343. \param type feature type
  344. \param points feature geometry
  345. \param cats feature categories
  346. \return new feature id (level 2)
  347. \return offset into file where the feature starts (level 1)
  348. */
  349. off_t
  350. Vect_write_line(struct Map_info *Map,
  351. int type, const struct line_pnts *points, const struct line_cats *cats)
  352. {
  353. off_t offset;
  354. G_debug(3, "Vect_write_line(): name = %s, format = %d, level = %d",
  355. Map->name, Map->format, Map->level);
  356. if (!VECT_OPEN(Map))
  357. G_fatal_error(_("Unable to write feature, vector map is not opened"));
  358. dig_line_reset_updated(&(Map->plus));
  359. dig_node_reset_updated(&(Map->plus));
  360. if (!(Map->plus.update_cidx)) {
  361. Map->plus.cidx_up_to_date = 0;
  362. }
  363. offset =
  364. (*Write_line_array[Map->format][Map->level]) (Map, type, points,
  365. cats);
  366. if (offset == -1)
  367. G_fatal_error(_("Unable to write feature (negative offset)"));
  368. /* NOTE: returns new line id on level 2 and file offset on level 1 */
  369. return offset;
  370. }
  371. /*!
  372. \brief Rewrites feature info at the given offset.
  373. The number of points or cats or type may change. If necessary, the
  374. old feature is deleted and new is written.
  375. This function calls G_fatal_error() on error.
  376. \param Map pointer to vector map
  377. \param line feature id
  378. \param type feature type
  379. \param points feature geometry
  380. \param cats feature categories
  381. \return new feature id
  382. \return -1 on error
  383. */
  384. int
  385. Vect_rewrite_line(struct Map_info *Map,
  386. int line,
  387. int type, const struct line_pnts *points, const struct line_cats *cats)
  388. {
  389. long ret;
  390. G_debug(3, "Vect_rewrite_line(): name = %s, line = %d", Map->name, line);
  391. if (!VECT_OPEN(Map))
  392. G_fatal_error(_("Unable to rewrite feature, vector map is not opened"));
  393. dig_line_reset_updated(&(Map->plus));
  394. dig_node_reset_updated(&(Map->plus));
  395. if (!(Map->plus.update_cidx)) {
  396. Map->plus.cidx_up_to_date = 0;
  397. }
  398. ret =
  399. (*Vect_rewrite_line_array[Map->format][Map->level]) (Map, line, type,
  400. points, cats);
  401. if (ret == -1)
  402. G_fatal_error(_("Unable to rewrite feature %d"), line);
  403. return ret;
  404. }
  405. /*!
  406. \brief Delete feature
  407. Vector map must be opened on topo level 2.
  408. This function calls G_fatal_error() on error.
  409. \param Map pointer to vector map
  410. \param line feature id
  411. \return 0 on success
  412. \return -1 on error
  413. */
  414. int Vect_delete_line(struct Map_info *Map, int line)
  415. {
  416. int ret;
  417. G_debug(3, "Vect_delete_line(): name = %s, line = %d", Map->name, line);
  418. if (Map->level < 2) {
  419. G_fatal_error(_("Unable to delete feature %d, "
  420. "vector map <%s> is not opened on topology level"),
  421. line, Map->name);
  422. }
  423. if (Map->mode != GV_MODE_RW && Map->mode != GV_MODE_WRITE) {
  424. G_fatal_error(_("Unable to delete feature %d, "
  425. "vector map <%s> is not opened in 'write' mode"),
  426. line, Map->name);
  427. }
  428. dig_line_reset_updated(&(Map->plus));
  429. dig_node_reset_updated(&(Map->plus));
  430. if (!(Map->plus.update_cidx)) {
  431. Map->plus.cidx_up_to_date = 0;
  432. }
  433. ret = (*Vect_delete_line_array[Map->format][Map->level]) (Map, line);
  434. if (ret == -1)
  435. G_fatal_error(_("Unable to delete feature id %d from vector map <%s>"),
  436. line, Vect_get_full_name(Map));
  437. return ret;
  438. }
  439. /*!
  440. \brief Restore previously deleted feature
  441. Vector map must be opened on topo level 2.
  442. This function calls G_fatal_error() on error.
  443. \param Map pointer to vector map
  444. \param line feature id to be deleted
  445. \return 0 on success
  446. \return -1 on error
  447. */
  448. int Vect_restore_line(struct Map_info *Map, int line, off_t offset)
  449. {
  450. int ret;
  451. G_debug(3, "Vect_restore_line(): name = %s, line = %d", Map->name, line);
  452. if (Map->level < 2) {
  453. G_fatal_error(_("Unable to restore feature %d, "
  454. "vector map <%s> is not opened on topology level"),
  455. line, Map->name);
  456. }
  457. if (Map->mode != GV_MODE_RW && Map->mode != GV_MODE_WRITE) {
  458. G_fatal_error(_("Unable to restore feature %d, "
  459. "vector map <%s> is not opened in 'write' mode"),
  460. line, Map->name);
  461. }
  462. dig_line_reset_updated(&(Map->plus));
  463. dig_node_reset_updated(&(Map->plus));
  464. if (!(Map->plus.update_cidx)) {
  465. Map->plus.cidx_up_to_date = 0;
  466. }
  467. ret = (*Vect_restore_line_array[Map->format][Map->level]) (Map, line, offset);
  468. if (ret == -1)
  469. G_fatal_error(_("Unable to restore feature %d from vector map <%s>"),
  470. line, Map->name);
  471. return ret;
  472. }