write.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831
  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-2010 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, V2_write_line_ogr}
  58. , {
  59. write_dummy, V1_write_line_ogr, V2_write_line_ogr}
  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, V1_rewrite_line_nat, V2_rewrite_line_nat}
  70. #ifdef HAVE_OGR
  71. , {
  72. rewrite_dummy, V1_rewrite_line_ogr, V2_rewrite_line_ogr}
  73. , {
  74. rewrite_dummy, V1_rewrite_line_ogr, V2_rewrite_line_ogr}
  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 Add line to topo file
  341. Update areas. Areas are modified if:
  342. 1) first or/and last point are existing nodes ->
  343. - drop areas/islands whose boundaries are neighbour to this boundary at these nodes
  344. - try build areas and islands for this boundary and neighbour boundaries going through these nodes
  345. Question: may be by adding line created new area/isle which doesn't go through nodes of this line
  346. <pre>
  347. old new line
  348. +----+----+ +----+----+ +----+----+
  349. | A1 | A2 | + / -> | A1 | /| or + \ -> | A1 | A2 | \
  350. | | | | | | | | |
  351. +----+----+ +----+----+ +----+----+
  352. I1 I1 I1 I1
  353. </pre>
  354. - reattache all centroids/isles inside new area(s)
  355. - attach new isle to area outside
  356. 2) line is closed ring (node at the end is new, so it is not case above)
  357. - build new area/isle
  358. - check if it is island or contains island(s)
  359. - re-attach all centroids/isles inside new area(s)
  360. - attach new isle to area outside
  361. Note that 1) and 2) is done by the same code.
  362. */
  363. void Vect__add_line_to_topo(struct Map_info *Map, int line,
  364. const struct line_pnts *points, const struct line_cats *cats)
  365. {
  366. int first, s, n, i;
  367. int type, node, next_line, area, side, sel_area, new_area[2];
  368. struct Plus_head *plus;
  369. struct P_line *Line, *NLine;
  370. struct P_node *Node;
  371. struct P_area *Area;
  372. struct bound_box box, abox;
  373. plus = &(Map->plus);
  374. Line = plus->Line[line];
  375. type = Line->type;
  376. if (plus->built >= GV_BUILD_AREAS) {
  377. if (type == GV_BOUNDARY) {
  378. /* Delete neighbour areas/isles */
  379. first = 1;
  380. for (s = 1; s < 3; s++) { /* for each node */
  381. if (s == 1)
  382. node = Line->N1; /* Node 1 */
  383. else
  384. node = Line->N2;
  385. G_debug(3,
  386. " delete neighbour areas/iseles: side = %d node = %d",
  387. s, node);
  388. Node = plus->Node[node];
  389. n = 0;
  390. for (i = 0; i < Node->n_lines; i++) {
  391. NLine = plus->Line[abs(Node->lines[i])];
  392. if (NLine->type == GV_BOUNDARY)
  393. n++;
  394. }
  395. G_debug(3, " number of boundaries at node = %d", n);
  396. if (n > 2) { /* more than 2 boundaries at node ( >= 2 old + 1 new ) */
  397. /* Line above (to the right), it is enough to check to the right, because if area/isle
  398. * exists it is the same to the left */
  399. if (s == 1)
  400. next_line =
  401. dig_angle_next_line(plus, line, GV_RIGHT,
  402. GV_BOUNDARY);
  403. else
  404. next_line =
  405. dig_angle_next_line(plus, -line, GV_RIGHT,
  406. GV_BOUNDARY);
  407. if (next_line != 0) { /* there is a boundary to the right */
  408. NLine = plus->Line[abs(next_line)];
  409. if (next_line > 0) /* the boundary is connected by 1. node */
  410. area = NLine->right; /* we are interested just in this side (close to our line) */
  411. else if (next_line < 0) /* the boundary is connected by 2. node */
  412. area = NLine->left;
  413. G_debug(3, " next_line = %d area = %d", next_line,
  414. area);
  415. if (area > 0) { /* is area */
  416. Vect_get_area_box(Map, area, &box);
  417. if (first) {
  418. Vect_box_copy(&abox, &box);
  419. first = 0;
  420. }
  421. else
  422. Vect_box_extend(&abox, &box);
  423. if (plus->update_cidx) {
  424. Vect__delete_area_cats_from_cidx(Map, area);
  425. }
  426. dig_del_area(plus, area);
  427. }
  428. else if (area < 0) { /* is isle */
  429. dig_del_isle(plus, -area);
  430. }
  431. }
  432. }
  433. }
  434. /* Build new areas/isles. Thas true that we deleted also adjacent areas/isles, but if
  435. * they form new one our boundary must participate, so we need to build areas/isles
  436. * just for our boundary */
  437. for (s = 1; s < 3; s++) {
  438. if (s == 1)
  439. side = GV_LEFT;
  440. else
  441. side = GV_RIGHT;
  442. G_debug(3, " build area/isle on side = %d", side);
  443. G_debug(3, "Build area for line = %d, side = %d", line, side);
  444. area = Vect_build_line_area(Map, line, side);
  445. G_debug(3, "Build area for line = %d, side = %d", line, side);
  446. if (area > 0) { /* area */
  447. Vect_get_area_box(Map, area, &box);
  448. if (first) {
  449. Vect_box_copy(&abox, &box);
  450. first = 0;
  451. }
  452. else
  453. Vect_box_extend(&abox, &box);
  454. }
  455. else if (area < 0) {
  456. /* isle -> must be attached -> add to abox */
  457. Vect_get_isle_box(Map, -area, &box);
  458. if (first) {
  459. Vect_box_copy(&abox, &box);
  460. first = 0;
  461. }
  462. else
  463. Vect_box_extend(&abox, &box);
  464. }
  465. new_area[s - 1] = area;
  466. }
  467. /* Reattach all centroids/isles in deleted areas + new area.
  468. * Because isles are selected by box it covers also possible new isle created above */
  469. if (!first) { /* i.e. old area/isle was deleted or new one created */
  470. /* Reattache isles */
  471. if (plus->built >= GV_BUILD_ATTACH_ISLES)
  472. Vect_attach_isles(Map, &abox);
  473. /* Reattach centroids */
  474. if (plus->built >= GV_BUILD_CENTROIDS)
  475. Vect_attach_centroids(Map, &abox);
  476. }
  477. /* Add to category index */
  478. if (plus->update_cidx) {
  479. for (s = 1; s < 3; s++) {
  480. if (new_area[s - 1] > 0) {
  481. Vect__add_area_cats_to_cidx(Map, new_area[s - 1]);
  482. }
  483. }
  484. }
  485. }
  486. }
  487. /* Attach centroid */
  488. if (plus->built >= GV_BUILD_CENTROIDS) {
  489. if (type == GV_CENTROID) {
  490. sel_area = Vect_find_area(Map, points->x[0], points->y[0]);
  491. G_debug(3, " new centroid %d is in area %d", line, sel_area);
  492. if (sel_area > 0) {
  493. Area = plus->Area[sel_area];
  494. Line = plus->Line[line];
  495. if (Area->centroid == 0) { /* first centroid */
  496. G_debug(3, " first centroid -> attach to area");
  497. Area->centroid = line;
  498. Line->left = sel_area;
  499. if (plus->update_cidx) {
  500. Vect__add_area_cats_to_cidx(Map, sel_area);
  501. }
  502. }
  503. else { /* duplicate centroid */
  504. G_debug(3,
  505. " duplicate centroid -> do not attach to area");
  506. Line->left = -sel_area;
  507. }
  508. }
  509. }
  510. }
  511. /* Add cetegory index */
  512. for (i = 0; i < cats->n_cats; i++) {
  513. dig_cidx_add_cat_sorted(plus, cats->field[i], cats->cat[i], line,
  514. type);
  515. }
  516. return;
  517. }
  518. /*!
  519. \brief Writes feature to 'coor' file (topology level) - internal use only
  520. \param Map pointer to Map_info structure
  521. \param type feature type
  522. \param points feature geometry
  523. \param cats feature categories
  524. \return new feature id
  525. \return -1 on error
  526. */
  527. off_t V2__write_line(struct Map_info *Map,
  528. int type, const struct line_pnts *points, const struct line_cats *cats,
  529. off_t (*write_fn) (struct Map_info *, int, const struct line_pnts *,
  530. const struct line_cats *))
  531. {
  532. int line;
  533. off_t offset;
  534. struct Plus_head *plus;
  535. struct bound_box box;
  536. line = 0;
  537. G_debug(3, "V2__write_line()");
  538. offset = write_fn(Map, type, points, cats);
  539. if (offset < 0)
  540. return -1;
  541. /* Update topology */
  542. plus = &(Map->plus);
  543. /* Add line */
  544. if (plus->built >= GV_BUILD_BASE) {
  545. line = dig_add_line(plus, type, points, offset);
  546. G_debug(3, " line added to topo with id = %d", line);
  547. dig_line_box(points, &box);
  548. dig_line_set_box(plus, line, &box);
  549. if (line == 1)
  550. Vect_box_copy(&(plus->box), &box);
  551. else
  552. Vect_box_extend(&(plus->box), &box);
  553. }
  554. Vect__add_line_to_topo(Map,
  555. line, points, cats);
  556. G_debug(3, "updated lines : %d , updated nodes : %d", plus->n_uplines,
  557. plus->n_upnodes);
  558. /* returns int line, but is defined as off_t for compatibility with
  559. * Write_line_array in write.c */
  560. return line;
  561. }
  562. /*!
  563. \brief Writes new feature to the end of file
  564. The function calls G_fatal_error() on error.
  565. \param Map pointer to vector map
  566. \param type feature type
  567. \param points feature geometry
  568. \param cats feature categories
  569. \return new feature id (level 2)
  570. \return offset into file where the feature starts (level 1)
  571. */
  572. off_t
  573. Vect_write_line(struct Map_info *Map,
  574. int type, const struct line_pnts *points, const struct line_cats *cats)
  575. {
  576. off_t offset;
  577. G_debug(3, "Vect_write_line(): name = %s, format = %d, level = %d",
  578. Map->name, Map->format, Map->level);
  579. if (!VECT_OPEN(Map))
  580. G_fatal_error(_("Unable to write feature, vector map is not opened"));
  581. dig_line_reset_updated(&(Map->plus));
  582. dig_node_reset_updated(&(Map->plus));
  583. if (!(Map->plus.update_cidx)) {
  584. Map->plus.cidx_up_to_date = 0;
  585. }
  586. offset =
  587. (*Write_line_array[Map->format][Map->level]) (Map, type, points,
  588. cats);
  589. if (offset == -1)
  590. G_fatal_error(_("Unable to write feature (negative offset)"));
  591. /* NOTE: returns new line id on level 2 and file offset on level 1 */
  592. return offset;
  593. }
  594. /*!
  595. \brief Rewrites feature info at the given offset.
  596. The number of points or cats or type may change. If necessary, the
  597. old feature is deleted and new is written.
  598. This function calls G_fatal_error() on error.
  599. \param Map pointer to vector map
  600. \param line feature id
  601. \param type feature type
  602. \param points feature geometry
  603. \param cats feature categories
  604. \return new feature id
  605. \return -1 on error
  606. */
  607. int
  608. Vect_rewrite_line(struct Map_info *Map,
  609. int line,
  610. int type, const struct line_pnts *points, const struct line_cats *cats)
  611. {
  612. long ret;
  613. G_debug(3, "Vect_rewrite_line(): name = %s, line = %d", Map->name, line);
  614. if (!VECT_OPEN(Map))
  615. G_fatal_error(_("Unable to rewrite feature, vector map is not opened"));
  616. dig_line_reset_updated(&(Map->plus));
  617. dig_node_reset_updated(&(Map->plus));
  618. if (!(Map->plus.update_cidx)) {
  619. Map->plus.cidx_up_to_date = 0;
  620. }
  621. ret =
  622. (*Vect_rewrite_line_array[Map->format][Map->level]) (Map, line, type,
  623. points, cats);
  624. if (ret == -1)
  625. G_fatal_error(_("Unable to rewrite feature %d"), line);
  626. return ret;
  627. }
  628. /*!
  629. \brief Delete feature
  630. Vector map must be opened on topo level 2.
  631. This function calls G_fatal_error() on error.
  632. \param Map pointer to vector map
  633. \param line feature id
  634. \return 0 on success
  635. \return -1 on error
  636. */
  637. int Vect_delete_line(struct Map_info *Map, int line)
  638. {
  639. int ret;
  640. G_debug(3, "Vect_delete_line(): name = %s, line = %d", Map->name, line);
  641. if (Map->level < 2) {
  642. G_fatal_error(_("Unable to delete feature %d, "
  643. "vector map <%s> is not opened on topology level"),
  644. line, Map->name);
  645. }
  646. if (Map->mode != GV_MODE_RW && Map->mode != GV_MODE_WRITE) {
  647. G_fatal_error(_("Unable to delete feature %d, "
  648. "vector map <%s> is not opened in 'write' mode"),
  649. line, Map->name);
  650. }
  651. dig_line_reset_updated(&(Map->plus));
  652. dig_node_reset_updated(&(Map->plus));
  653. if (!(Map->plus.update_cidx)) {
  654. Map->plus.cidx_up_to_date = 0;
  655. }
  656. ret = (*Vect_delete_line_array[Map->format][Map->level]) (Map, line);
  657. if (ret == -1)
  658. G_fatal_error(_("Unable to delete feature id %d from vector map <%s>"),
  659. line, Vect_get_full_name(Map));
  660. return ret;
  661. }
  662. /*!
  663. \brief Restore previously deleted feature
  664. Vector map must be opened on topo level 2.
  665. This function calls G_fatal_error() on error.
  666. \param Map pointer to vector map
  667. \param line feature id to be deleted
  668. \return 0 on success
  669. \return -1 on error
  670. */
  671. int Vect_restore_line(struct Map_info *Map, int line, off_t offset)
  672. {
  673. int ret;
  674. G_debug(3, "Vect_restore_line(): name = %s, line = %d", Map->name, line);
  675. if (Map->level < 2) {
  676. G_fatal_error(_("Unable to restore feature %d, "
  677. "vector map <%s> is not opened on topology level"),
  678. line, Map->name);
  679. }
  680. if (Map->mode != GV_MODE_RW && Map->mode != GV_MODE_WRITE) {
  681. G_fatal_error(_("Unable to restore feature %d, "
  682. "vector map <%s> is not opened in 'write' mode"),
  683. line, Map->name);
  684. }
  685. dig_line_reset_updated(&(Map->plus));
  686. dig_node_reset_updated(&(Map->plus));
  687. if (!(Map->plus.update_cidx)) {
  688. Map->plus.cidx_up_to_date = 0;
  689. }
  690. ret = (*Vect_restore_line_array[Map->format][Map->level]) (Map, line, offset);
  691. if (ret == -1)
  692. G_fatal_error(_("Unable to restore feature %d from vector map <%s>"),
  693. line, Map->name);
  694. return ret;
  695. }