merge_lines.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. /*!
  2. \file merge_lines.c
  3. \brief Vector library - clean geometry (merge lines/boundaries)
  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
  7. GNU General Public License (>=v2).
  8. Read the file COPYING that comes with GRASS
  9. for details.
  10. \author Markus Metz
  11. */
  12. #include <grass/config.h>
  13. #include <stdlib.h>
  14. #include <math.h>
  15. #include <grass/gis.h>
  16. #include <grass/vector.h>
  17. #include <grass/glocale.h>
  18. /*!
  19. \brief Merge lines or boundaries in vector map.
  20. Merges lines specified by type in vector map.
  21. Useful for generalization and smoothing.
  22. Adjacent boundaries are merged as long as topology is maintained.
  23. Adjacent lines are merged as long as there are exactly two different
  24. lines connected at a given node.
  25. Categories are added up when merging.
  26. GV_BUILD_BASE as topo build level is sufficient, areas need not be built.
  27. \param Map input vector map
  28. \param type feature type
  29. \param[out] Err vector map where merged lines/boundaries will be written or NULL
  30. \param new_lines pointer to where number of new lines/boundaries is stored or NULL
  31. \return number of merged lines/boundaries
  32. */
  33. int Vect_merge_lines(struct Map_info *Map, int type, int *new_lines,
  34. struct Map_info *Err)
  35. {
  36. int line, nlines, i, c, first, last, next_line, curr_line;
  37. int merged = 0, newl = 0;
  38. int next_node, direction, node_n_lines, same_type;
  39. struct Plus_head *Plus;
  40. struct ilist *List;
  41. struct line_pnts *MPoints, *Points;
  42. struct line_cats *MCats, *Cats;
  43. struct P_line *Line;
  44. if ((type & GV_BOUNDARY) && (type & GV_LINE)) {
  45. G_warning
  46. ("Merging is done only with either lines or boundaries, not both types at the same time");
  47. return 0;
  48. }
  49. if (!(type & GV_BOUNDARY) && !(type & GV_LINE)) {
  50. G_warning
  51. ("Merging is done with lines or boundaries only, not with other types");
  52. return 0;
  53. }
  54. Plus = &(Map->plus);
  55. nlines = Vect_get_num_lines(Map);
  56. Points = Vect_new_line_struct();
  57. Cats = Vect_new_cats_struct();
  58. MPoints = Vect_new_line_struct();
  59. MCats = Vect_new_cats_struct();
  60. List = Vect_new_list();
  61. for (line = 1; line <= nlines; line++) {
  62. G_percent(line, nlines, 2);
  63. if (!Vect_line_alive(Map, line))
  64. continue;
  65. Line = Plus->Line[line];
  66. if (!(Line->type & type))
  67. continue;
  68. /* special cases:
  69. * - loop back to start boundary via several other boundaries
  70. * - one boundary forming closed loop
  71. * - node with 3 entries but only 2 boundaries, one of them connecting twice,
  72. * the other one must then be topologically incorrect in case of boundary */
  73. /* go backward as long as there is only one other line/boundary at the current node */
  74. G_debug(3, "go backward");
  75. next_node = Line->N1;
  76. first = -line;
  77. while (1) {
  78. node_n_lines = Vect_get_node_n_lines(Map, next_node);
  79. same_type = 0;
  80. next_line = first;
  81. for (i = 0; i < node_n_lines; i++) {
  82. curr_line = Vect_get_node_line(Map, next_node, i);
  83. if ((Plus->Line[abs(curr_line)]->type & type)) {
  84. same_type++;
  85. if (abs(curr_line) != abs(first))
  86. next_line = curr_line;
  87. }
  88. }
  89. if (same_type == 2 && abs(next_line) != abs(first) &&
  90. abs(next_line) != line) {
  91. first = next_line;
  92. if (first < 0)
  93. next_node = Plus->Line[-first]->N1;
  94. else
  95. next_node = Plus->Line[first]->N2;
  96. }
  97. else
  98. break;
  99. }
  100. /* go forward as long as there is only one other line/boundary at the current node */
  101. G_debug(3, "go forward");
  102. /* reverse direction */
  103. last = -first;
  104. if (last < 0)
  105. next_node = Plus->Line[-last]->N1;
  106. else
  107. next_node = Plus->Line[last]->N2;
  108. Vect_reset_list(List);
  109. while (1) {
  110. Vect_list_append(List, last);
  111. node_n_lines = Vect_get_node_n_lines(Map, next_node);
  112. same_type = 0;
  113. next_line = last;
  114. for (i = 0; i < node_n_lines; i++) {
  115. curr_line = Vect_get_node_line(Map, next_node, i);
  116. if ((Plus->Line[abs(curr_line)]->type & type)) {
  117. same_type++;
  118. if (abs(curr_line) != abs(last))
  119. next_line = curr_line;
  120. }
  121. }
  122. if (same_type == 2 && abs(next_line) != abs(last) &&
  123. abs(next_line) != abs(first)) {
  124. last = next_line;
  125. if (last < 0)
  126. next_node = Plus->Line[-last]->N1;
  127. else
  128. next_node = Plus->Line[last]->N2;
  129. }
  130. else
  131. break;
  132. }
  133. /* merge lines */
  134. if (List->n_values > 1) {
  135. G_debug(3, "merge %d lines", List->n_values);
  136. Vect_reset_line(MPoints);
  137. Vect_reset_cats(MCats);
  138. for (i = 0; i < List->n_values; i++) {
  139. Vect_reset_line(Points);
  140. Vect_reset_cats(Cats);
  141. Vect_read_line(Map, Points, Cats, abs(List->value[i]));
  142. direction = (List->value[i] < 0 ? GV_BACKWARD : GV_FORWARD);
  143. Vect_append_points(MPoints, Points, direction);
  144. MPoints->n_points--;
  145. for (c = 0; c < Cats->n_cats; c++) {
  146. Vect_cat_set(MCats, Cats->field[c], Cats->cat[c]);
  147. }
  148. if (Err) {
  149. /* write out lines/boundaries to be merged */
  150. Vect_write_line(Err, type, Points, Cats);
  151. }
  152. Vect_delete_line(Map, abs(List->value[i]));
  153. }
  154. MPoints->n_points++;
  155. Vect_write_line(Map, type, MPoints, MCats);
  156. merged += List->n_values;
  157. newl++;
  158. }
  159. nlines = Vect_get_num_lines(Map);
  160. }
  161. G_verbose_message(_("%d boundaries merged"), merged);
  162. G_verbose_message(_("%d new boundaries"), newl);
  163. if (new_lines)
  164. *new_lines = newl;
  165. return merged;
  166. }