filldepr.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /****************************************************************************
  2. *
  3. * MODULE: r.terraflow
  4. *
  5. * COPYRIGHT (C) 2007 Laura Toma
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. *****************************************************************************/
  18. #include <assert.h>
  19. #include "filldepr.h"
  20. #include "unionFind.h"
  21. #include "common.h"
  22. #define FLOOD_DEBUG if(0)
  23. /************************************************************/
  24. /* INPUT: stream containing the edgelist of watershed adjacency graph
  25. E={(u,v,h) | 0 <= u,v <= W-1}; W is the maximum number of watersheds
  26. (also counting the outside watershed 0)
  27. elevation_type*
  28. h is the smallest height on the boundary between watershed u and
  29. watershed v;
  30. the outside face is assumed to be watershed number 0
  31. E contains the edges between the watersheds on the boundary and the
  32. outside watershed 0;
  33. E is sorted increasingly by (h,u,v)
  34. OUTPUT: allocate and returns an array raise[1..W-1], raise[i] is the
  35. height to which the watershed i must be raised in order to have a
  36. valid flow path to the outside watershed (raise[0] is 0) */
  37. /************************************************************/
  38. elevation_type*
  39. fill_depression(AMI_STREAM<boundaryType> *boundaryStr,
  40. cclabel_type maxWatersheds) {
  41. if (stats) {
  42. stats->comment("----------", opt->verbose);
  43. stats->comment("flooding depressions");
  44. }
  45. /* find available memory */
  46. size_t mem_avail = getAvailableMemory();
  47. if (opt->verbose)
  48. MM_manager.print();
  49. /* find how much memory filling depression uses */
  50. size_t mem_usage = inmemory_fill_depression_mmusage(maxWatersheds);
  51. /* decide whether to run it in memory or not */
  52. if (mem_avail > mem_usage) {
  53. return inmemory_fill_depression(boundaryStr, maxWatersheds);
  54. } else {
  55. return ext_fill_depression(boundaryStr, maxWatersheds);
  56. }
  57. }
  58. /************************************************************/
  59. elevation_type*
  60. ext_fill_depression(AMI_STREAM<boundaryType> *boundaryStr,
  61. cclabel_type maxWatersheds) {
  62. G_fatal_error(_("Fill_depressions do not fit in memory. Not implemented yet"));
  63. }
  64. /************************************************************/
  65. /* inside the function memory allocation is done with malloc/calloc
  66. and not with new; memory check should be done prior to this function
  67. to decide whether there's enough available memory to run it*/
  68. /************************************************************/
  69. elevation_type*
  70. inmemory_fill_depression(AMI_STREAM<boundaryType> *boundaryStr,
  71. cclabel_type maxWatersheds) {
  72. assert(boundaryStr && maxWatersheds >= 0);
  73. /*__________________________________________________________*/
  74. /* initialize */
  75. /*__________________________________________________________*/
  76. /* allocate the raised-elevation array */
  77. elevation_type* raise = new elevation_type [maxWatersheds];
  78. assert(raise);
  79. /*allocate and initialize done; done[i] = true iff watershed i has
  80. found a flow path to the outside; initially only outside watershed
  81. is done */
  82. int* done = (int*)calloc(maxWatersheds, sizeof(int));
  83. assert(done);
  84. done[LABEL_BOUNDARY] = 1;
  85. /*allocate and initialize an union find structure; insert all
  86. watersheds except for the outside watershed; the outside watershed
  87. is not in the unionfind structure; */
  88. unionFind<cclabel_type> unionf;
  89. FLOOD_DEBUG printf("nb watersheds %d, bstream length %ld\n",
  90. (int)maxWatersheds, (long)boundaryStr->stream_len());
  91. for (cclabel_type i=1; i< maxWatersheds; i++) {
  92. FLOOD_DEBUG printf("makeset %d\n",i);
  93. unionf.makeSet(i);
  94. }
  95. /*__________________________________________________________*/
  96. /*SCAN THE EDGES; invariant---watersheds adjacent to a 'done' watershed
  97. become done */
  98. /*__________________________________________________________*/
  99. AMI_err ae;
  100. boundaryType* nextedge;
  101. elevation_type h;
  102. cclabel_type u, v, ur, vr;
  103. off_t nitems = boundaryStr->stream_len();
  104. boundaryStr->seek(0);
  105. for (size_t i=0; i< nitems; i++) {
  106. /*read next edge*/
  107. ae = boundaryStr->read_item(&nextedge);
  108. assert(ae == AMI_ERROR_NO_ERROR);
  109. u = nextedge->getLabel1();
  110. v = nextedge->getLabel2();
  111. h = nextedge->getElevation();
  112. FLOOD_DEBUG {
  113. printf("\nreading edge ((%d,%d),h=%d)\n",(int)u,(int)v,(int)h);
  114. }
  115. /*find representatives; LABEL_BOUNDARY means the outside watershed*/
  116. (u==LABEL_BOUNDARY)? ur = LABEL_BOUNDARY: ur = unionf.findSet(u);
  117. (v==LABEL_BOUNDARY)? vr = LABEL_BOUNDARY: vr = unionf.findSet(v);
  118. FLOOD_DEBUG printf("%d is %d, %d is %d\n", u, ur, v, vr);
  119. /*watersheds are done; just ignore it*/
  120. if ((ur == vr) || (done[ur] && done[vr])) {
  121. continue;
  122. }
  123. /*union and raise colliding watersheds*/
  124. /* if one of the watersheds is done, then raise the other one,
  125. mark it as done too but do not union them; this handles also the
  126. case of boundary watersheds; */
  127. if (done[ur] || done[vr]) {
  128. if (done[ur]) {
  129. FLOOD_DEBUG printf("%d is done, %d raised to %f and done\n",
  130. ur, vr, (double)h);
  131. done[vr] = 1;
  132. raise[vr] = h;
  133. } else {
  134. assert(done[vr]);
  135. FLOOD_DEBUG printf("%d is done, %d raised to %f and done\n",
  136. vr, ur, (double)h);
  137. done[ur] = 1;
  138. raise[ur] = h;
  139. }
  140. continue;
  141. }
  142. /* if none of the watersheds is done: union and raise them */
  143. assert(!done[ur] && !done[vr] && ur>0 && vr>0);
  144. FLOOD_DEBUG printf("union %d and %d, raised to %f\n", ur, vr, (double)h);
  145. raise[ur] = raise[vr] = h;
  146. unionf.makeUnion(ur,vr);
  147. }
  148. #ifndef NDEBUG
  149. for (cclabel_type i=1; i< maxWatersheds; i++) {
  150. /* assert(done[unionf.findSet(i)]); sometimes this fails! */
  151. if (!done[unionf.findSet(i)]) {
  152. G_warning(_("Watershed %d (R=%d) not done"),
  153. i, unionf.findSet(i));
  154. }
  155. }
  156. #endif
  157. /* for each watershed find its raised elevation */
  158. for (cclabel_type i=1; i< maxWatersheds; i++) {
  159. raise[i] = raise[unionf.findSet(i)];
  160. }
  161. raise[LABEL_BOUNDARY] = 0;
  162. /*__________________________________________________________*/
  163. /*cleanup*/
  164. /*__________________________________________________________*/
  165. free(done);
  166. return raise;
  167. }
  168. /************************************************************/
  169. /* returns the amount of mmemory allocated by
  170. inmemory_fill_depression() */
  171. size_t
  172. inmemory_fill_depression_mmusage(cclabel_type maxWatersheds) {
  173. size_t mmusage = 0;
  174. /*account for done array*/
  175. mmusage += sizeof(int)*maxWatersheds;
  176. /* account for raise array */
  177. mmusage += sizeof(elevation_type)*maxWatersheds;
  178. /*account for unionFind structure*/
  179. unionFind<cclabel_type> foo;
  180. mmusage += foo.mmusage(maxWatersheds);
  181. return mmusage;
  182. }
  183. /************************************************************/
  184. /* produce a new stream where each elevation e inside watershed i is
  185. replaced with max(raise[i], e) */
  186. /************************************************************/
  187. void
  188. commit_fill(AMI_STREAM<labelElevType>* labeledGrid,
  189. elevation_type* raise, cclabel_type maxWatersheds,
  190. AMI_STREAM<elevation_type>* filledGrid) {
  191. labelElevType* pt;
  192. elevation_type h;
  193. labeledGrid->seek(0);
  194. while (labeledGrid->read_item(&pt) == AMI_ERROR_NO_ERROR) {
  195. h = pt->getElevation();
  196. if(is_nodata(h) || pt->getLabel() == LABEL_UNDEF) {
  197. /*h = nodataType::ELEVATION_NODATA; ..unhack... XXX*/
  198. } else {
  199. assert(pt->getLabel() < maxWatersheds);
  200. h = (pt->getElevation() < raise[pt->getLabel()])?
  201. raise[pt->getLabel()]: pt->getElevation();
  202. }
  203. filledGrid->write_item(h);
  204. }
  205. /* cout << "filled " << filledGrid->stream_len() << " points\n"; */
  206. }