filldir.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <math.h>
  5. #include <limits.h>
  6. #include <float.h>
  7. #include <grass/gis.h>
  8. #include <grass/raster.h>
  9. #include "tinf.h"
  10. /* get the slope between two cells and return a slope direction */
  11. void check(CELL newdir, CELL * dir, void *center, void *edge, double cnst,
  12. double *oldslope)
  13. {
  14. double newslope;
  15. /* always discharge to a null boundary */
  16. if (is_null(edge)) {
  17. *oldslope = DBL_MAX;
  18. *dir = newdir;
  19. }
  20. else {
  21. newslope = slope(center, edge, cnst);
  22. if (newslope == *oldslope) {
  23. *dir += newdir;
  24. }
  25. else if (newslope > *oldslope) {
  26. *oldslope = newslope;
  27. *dir = newdir;
  28. }
  29. }
  30. return;
  31. }
  32. /* process one row, filling single-cell pits */
  33. int fill_row(int nl, int ns, struct band3 *bnd)
  34. {
  35. int j, offset, inc, rc;
  36. void *min;
  37. char *center;
  38. char *edge;
  39. inc = bpe();
  40. min = G_malloc(bpe());
  41. rc = 0;
  42. for (j = 1; j < ns - 1; j += 1) {
  43. offset = j * bpe();
  44. center = bnd->b[1] + offset;
  45. if (is_null(center))
  46. return rc;
  47. edge = bnd->b[0] + offset;
  48. min = edge - inc;
  49. min = get_min(min, edge);
  50. min = get_min(min, edge + inc);
  51. min = get_min(min, center - inc);
  52. min = get_min(min, center + inc);
  53. edge = bnd->b[2] + offset;
  54. min = get_min(min, edge - inc);
  55. min = get_min(min, edge);
  56. min = get_min(min, edge + inc);
  57. if (get_min(center, min) == center) {
  58. rc = 1;
  59. memcpy(center, min, bpe());
  60. }
  61. }
  62. return rc;
  63. }
  64. /* determine the flow direction at each cell on one row */
  65. void build_one_row(int i, int nl, int ns, struct band3 *bnd, CELL * dir)
  66. {
  67. int j, offset, inc;
  68. CELL sdir;
  69. double slope;
  70. char *center;
  71. char *edge;
  72. inc = bpe();
  73. for (j = 0; j < ns; j += 1) {
  74. offset = j * bpe();
  75. center = bnd->b[1] + offset;
  76. if (is_null(center)) {
  77. Rast_set_c_null_value(dir + j, 1);
  78. continue;
  79. }
  80. sdir = 0;
  81. slope = HUGE_VAL;
  82. if (i == 0) {
  83. sdir = 128;
  84. }
  85. else if (i == nl - 1) {
  86. sdir = 8;
  87. }
  88. else if (j == 0) {
  89. sdir = 32;
  90. }
  91. else if (j == ns - 1) {
  92. sdir = 2;
  93. }
  94. else {
  95. slope = -HUGE_VAL;
  96. /* check one row back */
  97. edge = bnd->b[0] + offset;
  98. check(64, &sdir, center, edge - inc, 1.4142136, &slope);
  99. check(128, &sdir, center, edge, 1., &slope);
  100. check(1, &sdir, center, edge + inc, 1.4142136, &slope);
  101. /* check this row */
  102. check(32, &sdir, center, center - inc, 1., &slope);
  103. check(2, &sdir, center, center + inc, 1., &slope);
  104. /* check one row forward */
  105. edge = bnd->b[2] + offset;
  106. check(16, &sdir, center, edge - inc, 1.4142136, &slope);
  107. check(8, &sdir, center, edge, 1., &slope);
  108. check(4, &sdir, center, edge + inc, 1.4142136, &slope);
  109. }
  110. if (slope == 0.)
  111. sdir = -sdir;
  112. else if (slope < 0.)
  113. sdir = -256;
  114. dir[j] = sdir;
  115. }
  116. return;
  117. }
  118. void filldir(int fe, int fd, int nl, struct band3 *bnd)
  119. {
  120. int i, bufsz;
  121. CELL *dir;
  122. /* fill single-cell depressions, except on outer rows and columns */
  123. lseek(fe, 0, SEEK_SET);
  124. advance_band3(fe, bnd);
  125. advance_band3(fe, bnd);
  126. for (i = 1; i < nl - 1; i += 1) {
  127. lseek(fe, (off_t) (i + 1) * bnd->sz, SEEK_SET);
  128. advance_band3(fe, bnd);
  129. if (fill_row(nl, bnd->ns, bnd)) {
  130. lseek(fe, (off_t) i * bnd->sz, SEEK_SET);
  131. write(fe, bnd->b[1], bnd->sz);
  132. }
  133. }
  134. advance_band3(0, bnd);
  135. if (fill_row(nl, bnd->ns, bnd)) {
  136. lseek(fe, (off_t) i * bnd->sz, SEEK_SET);
  137. write(fe, bnd->b[1], bnd->sz);
  138. }
  139. /* determine the flow direction in each cell. On outer rows and columns
  140. * the flow direction is always directly out of the map */
  141. dir = G_calloc(bnd->ns, sizeof(CELL));
  142. bufsz = bnd->ns * sizeof(CELL);
  143. lseek(fe, 0, SEEK_SET);
  144. lseek(fd, 0, SEEK_SET);
  145. advance_band3(fe, bnd);
  146. for (i = 0; i < nl; i += 1) {
  147. advance_band3(fe, bnd);
  148. build_one_row(i, nl, bnd->ns, bnd, dir);
  149. write(fd, dir, bufsz);
  150. }
  151. advance_band3(fe, bnd);
  152. build_one_row(i, nl, bnd->ns, bnd, dir);
  153. write(fd, dir, bufsz);
  154. G_free(dir);
  155. return;
  156. }