plus_line.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. /**
  2. * \file plus_line.c
  3. *
  4. * \brief Vector library - update topo for lines (lower level functions)
  5. *
  6. * Lower level functions for reading/writing/manipulating vectors.
  7. *
  8. * This program is free software under the GNU General Public License
  9. * (>=v2). Read the file COPYING that comes with GRASS for details.
  10. *
  11. * \author CERL (probably Dave Gerdes), Radim Blazek
  12. *
  13. * \date 2001-2008
  14. */
  15. #include <sys/types.h>
  16. #include <stdlib.h>
  17. #include <grass/vector.h>
  18. #include <grass/glocale.h>
  19. static int add_line(struct Plus_head *plus, int lineid, int type, const struct line_pnts *Points,
  20. const struct bound_box *box, off_t offset)
  21. {
  22. int node, lp, node_new;
  23. struct P_line *line;
  24. plus->Line[lineid] = dig_alloc_line();
  25. line = plus->Line[lineid];
  26. line->type = type;
  27. line->offset = offset;
  28. dig_spidx_add_line(plus, lineid, box);
  29. if (plus->uplist.do_uplist) {
  30. dig_line_add_updated(plus, lineid, offset);
  31. }
  32. if (type & GV_POINT) {
  33. line->topo = NULL;
  34. return (lineid);
  35. }
  36. line->topo = dig_alloc_topo(type);
  37. if (type & GV_CENTROID) {
  38. struct P_topo_c *topo = (struct P_topo_c *)line->topo;
  39. topo->area = 0;
  40. return (lineid);
  41. }
  42. /* Add nodes for lines */
  43. G_debug(3, "Register node: type = %d, %f,%f", type, Points->x[0],
  44. Points->y[0]);
  45. /* Start node */
  46. node = dig_find_node(plus, Points->x[0], Points->y[0], Points->z[0]);
  47. G_debug(3, "node = %d", node);
  48. if (node == 0) {
  49. node = dig_add_node(plus, Points->x[0], Points->y[0], Points->z[0]);
  50. G_debug(3, "Add new node: %d", node);
  51. node_new = TRUE;
  52. }
  53. else {
  54. G_debug(3, "Old node found: %d", node);
  55. node_new = FALSE;
  56. }
  57. if (type == GV_LINE) {
  58. struct P_topo_l *topo = (struct P_topo_l *)line->topo;
  59. topo->N1 = node;
  60. topo->N2 = 0;
  61. }
  62. else if (type == GV_BOUNDARY) {
  63. struct P_topo_b *topo = (struct P_topo_b *)line->topo;
  64. topo->N1 = node;
  65. topo->N2 = 0;
  66. topo->left = 0;
  67. topo->right = 0;
  68. }
  69. dig_node_add_line(plus, node, lineid, Points, type);
  70. if (plus->uplist.do_uplist)
  71. dig_node_add_updated(plus, node_new ? -node : node);
  72. /* End node */
  73. lp = Points->n_points - 1;
  74. G_debug(3, "Register node %f,%f", Points->x[lp], Points->y[lp]);
  75. node = dig_find_node(plus, Points->x[lp], Points->y[lp],
  76. Points->z[lp]);
  77. G_debug(3, "node = %d", node);
  78. if (node == 0) {
  79. node = dig_add_node(plus, Points->x[lp], Points->y[lp],
  80. Points->z[lp]);
  81. G_debug(3, "Add new node: %d", node);
  82. node_new = TRUE;
  83. }
  84. else {
  85. G_debug(3, "Old node found: %d", node);
  86. node_new = FALSE;
  87. }
  88. if (type == GV_LINE) {
  89. struct P_topo_l *topo = (struct P_topo_l *)line->topo;
  90. topo->N2 = node;
  91. }
  92. else if (type == GV_BOUNDARY) {
  93. struct P_topo_b *topo = (struct P_topo_b *)line->topo;
  94. topo->N2 = node;
  95. }
  96. dig_node_add_line(plus, node, -lineid, Points, type);
  97. if (plus->uplist.do_uplist)
  98. dig_node_add_updated(plus, node_new ? -node : node);
  99. return (lineid);
  100. }
  101. /*!
  102. * \brief Add new line to Plus_head structure.
  103. *
  104. * \param[in,out] plus pointer to Plus_head structure
  105. * \param type feature type
  106. * \param Points line geometry
  107. * \param box bounding box
  108. * \param offset line offset
  109. *
  110. * \return -1 on error
  111. * \return line id
  112. */
  113. int
  114. dig_add_line(struct Plus_head *plus, int type, const struct line_pnts *Points,
  115. const struct bound_box *box, off_t offset)
  116. {
  117. int ret;
  118. /* First look if we have space in array of pointers to lines
  119. * and reallocate if necessary */
  120. if (plus->n_lines >= plus->alloc_lines) { /* array is full */
  121. if (dig_alloc_lines(plus, 1000) == -1)
  122. return -1;
  123. }
  124. ret = add_line(plus, plus->n_lines + 1, type, Points, box, offset);
  125. if (ret == -1)
  126. return ret;
  127. plus->n_lines++;
  128. switch (type) {
  129. case GV_POINT:
  130. plus->n_plines++;
  131. break;
  132. case GV_LINE:
  133. plus->n_llines++;
  134. break;
  135. case GV_BOUNDARY:
  136. plus->n_blines++;
  137. break;
  138. case GV_CENTROID:
  139. plus->n_clines++;
  140. break;
  141. case GV_FACE:
  142. plus->n_flines++;
  143. break;
  144. case GV_KERNEL:
  145. plus->n_klines++;
  146. break;
  147. }
  148. return ret;
  149. }
  150. /*!
  151. * \brief Restore line in Plus_head structure.
  152. *
  153. * \param[in,out] plus pointer to Plus_head structure
  154. * \param type feature type
  155. * \param Points line geometry
  156. * \param box bounding box
  157. * \param offset line offset
  158. *
  159. * \return -1 on error
  160. * \return line id
  161. */
  162. int
  163. dig_restore_line(struct Plus_head *plus, int lineid,
  164. int type, const struct line_pnts *Points,
  165. const struct bound_box *box, off_t offset)
  166. {
  167. if (lineid < 1 || lineid > plus->n_lines) {
  168. return -1;
  169. }
  170. return add_line(plus, lineid, type, Points, box, offset);
  171. }
  172. /*!
  173. * \brief Delete line from Plus_head structure.
  174. *
  175. * Doesn't update area/isle references (dig_del_area() or dig_del_isle()) must be
  176. * run before the line is deleted if the line is part of such
  177. * structure). Update is info about line in nodes. If this line is
  178. * last in node then node is deleted.
  179. *
  180. * \param[in,out] plus pointer to Plus_head structure
  181. * \param[in] line line id
  182. * \param[in] x,y,z coordinates
  183. *
  184. * \return -1 on error
  185. * \return 0 OK
  186. *
  187. */
  188. int dig_del_line(struct Plus_head *plus, int line, double x, double y, double z)
  189. {
  190. int i;
  191. plus_t N1 = 0, N2 = 0;
  192. struct P_line *Line;
  193. struct P_node *Node;
  194. G_debug(3, "dig_del_line() line = %d", line);
  195. Line = plus->Line[line];
  196. dig_spidx_del_line(plus, line, x, y, z);
  197. if (plus->uplist.do_uplist) {
  198. dig_line_add_updated(plus, line, -Line->offset);
  199. }
  200. if (!(Line->type & GV_LINES)) {
  201. /* Delete line */
  202. dig_free_line(Line);
  203. plus->Line[line] = NULL;
  204. return 0;
  205. }
  206. /* Delete from nodes (and nodes) */
  207. if (Line->type == GV_LINE) {
  208. struct P_topo_l *topo = (struct P_topo_l *)Line->topo;
  209. N1 = topo->N1;
  210. }
  211. else if (Line->type == GV_BOUNDARY) {
  212. struct P_topo_b *topo = (struct P_topo_b *)Line->topo;
  213. N1 = topo->N1;
  214. }
  215. Node = plus->Node[N1];
  216. i = 0;
  217. while (i < Node->n_lines && Node->lines[i] != line)
  218. i++;
  219. if (i == Node->n_lines) {
  220. G_fatal_error(_("Attempt to delete not registered line %d from node %d"),
  221. line, N1);
  222. }
  223. i++;
  224. while (i < Node->n_lines) {
  225. Node->lines[i - 1] = Node->lines[i];
  226. Node->angles[i - 1] = Node->angles[i];
  227. i++;
  228. }
  229. Node->n_lines--;
  230. if (plus->uplist.do_uplist) {
  231. dig_node_add_updated(plus, Node->n_lines > 0 ? N1 : -N1);
  232. }
  233. if (Node->n_lines == 0) {
  234. G_debug(3, " node %d has 0 lines -> delete", N1);
  235. dig_spidx_del_node(plus, N1);
  236. /* free structures */
  237. dig_free_node(Node);
  238. plus->Node[N1] = NULL;
  239. }
  240. if (Line->type == GV_LINE) {
  241. struct P_topo_l *topo = (struct P_topo_l *)Line->topo;
  242. N2 = topo->N2;
  243. }
  244. else if (Line->type == GV_BOUNDARY) {
  245. struct P_topo_b *topo = (struct P_topo_b *)Line->topo;
  246. N2 = topo->N2;
  247. }
  248. Node = plus->Node[N2];
  249. i = 0;
  250. while (i < Node->n_lines && Node->lines[i] != -line)
  251. i++;
  252. if (i == Node->n_lines) {
  253. G_fatal_error(_("Attempt to delete not registered line %d from node %d"),
  254. -line, N2);
  255. }
  256. i++;
  257. while (i < Node->n_lines) {
  258. Node->lines[i - 1] = Node->lines[i];
  259. Node->angles[i - 1] = Node->angles[i];
  260. i++;
  261. }
  262. Node->n_lines--;
  263. if (plus->uplist.do_uplist) {
  264. dig_node_add_updated(plus, Node->n_lines > 0 ? N2 : -N2);
  265. }
  266. if (Node->n_lines == 0) {
  267. G_debug(3, " node %d has 0 lines -> delete", N2);
  268. dig_spidx_del_node(plus, N2);
  269. /* free structures */
  270. dig_free_node(Node);
  271. plus->Node[N2] = NULL;
  272. }
  273. /* Delete line */
  274. dig_free_line(Line);
  275. plus->Line[line] = NULL;
  276. return 0;
  277. }
  278. /*!
  279. * \brief Get area number on line side.
  280. *
  281. * \param[in] plus pointer Plus_head structure
  282. * \param[in] line line id
  283. * \param[in] side side id (GV_LEFT || GV_RIGHT)
  284. *
  285. * \return area number
  286. * \return 0 no area
  287. * \return -1 on error
  288. */
  289. plus_t dig_line_get_area(struct Plus_head * plus, plus_t line, int side)
  290. {
  291. struct P_line *Line;
  292. struct P_topo_b *topo;
  293. Line = plus->Line[line];
  294. if (!Line) /* dead */
  295. return -1;
  296. if (Line->type != GV_BOUNDARY)
  297. return -1;
  298. topo = (struct P_topo_b *)Line->topo;
  299. if (side == GV_LEFT) {
  300. G_debug(3,
  301. "dig_line_get_area(): line = %d, side = %d (left), area = %d",
  302. line, side, topo->left);
  303. return (topo->left);
  304. }
  305. if (side == GV_RIGHT) {
  306. G_debug(3,
  307. "dig_line_get_area(): line = %d, side = %d (right), area = %d",
  308. line, side, topo->right);
  309. return (topo->right);
  310. }
  311. return (-1);
  312. }
  313. /*!
  314. * \brief Set area number on line side
  315. *
  316. * \param[in] plus pointer Plus_head structure
  317. * \param[in] line line id
  318. * \param[in] side side id (GV_LEFT || GV_RIGHT)
  319. * \param[in] area area id
  320. *
  321. * \return 1
  322. */
  323. int
  324. dig_line_set_area(struct Plus_head *plus, plus_t line, int side, plus_t area)
  325. {
  326. struct P_line *Line;
  327. struct P_topo_b *topo;
  328. Line = plus->Line[line];
  329. if (Line->type != GV_BOUNDARY)
  330. return (0);
  331. topo = (struct P_topo_b *)Line->topo;
  332. if (side == GV_LEFT) {
  333. topo->left = area;
  334. }
  335. else if (side == GV_RIGHT) {
  336. topo->right = area;
  337. }
  338. return (1);
  339. }
  340. /*!
  341. * \brief Set line bounding box
  342. *
  343. * \param[in] plus pointer Plus_head structure
  344. * \param[in] line line id
  345. * \param[in] Box bounding box
  346. *
  347. * \return 1
  348. */
  349. /*
  350. int dig_line_set_box(struct Plus_head *plus, plus_t line, struct bound_box * Box)
  351. {
  352. struct P_line *Line;
  353. Line = plus->Line[line];
  354. Line->N = Box->N;
  355. Line->S = Box->S;
  356. Line->E = Box->E;
  357. Line->W = Box->W;
  358. Line->T = Box->T;
  359. Line->B = Box->B;
  360. return (1);
  361. }
  362. */
  363. /*!
  364. * \brief Get line bounding box saved in topo
  365. *
  366. * \param[in] plus pointer Plus_head structure
  367. * \param[in] line line id
  368. * \param[in,out] Box bounding box
  369. *
  370. * \return 1
  371. */
  372. /*
  373. int dig_line_get_box(struct Plus_head *plus, plus_t line, struct bound_box * Box)
  374. {
  375. struct P_line *Line;
  376. Line = plus->Line[line];
  377. Box->N = Line->N;
  378. Box->S = Line->S;
  379. Box->E = Line->E;
  380. Box->W = Line->W;
  381. Box->T = Line->T;
  382. Box->B = Line->B;
  383. return (1);
  384. }
  385. */