clean_nodes.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /*!
  2. \file lib/vector/Vlib/clean_nodes.c
  3. \brief Vector library - Clean boundaries at nodes
  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 GNU General Public License
  7. (>=v2). Read the file COPYING that comes with GRASS for details.
  8. \author Radim Blazek
  9. */
  10. #include <stdlib.h>
  11. #include <grass/vector.h>
  12. #include <grass/glocale.h>
  13. /*!
  14. \brief Clean small angles at nodes.
  15. It may happen that even if the angle between 2 boundaries at node
  16. is very small, the calculated angle is 0 because of representation
  17. error. The map must be built at least on level GV_BUILD_BASE
  18. \param Map input map
  19. \param otype feature type
  20. \param[out] Err vector map where error line segments are written
  21. \return number of line modifications
  22. */
  23. int
  24. Vect_clean_small_angles_at_nodes(struct Map_info *Map, int otype,
  25. struct Map_info *Err)
  26. {
  27. int node, nnodes;
  28. int nmodif = 0;
  29. struct line_pnts *Points;
  30. struct line_cats *SCats, *LCats, *OCats;
  31. Points = Vect_new_line_struct();
  32. SCats = Vect_new_cats_struct();
  33. LCats = Vect_new_cats_struct();
  34. OCats = Vect_new_cats_struct();
  35. nnodes = Vect_get_num_nodes(Map);
  36. for (node = 1; node <= Vect_get_num_nodes(Map); node++) {
  37. int i, nlines;
  38. if (node <= nnodes)
  39. G_percent(node, nnodes, 1);
  40. G_debug(3, "node = %d", node);
  41. if (!Vect_node_alive(Map, node))
  42. continue;
  43. while (1) {
  44. float angle1 = -100;
  45. int line1 = -999; /* value not important, just for debug */
  46. int clean = 1;
  47. nlines = Vect_get_node_n_lines(Map, node);
  48. G_debug(3, "nlines = %d", nlines);
  49. for (i = 0; i < nlines; i++) {
  50. struct P_line *Line;
  51. int line2;
  52. float angle2;
  53. line2 = Vect_get_node_line(Map, node, i);
  54. Line = Map->plus.Line[abs(line2)];
  55. if (!Line)
  56. continue;
  57. G_debug(4, " type = %d", Line->type);
  58. if (!(Line->type & (otype & GV_LINES)))
  59. continue;
  60. angle2 = Vect_get_node_line_angle(Map, node, i);
  61. if (angle2 == -9.0)
  62. continue; /* Degenerated line */
  63. G_debug(4, " line1 = %d angle1 = %e line2 = %d angle2 = %e",
  64. line1, angle1, line2, angle2);
  65. if (angle2 == angle1) {
  66. int j;
  67. double length1, length2;
  68. int short_line; /* line with shorter end segment */
  69. int long_line; /* line with longer end segment */
  70. int new_short_line = 0; /* line number of short line after rewrite */
  71. int short_type, long_type, type;
  72. double x, y, z, nx, ny, nz;
  73. G_debug(4, " identical angles -> clean");
  74. /* Length of end segments for both lines */
  75. Vect_read_line(Map, Points, NULL, abs(line1));
  76. if (line1 > 0) {
  77. length1 =
  78. Vect_points_distance(Points->x[0], Points->y[0],
  79. 0.0, Points->x[1],
  80. Points->y[1], 0.0, 0);
  81. }
  82. else {
  83. int np;
  84. np = Points->n_points;
  85. length1 =
  86. Vect_points_distance(Points->x[np - 1],
  87. Points->y[np - 1], 0.0,
  88. Points->x[np - 2],
  89. Points->y[np - 2], 0.0, 0);
  90. }
  91. Vect_read_line(Map, Points, NULL, abs(line2));
  92. if (line2 > 0) {
  93. length2 =
  94. Vect_points_distance(Points->x[0], Points->y[0],
  95. 0.0, Points->x[1],
  96. Points->y[1], 0.0, 0);
  97. }
  98. else {
  99. int np;
  100. np = Points->n_points;
  101. length2 =
  102. Vect_points_distance(Points->x[np - 1],
  103. Points->y[np - 1], 0.0,
  104. Points->x[np - 2],
  105. Points->y[np - 2], 0.0, 0);
  106. }
  107. G_debug(4, " length1 = %f length2 = %f", length1,
  108. length2);
  109. if (length1 < length2) {
  110. short_line = line1;
  111. long_line = line2;
  112. }
  113. else {
  114. short_line = line2;
  115. long_line = line1;
  116. }
  117. /* Remove end segment from short_line */
  118. short_type =
  119. Vect_read_line(Map, Points, SCats, abs(short_line));
  120. if (short_line > 0) {
  121. x = Points->x[1];
  122. y = Points->y[1];
  123. z = Points->z[1];
  124. Vect_line_delete_point(Points, 0); /* first */
  125. }
  126. else {
  127. x = Points->x[Points->n_points - 2];
  128. y = Points->y[Points->n_points - 2];
  129. z = Points->z[Points->n_points - 2];
  130. Vect_line_delete_point(Points, Points->n_points - 1); /* last */
  131. }
  132. /* It may happen that it is one line: node could be deleted,
  133. * in that case we have to read the node coords first */
  134. Vect_get_node_coor(Map, node, &nx, &ny, &nz);
  135. if (Points->n_points > 1) {
  136. new_short_line =
  137. Vect_rewrite_line(Map, abs(short_line),
  138. short_type, Points, SCats);
  139. }
  140. else {
  141. Vect_delete_line(Map, abs(short_line));
  142. }
  143. /* It may happen that it is one line, in that case we have to take the new
  144. * short line as long line, orientation is not changed */
  145. if (abs(line1) == abs(line2)) {
  146. if (long_line > 0)
  147. long_line = new_short_line;
  148. else
  149. long_line = -new_short_line;
  150. }
  151. /* Add new line (must be before rewrite of long_line otherwise node could be deleted) */
  152. long_type =
  153. Vect_read_line(Map, NULL, LCats, abs(long_line));
  154. Vect_reset_cats(OCats);
  155. for (j = 0; j < SCats->n_cats; j++) {
  156. Vect_cat_set(OCats, SCats->field[j], SCats->cat[j]);
  157. }
  158. for (j = 0; j < LCats->n_cats; j++) {
  159. Vect_cat_set(OCats, LCats->field[j], LCats->cat[j]);
  160. }
  161. if (long_type == GV_BOUNDARY || short_type == GV_BOUNDARY) {
  162. type = GV_BOUNDARY;
  163. }
  164. else {
  165. type = GV_LINE;
  166. }
  167. Vect_reset_line(Points);
  168. Vect_append_point(Points, nx, ny, nz);
  169. Vect_append_point(Points, x, y, z);
  170. Vect_write_line(Map, type, Points, OCats);
  171. if (Err) {
  172. Vect_write_line(Err, type, Points, OCats);
  173. }
  174. /* Snap long_line to the new short_line end */
  175. long_type =
  176. Vect_read_line(Map, Points, LCats, abs(long_line));
  177. if (long_line > 0) {
  178. Points->x[0] = x;
  179. Points->y[0] = y;
  180. Points->z[0] = z;
  181. }
  182. else {
  183. Points->x[Points->n_points - 1] = x;
  184. Points->y[Points->n_points - 1] = y;
  185. Points->z[Points->n_points - 1] = z;
  186. }
  187. Vect_line_prune(Points);
  188. if (Points->n_points > 1) {
  189. Vect_rewrite_line(Map, abs(long_line), long_type,
  190. Points, LCats);
  191. }
  192. else {
  193. Vect_delete_line(Map, abs(long_line));
  194. }
  195. nmodif += 3;
  196. clean = 0;
  197. break;
  198. }
  199. line1 = line2;
  200. angle1 = angle2;
  201. }
  202. if (clean || !Vect_node_alive(Map, node))
  203. break;
  204. }
  205. }
  206. G_verbose_message(_("Modifications: %d"), nmodif);
  207. return (nmodif);
  208. }