del_streams.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. #include <stdlib.h>
  2. #include <math.h>
  3. #include <grass/raster.h>
  4. #include <grass/glocale.h>
  5. #include "local_proto.h"
  6. /* get stream segment length */
  7. int seg_length(CELL stream_id, CELL *next_stream_id)
  8. {
  9. int r, c, r_nbr, c_nbr;
  10. int slength = 1;
  11. CELL curr_stream;
  12. int asp_r[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 };
  13. int asp_c[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 };
  14. ASP_FLAG af;
  15. r = stream_node[stream_id].r;
  16. c = stream_node[stream_id].c;
  17. if (next_stream_id)
  18. *next_stream_id = stream_id;
  19. /* get next downstream point */
  20. seg_get(&aspflag, (char *)&af, r, c);
  21. while (af.asp > 0) {
  22. r_nbr = r + asp_r[(int)af.asp];
  23. c_nbr = c + asp_c[(int)af.asp];
  24. /* user-defined depression */
  25. if (r_nbr == r && c_nbr == c)
  26. break;
  27. /* outside region */
  28. if (r_nbr < 0 || r_nbr >= nrows || c_nbr < 0 || c_nbr >= ncols)
  29. break;
  30. /* next stream */
  31. cseg_get(&stream, &curr_stream, r_nbr, c_nbr);
  32. if (next_stream_id)
  33. *next_stream_id = curr_stream;
  34. if (curr_stream != stream_id)
  35. break;
  36. slength++;
  37. r = r_nbr;
  38. c = c_nbr;
  39. seg_get(&aspflag, (char *)&af, r, c);
  40. }
  41. return slength;
  42. }
  43. /* change downstream id: update or remove */
  44. int update_stream_id(CELL stream_id, CELL new_stream_id)
  45. {
  46. int i, r, c, r_nbr, c_nbr;
  47. CELL new_stream = new_stream_id;
  48. CELL curr_stream;
  49. int asp_r[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 };
  50. int asp_c[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 };
  51. ASP_FLAG af;
  52. r = stream_node[stream_id].r;
  53. c = stream_node[stream_id].c;
  54. cseg_get(&stream, &curr_stream, r, c);
  55. if (curr_stream != stream_id)
  56. G_fatal_error("update downstream id: curr_stream != stream_id");
  57. cseg_put(&stream, &new_stream, r, c);
  58. curr_stream = stream_id;
  59. /* get next downstream point */
  60. seg_get(&aspflag, (char *)&af, r, c);
  61. while (af.asp > 0) {
  62. r_nbr = r + asp_r[(int)af.asp];
  63. c_nbr = c + asp_c[(int)af.asp];
  64. /* user-defined depression */
  65. if (r_nbr == r && c_nbr == c)
  66. break;
  67. /* outside region */
  68. if (r_nbr < 0 || r_nbr >= nrows || c_nbr < 0 || c_nbr >= ncols)
  69. break;
  70. /* next stream */
  71. cseg_get(&stream, &curr_stream, r_nbr, c_nbr);
  72. if (curr_stream != stream_id)
  73. break;
  74. r = r_nbr;
  75. c = c_nbr;
  76. cseg_put(&stream, &new_stream, r, c);
  77. seg_get(&aspflag, (char *)&af, r, c);
  78. }
  79. if (curr_stream <= 0)
  80. return curr_stream;
  81. /* update tributaries */
  82. if (curr_stream != stream_id) {
  83. int last_i = -1;
  84. for (i = 0; i < stream_node[curr_stream].n_trib; i++) {
  85. if (stream_node[curr_stream].trib[i] == stream_id) {
  86. if (new_stream_id) {
  87. stream_node[curr_stream].trib[i] = new_stream_id;
  88. }
  89. else {
  90. stream_node[curr_stream].n_trib--;
  91. stream_node[curr_stream].trib[i] = stream_node[curr_stream].trib[stream_node[curr_stream].n_trib];
  92. stream_node[curr_stream].trib[stream_node[curr_stream].n_trib] = 0;
  93. }
  94. last_i = i;
  95. break;
  96. }
  97. }
  98. for (i = 0; i < stream_node[curr_stream].n_trib; i++) {
  99. if (stream_node[curr_stream].trib[i] == stream_id) {
  100. G_warning("last_i %d, i %d", last_i, i);
  101. G_warning("failed updating stream %d at node %d", stream_id, curr_stream);
  102. }
  103. }
  104. }
  105. return curr_stream;
  106. }
  107. /* delete stream segments shorter than threshold */
  108. int del_streams(int min_length)
  109. {
  110. int i;
  111. int n_deleted = 0;
  112. CELL curr_stream, stream_id;
  113. int other_trib, tmp_trib;
  114. int slength;
  115. G_message(_("Deleting stream segments shorter than %d cells..."), min_length);
  116. /* TODO: proceed from stream heads to outlets
  117. * -> use depth first post order traversal */
  118. /* go through all nodes */
  119. for (i = 1; i <= n_stream_nodes; i++) {
  120. G_percent(i, n_stream_nodes, 2);
  121. /* not a stream head */
  122. if (stream_node[i].n_trib > 0)
  123. continue;
  124. /* already deleted */
  125. cseg_get(&stream, &curr_stream, stream_node[i].r, stream_node[i].c);
  126. if (curr_stream == 0)
  127. continue;
  128. /* get length counted as n cells */
  129. if ((slength = seg_length(i, &curr_stream)) >= min_length)
  130. continue;
  131. stream_id = i;
  132. /* check n sibling tributaries */
  133. if (curr_stream != stream_id) {
  134. /* only one sibling tributary */
  135. if (stream_node[curr_stream].n_trib == 2) {
  136. if (stream_node[curr_stream].trib[0] != stream_id)
  137. other_trib = stream_node[curr_stream].trib[0];
  138. else
  139. other_trib = stream_node[curr_stream].trib[1];
  140. /* other trib is also stream head */
  141. if (stream_node[other_trib].n_trib == 0) {
  142. /* use shorter one */
  143. if (seg_length(other_trib, NULL) < slength) {
  144. tmp_trib = stream_id;
  145. stream_id = other_trib;
  146. other_trib = tmp_trib;
  147. }
  148. }
  149. update_stream_id(stream_id, 0);
  150. n_deleted++;
  151. /* update downstream IDs */
  152. update_stream_id(curr_stream, other_trib);
  153. }
  154. /* more than one other tributary */
  155. else {
  156. update_stream_id(stream_id, 0);
  157. n_deleted++;
  158. }
  159. }
  160. /* stream head is also outlet */
  161. else {
  162. update_stream_id(stream_id, 0);
  163. n_deleted++;
  164. }
  165. }
  166. G_verbose_message(_("%d stream segments deleted"), n_deleted);
  167. return n_deleted;
  168. }