merge.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. /*!
  2. \file lib/vector/vedit/merge.c
  3. \brief Vedit library - merge lines
  4. (C) 2006-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 Jachym Cepicky <jachym.cepicky gmail.com>
  8. \author Martin Landa <landa.martin gmail.com>
  9. */
  10. #include <grass/vedit.h>
  11. /*!
  12. \brief Merge two given lines a, b
  13. a : Points1/Cats1
  14. b : Points2/Cats2
  15. merged line : Points/Cats
  16. \param Points1,Cats1 first line
  17. \param Points2,Cats2 second line
  18. \param thresh threshold value
  19. \param[out] Points result line
  20. \return 1 on success
  21. \return 0 on error
  22. */
  23. static int merge_lines(struct line_pnts *Points1, struct line_cats *Cats1,
  24. struct line_pnts *Points2, struct line_cats *Cats2,
  25. double thresh, struct line_pnts **Points);
  26. /*!
  27. \brief Merge lines/boundaries
  28. At least two lines need to be given.
  29. \param Map pointer to Map_info
  30. \param List list of selected lines
  31. \return number of merged lines
  32. \return -1 on error
  33. */
  34. int Vedit_merge_lines(struct Map_info *Map, struct ilist *List)
  35. {
  36. struct ilist *List_in_box;
  37. struct line_pnts *Points1, *Points2, *Points;
  38. struct line_cats *Cats1, *Cats2;
  39. int line_i, i, j;
  40. int line, line1, type1, line2;
  41. int do_merge;
  42. /* number of lines (original, selected, merged) */
  43. int nlines, nlines_merged;
  44. nlines_merged = 0;
  45. if (List->n_values < 2) {
  46. return 0;
  47. }
  48. G_debug(1, "Vedit_merge_lines(): merging %d lines", List->n_values);
  49. Points1 = Vect_new_line_struct();
  50. Cats1 = Vect_new_cats_struct();
  51. Points2 = Vect_new_line_struct();
  52. Cats2 = Vect_new_cats_struct();
  53. Points = Vect_new_line_struct();
  54. List_in_box = Vect_new_list();
  55. nlines = Vect_get_num_lines(Map);
  56. /* merge lines */
  57. for (line_i = 0; line_i < List->n_values; line_i++) {
  58. line1 = List->value[line_i];
  59. if (!Vect_line_alive(Map, line1))
  60. continue;
  61. type1 = Vect_read_line(Map, Points1, Cats1, line1);
  62. if (!(type1 & GV_LINES))
  63. continue;
  64. /* remove duplicate points */
  65. Vect_line_prune(Points1);
  66. if (Points1->n_points < 2) {
  67. G_debug(3, "Vedit_merge_lines(): skipping zero length line");
  68. continue;
  69. }
  70. Vect_reset_line(Points);
  71. for (i = 0; i < Points1->n_points; i += Points1->n_points - 1) {
  72. Vect_reset_list(List_in_box);
  73. /* define searching region */
  74. Vect_reset_line(Points2);
  75. /*
  76. Vect_append_point (Points2, Points1 -> x[i] - thresh,
  77. Points1 -> y[i] + thresh, Points1 -> z[i]);
  78. Vect_append_point (Points2, Points1 -> x[i] + thresh,
  79. Points1 -> y[i] + thresh, Points1 -> z[i]);
  80. Vect_append_point (Points2, Points1 -> x[i] + thresh,
  81. Points1 -> y[i] - thresh, Points1 -> z[i]);
  82. Vect_append_point (Points2, Points1 -> x[i] - thresh,
  83. Points1 -> y[i] - thresh, Points1 -> z[i]);
  84. */
  85. Vect_append_point(Points2, Points1->x[i],
  86. Points1->y[i], Points1->z[i]);
  87. /*
  88. * merge lines only if two lines found in the region
  89. * i.e. the current line and an adjacent line
  90. */
  91. /* NOTE
  92. * - this merges two lines also if more than two lines are
  93. * found in the region, but only two of these lines are
  94. * in the List
  95. * - this not only merges lines connected by end points
  96. * but also any adjacent line with a mid point identical
  97. * to one of the end points of the current line
  98. */
  99. if (0 < Vect_find_line_list(Map, Points1->x[i], Points1->y[i],
  100. Points1->z[i], GV_LINES, 0, 0,
  101. NULL, List_in_box)) {
  102. do_merge = 1;
  103. line2 = -1;
  104. for (j = 0; do_merge && j < List_in_box->n_values; j++) {
  105. if (List_in_box->value[j] == line1 ||
  106. !Vect_line_alive(Map, List_in_box->value[j]))
  107. continue;
  108. if (Vect_val_in_list(List, List_in_box->value[j])) {
  109. Vect_read_line(Map, Points2, Cats2, List_in_box->value[j]);
  110. Vect_line_prune(Points2);
  111. if (Points2->n_points == 1) {
  112. line2 = List_in_box->value[j];
  113. do_merge = 1;
  114. break;
  115. }
  116. if (line2 > 0) {
  117. /* three lines found
  118. * selected lines will be not merged
  119. */
  120. do_merge = 0;
  121. }
  122. else {
  123. line2 = List_in_box->value[j];
  124. }
  125. }
  126. }
  127. if (!do_merge || line2 < 0)
  128. continue;
  129. Vect_read_line(Map, Points2, Cats2, line2);
  130. merge_lines(Points1, Cats1, Points2, Cats2, -1.0, &Points); /* do not use threshold value */
  131. G_debug(3, "Vedit_merge_lines(): lines=%d,%d", line1, line2);
  132. if (Points->n_points > 0) {
  133. if (Vect_delete_line(Map, line2) == -1) {
  134. return -1;
  135. }
  136. if (line2 <= nlines)
  137. nlines_merged++;
  138. }
  139. }
  140. } /* for each node */
  141. if (Points->n_points > 0) {
  142. line = Vect_rewrite_line(Map, line1, type1, Points, Cats1);
  143. if (line < 0) {
  144. return -1;
  145. }
  146. if (line1 <= nlines)
  147. nlines_merged++;
  148. /* update number of lines */
  149. G_ilist_add(List, line);
  150. }
  151. } /* for each line */
  152. /* destroy structures */
  153. Vect_destroy_line_struct(Points1);
  154. Vect_destroy_line_struct(Points2);
  155. Vect_destroy_line_struct(Points);
  156. Vect_destroy_cats_struct(Cats1);
  157. Vect_destroy_cats_struct(Cats2);
  158. return nlines_merged;
  159. }
  160. static int merge_lines(struct line_pnts *Points1, struct line_cats *Cats1,
  161. struct line_pnts *Points2, struct line_cats *Cats2,
  162. double thresh, struct line_pnts **Points)
  163. {
  164. struct line_pnts *ps = *Points;
  165. struct line_cats *cs = Cats1;
  166. int i, mindistidx;
  167. double mindist;
  168. /* find mininal distance and its index */
  169. mindist = Vedit_get_min_distance(Points1, Points2, 0, /* TODO 3D */
  170. &mindistidx);
  171. G_debug(3, " merge line ? index: %d, mindist: %g, thresh: %g",
  172. mindistidx, mindist, thresh);
  173. if (thresh > 0 && mindist > thresh) {
  174. return 0;
  175. }
  176. /* set index and other things */
  177. switch (mindistidx) {
  178. /* for each mindistidx create new line */
  179. case 0:
  180. Vect_append_points(ps, Points2, GV_BACKWARD);
  181. if (ps->n_points == Points2->n_points)
  182. Vect_append_points(ps, Points1, GV_FORWARD);
  183. break;
  184. case 1:
  185. Vect_append_points(ps, Points2, GV_FORWARD);
  186. if (ps->n_points == Points2->n_points)
  187. Vect_append_points(ps, Points1, GV_FORWARD);
  188. break;
  189. case 2:
  190. if (ps->n_points == 0)
  191. Vect_append_points(ps, Points1, GV_FORWARD);
  192. Vect_append_points(ps, Points2, GV_FORWARD);
  193. break;
  194. case 3:
  195. if (ps->n_points == 0)
  196. Vect_append_points(ps, Points1, GV_FORWARD);
  197. Vect_append_points(ps, Points2, GV_BACKWARD);
  198. break;
  199. default:
  200. break;
  201. }
  202. /* remove duplicate points */
  203. Vect_line_prune(ps);
  204. /* copy categories if needed */
  205. for (i = 0; i < Cats2->n_cats; i++) {
  206. Vect_cat_set(cs, Cats2->field[i], Cats2->cat[i]);
  207. }
  208. return 1;
  209. }