thin.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. #include <stdlib.h>
  2. #include <grass/gis.h>
  3. #include <grass/glocale.h>
  4. #include "local_proto.h"
  5. int thin_seg(int stream_id)
  6. {
  7. int thinned = 0;
  8. int r, c, r_nbr, c_nbr, last_r, last_c;
  9. CELL curr_stream, no_stream = 0;
  10. int asp_r[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 };
  11. int asp_c[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 };
  12. ASP_FLAG af;
  13. r = stream_node[stream_id].r;
  14. c = stream_node[stream_id].c;
  15. cseg_get(&stream, &curr_stream, r, c);
  16. seg_get(&aspflag, (char *)&af, r, c);
  17. if (af.asp > 0) {
  18. /* get downstream point */
  19. last_r = r + asp_r[(int)af.asp];
  20. last_c = c + asp_c[(int)af.asp];
  21. cseg_get(&stream, &curr_stream, last_r, last_c);
  22. if (curr_stream != stream_id)
  23. return thinned;
  24. /* get next downstream point */
  25. seg_get(&aspflag, (char *)&af, last_r, last_c);
  26. while (af.asp > 0) {
  27. r_nbr = last_r + asp_r[(int)af.asp];
  28. c_nbr = last_c + asp_c[(int)af.asp];
  29. if (r_nbr == last_r && c_nbr == last_c)
  30. return thinned;
  31. if (r_nbr < 0 || r_nbr >= nrows || c_nbr < 0 || c_nbr >= ncols)
  32. return thinned;
  33. cseg_get(&stream, &curr_stream, r_nbr, c_nbr);
  34. if (curr_stream != stream_id)
  35. return thinned;
  36. if (abs(r_nbr - r) < 2 && abs(c_nbr - c) < 2) {
  37. /* eliminate last point */
  38. cseg_put(&stream, &no_stream, last_r, last_c);
  39. FLAG_UNSET(af.flag, STREAMFLAG);
  40. seg_put(&aspflag, (char *)&af, last_r, last_c);
  41. /* update start point */
  42. seg_get(&aspflag, (char *)&af, r, c);
  43. af.asp = drain[r - r_nbr + 1][c - c_nbr + 1];
  44. seg_put(&aspflag, (char *)&af, r, c);
  45. thinned = 1;
  46. }
  47. else {
  48. /* nothing to eliminate, continue from last point */
  49. r = last_r;
  50. c = last_c;
  51. }
  52. last_r = r_nbr;
  53. last_c = c_nbr;
  54. seg_get(&aspflag, (char *)&af, last_r, last_c);
  55. }
  56. }
  57. return thinned;
  58. }
  59. int thin_streams(void)
  60. {
  61. int i, j, r, c, done;
  62. CELL stream_id;
  63. int next_node;
  64. struct sstack
  65. {
  66. int stream_id;
  67. int next_trib;
  68. } *nodestack;
  69. int top = 0, stack_step = 1000;
  70. int n_trib_total;
  71. int n_thinned = 0;
  72. G_message(_("Thinning stream segments..."));
  73. nodestack = (struct sstack *)G_malloc(stack_step * sizeof(struct sstack));
  74. for (i = 0; i < n_outlets; i++) {
  75. G_percent(i, n_outlets, 2);
  76. r = outlets[i].r;
  77. c = outlets[i].c;
  78. cseg_get(&stream, &stream_id, r, c);
  79. if (stream_id == 0)
  80. continue;
  81. /* add root node to stack */
  82. G_debug(2, "add root node");
  83. top = 0;
  84. nodestack[top].stream_id = stream_id;
  85. nodestack[top].next_trib = 0;
  86. /* depth first post order traversal */
  87. G_debug(2, "traverse");
  88. while (top >= 0) {
  89. done = 1;
  90. stream_id = nodestack[top].stream_id;
  91. G_debug(3, "stream_id %d, top %d", stream_id, top);
  92. if (nodestack[top].next_trib < stream_node[stream_id].n_trib) {
  93. /* add to stack */
  94. G_debug(3, "get next node");
  95. next_node =
  96. stream_node[stream_id].trib[nodestack[top].next_trib];
  97. G_debug(3, "add to stack: next %d, trib %d, n trib %d",
  98. next_node, nodestack[top].next_trib,
  99. stream_node[stream_id].n_trib);
  100. nodestack[top].next_trib++;
  101. top++;
  102. if (top >= stack_step) {
  103. /* need more space */
  104. stack_step += 1000;
  105. nodestack =
  106. (struct sstack *)G_realloc(nodestack,
  107. stack_step *
  108. sizeof(struct sstack));
  109. }
  110. nodestack[top].next_trib = 0;
  111. nodestack[top].stream_id = next_node;
  112. done = 0;
  113. G_debug(3, "go further down");
  114. }
  115. if (done) {
  116. /* thin stream segment */
  117. G_debug(3, "thin stream segment %d", stream_id);
  118. if (thin_seg(stream_id) == 0)
  119. G_debug(3, "segment %d not thinned", stream_id);
  120. else {
  121. G_debug(3, "segment %d thinned", stream_id);
  122. n_thinned++;
  123. }
  124. top--;
  125. /* count tributaries */
  126. if (top >= 0) {
  127. n_trib_total = 0;
  128. stream_id = nodestack[top].stream_id;
  129. for (j = 0; j < stream_node[stream_id].n_trib; j++) {
  130. /* intermediate */
  131. if (stream_node[stream_node[stream_id].trib[j]].
  132. n_trib > 0)
  133. n_trib_total +=
  134. stream_node[stream_node[stream_id].trib[j]].
  135. n_trib_total;
  136. /* start */
  137. else
  138. n_trib_total++;
  139. }
  140. stream_node[stream_id].n_trib_total = n_trib_total;
  141. }
  142. }
  143. }
  144. }
  145. G_percent(n_outlets, n_outlets, 1); /* finish it */
  146. G_free(nodestack);
  147. G_verbose_message(_("%d of %lld stream segments were thinned"), n_thinned, n_stream_nodes);
  148. return 1;
  149. }