break.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. /*!
  2. \file lib/vector/vedit/break.c
  3. \brief Vedit library - split, break, connect lines
  4. (C) 2007-2008 by the GRASS Development Team
  5. This program is free software under the GNU General Public License
  6. (>=v2). Read the file COPYING that comes with GRASS for details.
  7. \author Martin Landa <landa.martin gmail.com>
  8. */
  9. #include <math.h>
  10. #include <grass/vedit.h>
  11. static int connect_lines(struct Map_info *, int, int, int,
  12. double, struct ilist *);
  13. /*!
  14. \brief Split selected lines on given position
  15. \param Map pointer to Map_info
  16. \param List list of selected lines
  17. \param coord points location
  18. \param thresh threshold
  19. \param[out] List_updated list of rewritten features (or NULL)
  20. \return number of modified lines
  21. \return -1 on error
  22. */
  23. int Vedit_split_lines(struct Map_info *Map, struct ilist *List,
  24. struct line_pnts *coord, double thresh,
  25. struct ilist *List_updated)
  26. {
  27. int i, j, l;
  28. int type, line, seg, newline;
  29. int nlines_modified;
  30. double px, py, spdist, lpdist, dist;
  31. double *x, *y, *z;
  32. struct line_pnts *Points, *Points2;
  33. struct line_cats *Cats;
  34. struct ilist *List_in_box;
  35. nlines_modified = 0;
  36. Points = Vect_new_line_struct();
  37. Points2 = Vect_new_line_struct();
  38. Cats = Vect_new_cats_struct();
  39. List_in_box = Vect_new_list();
  40. for (i = 0; i < List->n_values; i++) {
  41. line = List->value[i];
  42. if (!Vect_line_alive(Map, line))
  43. continue;
  44. type = Vect_read_line(Map, Points, Cats, line);
  45. if (!(type & GV_LINES))
  46. continue;
  47. x = Points->x;
  48. y = Points->y;
  49. z = Points->z;
  50. for (j = 0; j < coord->n_points; j++) {
  51. seg =
  52. Vect_line_distance(Points, coord->x[j], coord->y[j],
  53. coord->z[j], WITHOUT_Z, &px, &py, NULL,
  54. &dist, &spdist, &lpdist);
  55. if (dist > thresh) {
  56. continue;
  57. }
  58. G_debug(3, "Vedit_split_lines(): line=%d, x=%f, y=%f, px=%f, py=%f, seg=%d, "
  59. "dist=%f, spdist=%f, lpdist=%f", line, coord->x[j],
  60. coord->y[j], px, py, seg, dist, spdist, lpdist);
  61. if (spdist <= 0.0 || spdist >= Vect_line_length(Points))
  62. continue;
  63. G_debug(3, "Vedit_split_lines(): line=%d", line);
  64. /* copy first line part */
  65. Vect_reset_line(Points2);
  66. for (l = 0; l < seg; l++) {
  67. Vect_append_point(Points2, x[l], y[l], z[l]);
  68. }
  69. /* add last vertex */
  70. Vect_append_point(Points2, px, py, 0.0);
  71. /* rewrite the line */
  72. if (j == 0)
  73. newline = Vect_rewrite_line(Map, line, type, Points2, Cats);
  74. else
  75. newline = Vect_write_line(Map, type, Points2, Cats);
  76. if (newline < 0) {
  77. return -1;
  78. }
  79. if (List_updated)
  80. Vect_list_append(List_updated, newline);
  81. Vect_reset_line(Points2);
  82. /* add given vertex */
  83. Vect_append_point(Points2, px, py, 0.0);
  84. /* copy second line part */
  85. for (l = seg; l < Points->n_points; l++) {
  86. Vect_append_point(Points2, x[l], y[l], z[l]);
  87. }
  88. /* rewrite the line */
  89. newline = Vect_write_line(Map, type, Points2, Cats);
  90. if (newline < 0) {
  91. return -1;
  92. }
  93. if (List_updated)
  94. Vect_list_append(List_updated, newline);
  95. nlines_modified++;
  96. } /* for each bounding box */
  97. } /* for each selected line */
  98. Vect_destroy_line_struct(Points);
  99. Vect_destroy_line_struct(Points2);
  100. Vect_destroy_cats_struct(Cats);
  101. Vect_destroy_list(List_in_box);
  102. return nlines_modified;
  103. }
  104. /*!
  105. \brief Connect lines in given threshold
  106. \code
  107. \ \
  108. id1 \ -> \
  109. \
  110. id2 --------- -----+---
  111. \endcode
  112. If two lines are selected and <i>thresh</i> is -1, no limit is
  113. applied.
  114. \param Map pointer to Map_info
  115. \param List list of selected lines
  116. \param thresh threshold value
  117. \return number of modified lines
  118. \return -1 on error
  119. */
  120. int Vedit_connect_lines(struct Map_info *Map, struct ilist *List,
  121. double thresh)
  122. {
  123. int nlines_modified, connected;
  124. int i, j, node[2], n_nodes;
  125. int line, found;
  126. double x, y, z;
  127. struct ilist *List_exclude, *List_found;
  128. nlines_modified = 0;
  129. List_exclude = Vect_new_list();
  130. List_found = Vect_new_list();
  131. n_nodes = 2;
  132. /* collect lines to be modified */
  133. for (i = 0; i < List->n_values; i++) {
  134. line = List->value[i];
  135. if (!Vect_line_alive(Map, line))
  136. continue;
  137. if (Vect_get_line_type(Map, line) & GV_POINTS)
  138. continue;
  139. node[0] = node[1] = -1;
  140. Vect_get_line_nodes(Map, line, &(node[0]), &(node[1]));
  141. if (node[0] < 0 || node[1] < 0)
  142. continue;
  143. connected = 0;
  144. Vect_reset_list(List_exclude);
  145. Vect_list_append(List_exclude, line);
  146. for (j = 0; j < n_nodes && !connected; j++) {
  147. /* for each line node find lines in threshold */
  148. Vect_get_node_coor(Map, node[j], &x, &y, &z);
  149. do {
  150. /* find first nearest line */
  151. found = Vect_find_line_list(Map, x, y, z,
  152. GV_LINES, thresh, WITHOUT_Z,
  153. List_exclude, List_found);
  154. if (found > 0 && Vect_line_alive(Map, found)) {
  155. /* try to connect lines (given node) */
  156. G_debug(3, "Vedit_connect_lines(): lines=%d,%d", line, found);
  157. if (connect_lines(Map, !j, line, found, thresh, List)) {
  158. G_debug(3, "Vedit_connect_lines(): lines=%d,%d -> connected",
  159. line, found);
  160. nlines_modified += 2;
  161. connected = 1;
  162. }
  163. }
  164. Vect_list_append(List_exclude, found);
  165. } while(List_found->n_values > 0 && !connected);
  166. }
  167. }
  168. Vect_destroy_list(List_exclude);
  169. Vect_destroy_list(List_found);
  170. return nlines_modified;
  171. }
  172. int connect_lines(struct Map_info *Map, int first, int line_from, int line_to,
  173. double thresh, struct ilist *List)
  174. {
  175. int line_new;
  176. int type_from, type_to;
  177. int n_points, seg, is;
  178. double x, y, px, py, x1, y1;
  179. double dist, spdist, lpdist, length, dist_p;
  180. double angle_t, angle_f, angle;
  181. struct line_pnts *Points_from, *Points_to, *Points_final;
  182. struct line_cats *Cats_from, *Cats_to;
  183. Points_from = Vect_new_line_struct();
  184. Points_to = Vect_new_line_struct();
  185. Points_final = Vect_new_line_struct();
  186. Cats_from = Vect_new_cats_struct();
  187. Cats_to = Vect_new_cats_struct();
  188. type_from = Vect_read_line(Map, Points_from, Cats_from, line_from);
  189. type_to = Vect_read_line(Map, Points_to, Cats_to, line_to);
  190. line_new = 0;
  191. if (!(type_from & GV_LINES) || !(type_to & GV_LINES))
  192. line_new = -1;
  193. if (line_new > -1) {
  194. n_points = Points_from->n_points - 1;
  195. if (first) {
  196. x = Points_from->x[0];
  197. y = Points_from->y[0];
  198. }
  199. else {
  200. x = Points_from->x[n_points];
  201. y = Points_from->y[n_points];
  202. }
  203. seg = Vect_line_distance(Points_to, x, y, 0.0, WITHOUT_Z,
  204. &px, &py, NULL, &dist, &spdist, &lpdist);
  205. if (seg > 0 && dist > 0.0 && (thresh < 0. || dist <= thresh)) {
  206. /* lines in threshold */
  207. if (first)
  208. length = 0;
  209. else
  210. length = Vect_line_length(Points_from);
  211. if (Vect_point_on_line(Points_from, length,
  212. NULL, NULL, NULL, &angle_f, NULL) > 0) {
  213. if (Vect_point_on_line(Points_to, lpdist,
  214. NULL, NULL, NULL, &angle_t,
  215. NULL) > 0) {
  216. angle = angle_t - angle_f;
  217. dist_p = fabs(dist / sin(angle));
  218. if (first) {
  219. if (angle_f < 0)
  220. angle_f -= M_PI;
  221. else
  222. angle_f += M_PI;
  223. }
  224. x1 = x + dist_p * cos(angle_f);
  225. y1 = y + dist_p * sin(angle_f);
  226. length = Vect_line_length(Points_to);
  227. Vect_line_insert_point(Points_to, seg, x1, y1, 0.);
  228. if (fabs(Vect_line_length(Points_to) - length) < length * 1e-3) {
  229. /* lines connected -> split line_to */
  230. /* update line_from */
  231. if (first) {
  232. Points_from->x[0] = x1;
  233. Points_from->y[0] = y1;
  234. }
  235. else {
  236. Points_from->x[n_points] = x1;
  237. Points_from->y[n_points] = y1;
  238. }
  239. line_new = Vect_rewrite_line(Map, line_from, type_from,
  240. Points_from, Cats_from);
  241. /* Vect_list_append(List, line_new); */
  242. /* update line_to -- first part */
  243. Vect_reset_line(Points_final);
  244. for (is = 0; is < seg; is++) {
  245. Vect_append_point(Points_final, Points_to->x[is],
  246. Points_to->y[is],
  247. Points_to->z[is]);
  248. }
  249. Vect_append_point(Points_final, x1, y1, 0.0);
  250. line_new = Vect_rewrite_line(Map, line_to, type_to,
  251. Points_final, Cats_to);
  252. /* Vect_list_append(List, line_new); */
  253. /* write second part */
  254. Vect_reset_line(Points_final);
  255. Vect_append_point(Points_final, x1, y1, 0.0);
  256. for (is = seg; is < Points_to->n_points; is++) {
  257. Vect_append_point(Points_final, Points_to->x[is],
  258. Points_to->y[is],
  259. Points_to->z[is]);
  260. }
  261. /* rewrite first part */
  262. line_new = Vect_write_line(Map, type_to,
  263. Points_final, Cats_to);
  264. /* Vect_list_append(List, line_new); */
  265. }
  266. }
  267. }
  268. }
  269. }
  270. Vect_destroy_line_struct(Points_from);
  271. Vect_destroy_line_struct(Points_to);
  272. Vect_destroy_line_struct(Points_final);
  273. Vect_destroy_cats_struct(Cats_from);
  274. Vect_destroy_cats_struct(Cats_to);
  275. return line_new > 0 ? 1 : 0;
  276. }