water.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  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. #ifndef WATER_H
  19. #define WATER_H
  20. /* watershed analysis related structures */
  21. #include "types.h"
  22. #include "plateau.h"
  23. #include "nodata.h"
  24. #include "genericWindow.h"
  25. char directionSymbol(direction_type dir);
  26. class labelElevTypePrintLabel;
  27. /* ---------------------------------------------------------------------- */
  28. class labelElevType : public ijBaseType {
  29. friend class labelElevTypePrintLabel;
  30. protected:
  31. elevation_type el;
  32. cclabel_type label;
  33. public:
  34. labelElevType() : label(LABEL_UNDEF) {};
  35. labelElevType(dimension_type gi,
  36. dimension_type gj,
  37. elevation_type gel,
  38. cclabel_type glabel) :
  39. ijBaseType(gi, gj), el(gel), label(glabel) {};
  40. cclabel_type getLabel() const { return label; };
  41. elevation_type getElevation() const { return el; };
  42. friend ostream& operator << (ostream& s, const labelElevType &p);
  43. static char *printLabel(const labelElevType &p);
  44. friend class printLabel;
  45. };
  46. class ijCmpLabelElevType {
  47. public:
  48. static int compare(const labelElevType &a, const labelElevType &b) {
  49. return ijBaseType::compare(a, b);
  50. }
  51. };
  52. class labelCmpLabelElevType {
  53. public:
  54. static int compare(const labelElevType &a, const labelElevType &b) {
  55. return a.getLabel() - b.getLabel();
  56. /* return (a.getLabel() == b.getLabel() ? 0
  57. : (a.getLabel() < b.getLabel() ? -1 : 1)); */
  58. }
  59. };
  60. class labelElevTypePrintLabel {
  61. public:
  62. cclabel_type operator()(const labelElevType &p) {
  63. return p.label;
  64. }
  65. };
  66. /* ---------------------------------------------------------------------- */
  67. class waterCmpBoundaryType;
  68. class elevCmpBoundaryType;
  69. class boundaryCmpBoundaryType;
  70. class ijCmpBoundaryType;
  71. class boundaryType : public labelElevType {
  72. friend class waterCmpBoundaryType;
  73. friend class elevCmpBoundaryType;
  74. friend class boundaryCmpBoundaryType;
  75. protected:
  76. cclabel_type label2;
  77. public:
  78. boundaryType() : label2(LABEL_UNDEF) {};
  79. boundaryType(dimension_type gi,
  80. dimension_type gj,
  81. elevation_type gel,
  82. cclabel_type glabel1,
  83. cclabel_type glabel2) :
  84. labelElevType(gi, gj, gel, glabel1), label2(glabel2) {
  85. assert(glabel1 < glabel2);
  86. };
  87. boundaryType(labelElevType let, cclabel_type glabel2) : labelElevType(let) {
  88. if(let.getLabel() < glabel2) {
  89. label2 = glabel2;
  90. } else {
  91. label2 = label;
  92. label = glabel2;
  93. }
  94. };
  95. boundaryType(labelElevType let, elevation_type gel, cclabel_type glabel2)
  96. : labelElevType(let) {
  97. el = gel;
  98. if(let.getLabel() < glabel2) {
  99. label2 = glabel2;
  100. } else {
  101. label2 = label;
  102. label = glabel2;
  103. }
  104. };
  105. bool isValid() const { return label2 != LABEL_UNDEF; }
  106. cclabel_type getLabel1() const { return getLabel(); }
  107. cclabel_type getLabel2() const { return label2; }
  108. friend ostream& operator << (ostream& s, const boundaryType &p);
  109. static char *print(const boundaryType &p);
  110. };
  111. class ijCmpBoundaryType {
  112. public:
  113. static int compare(const boundaryType &a, const boundaryType &b) {
  114. return ijBaseType::compare(a, b);
  115. }
  116. }
  117. ;
  118. class waterCmpBoundaryType {
  119. public:
  120. static int compare(const boundaryType &a, const boundaryType &b) {
  121. if(a.label < b.label) return -1;
  122. if(a.label > b.label) return 1;
  123. if(a.label2 < b.label2) return -1;
  124. if(a.label2 > b.label2) return 1;
  125. if(a.el < b.el) return -1;
  126. if(a.el > b.el) return 1;
  127. return 0;
  128. }
  129. };
  130. class elevCmpBoundaryType {
  131. public:
  132. static int compare(const boundaryType &a, const boundaryType &b) {
  133. if(a.el < b.el) return -1;
  134. if(a.el > b.el) return 1;
  135. return 0;
  136. }
  137. };
  138. class boundaryCmpBoundaryType {
  139. public:
  140. static int compare(const boundaryType &a, const boundaryType &b) {
  141. if(a.label < b.label) return -1;
  142. if(a.label > b.label) return 1;
  143. if(a.label2 < b.label2) return -1;
  144. if(a.label2 > b.label2) return 1;
  145. return 0;
  146. }
  147. };
  148. /* ---------------------------------------------------------------------- */
  149. class fillPriority : public ijBaseType {
  150. protected:
  151. elevation_type el;
  152. bfs_depth_type depth;
  153. public:
  154. fillPriority() : ijBaseType(-1,-1), el(-1), depth(DEPTH_INITIAL) {};
  155. fillPriority(elevation_type gel,
  156. bfs_depth_type gdepth,
  157. dimension_type gi,
  158. dimension_type gj) :
  159. ijBaseType(gi, gj), el(gel), depth(gdepth) {}
  160. friend int operator<(const fillPriority &a, const fillPriority &b);
  161. friend int operator<=(const fillPriority &a, const fillPriority &b);
  162. friend int operator>(const fillPriority &a, const fillPriority &b);
  163. friend int operator==(const fillPriority &a, const fillPriority &b);
  164. friend int operator!=(const fillPriority &a, const fillPriority &b);
  165. friend ostream& operator << (ostream& s, const fillPriority &p);
  166. static int compare(const fillPriority &a, const fillPriority &b);
  167. static int qscompare(const void *a, const void *b);
  168. };
  169. /* ---------------------------------------------------------------------- */
  170. class fillPLabel : public fillPriority {
  171. cclabel_type label;
  172. public:
  173. fillPLabel() : label(LABEL_UNDEF) {};
  174. fillPLabel(const fillPriority &gpriority, const cclabel_type glabel) :
  175. fillPriority(gpriority), label(glabel) {}
  176. fillPriority getPriority() const { return (fillPriority)(*this); }
  177. cclabel_type getLabel() const { return label; }
  178. /* static char *print(const fillPLabel &p); */
  179. boundaryType getBoundary(cclabel_type label2) {
  180. if(label < label2) {
  181. return boundaryType(i, j, el, label, label2);
  182. } else {
  183. return boundaryType(i, j, el, label2, label);
  184. }
  185. }
  186. friend ostream& operator << (ostream& s, const fillPLabel &p) {
  187. return s << "[" << (fillPriority)p << ", " << p.label << "]";
  188. }
  189. };
  190. /* ---------------------------------------------------------------------- */
  191. class waterWindowBaseType {
  192. public:
  193. elevation_type el;
  194. direction_type dir;
  195. bfs_depth_type depth;
  196. waterWindowBaseType() : el(nodataType::ELEVATION_NODATA), dir(0),
  197. depth(DEPTH_INITIAL) {};
  198. waterWindowBaseType(elevation_type gel,
  199. direction_type gdir, bfs_depth_type gdepth) :
  200. el(gel), dir(gdir), depth(gdepth) {};
  201. friend int
  202. operator==(const waterWindowBaseType &a, const waterWindowBaseType &b) {
  203. return (a.el == b.el) && (a.dir == b.dir) && (a.depth == b.depth);
  204. }
  205. friend ostream& operator << (ostream& s, const waterWindowBaseType &p) {
  206. return s << "["
  207. << "el=" << p.el << ", "
  208. << "dir=" << p.dir << ", "
  209. << "depth=" << p.depth << "]";
  210. }
  211. };
  212. /* ---------------------------------------------------------------------- */
  213. class waterType;
  214. class waterGridType;
  215. class waterType : public ijBaseType {
  216. friend int ijCmp_waterType(const waterType &a, const waterType &b);
  217. friend class waterGridType;
  218. protected:
  219. direction_type dir;
  220. bfs_depth_type depth;
  221. cclabel_type label;
  222. public:
  223. waterType() : label(LABEL_UNDEF) {}; /* needed to sort */
  224. waterType(dimension_type gi,
  225. dimension_type gj,
  226. direction_type gdir,
  227. cclabel_type glabel=LABEL_UNDEF,
  228. bfs_depth_type gdepth=DEPTH_INITIAL) :
  229. ijBaseType(gi, gj), dir(gdir), depth(gdepth), label(glabel) {
  230. }
  231. waterType(plateauType &data) :
  232. ijBaseType(data.i, data.j),
  233. dir(data.dir), depth(DEPTH_INITIAL), label(data.cclabel) {
  234. };
  235. direction_type getDirection() const { return dir; }
  236. bfs_depth_type getDepth() const { return depth; }
  237. cclabel_type getLabel() const { return label; }
  238. static char *printLabel(const waterType &p);
  239. friend ostream& operator << (ostream& s, const waterType &p) {
  240. return s << "[waterType" << (ijBaseType)p
  241. << ", dir=" << p.dir
  242. << ", bfs=" << p.depth
  243. << ", lab=" << p.label << "]";
  244. }
  245. };
  246. class ijCmpWaterType {
  247. public:
  248. static int compare(const waterType &a, const waterType &b) {
  249. return ijBaseType::compare(a, b);
  250. }
  251. };
  252. #if(0)
  253. class waterType2direction_type {
  254. public:
  255. direction_type operator()(waterType p) { return p.getDirection(); }
  256. direction_type operator()(direction_type p) { return p; }
  257. };
  258. #endif
  259. /* ---------------------------------------------------------------------- */
  260. class waterGridType : public waterWindowBaseType {
  261. protected:
  262. cclabel_type label;
  263. public:
  264. waterGridType() : label(LABEL_UNDEF) {};
  265. waterGridType(elevation_type gel,
  266. direction_type gdir=DIRECTION_UNDEF,
  267. cclabel_type glabel=LABEL_UNDEF,
  268. bfs_depth_type gdepth=DEPTH_INITIAL) :
  269. waterWindowBaseType(gel, gdir, gdepth), label(glabel) {
  270. }
  271. waterGridType(elevation_type gel, waterType w) :
  272. waterWindowBaseType(gel, w.dir, w.depth), label(w.label) {}
  273. cclabel_type getLabel() const { return label; };
  274. void setLabel(cclabel_type lbl) { label=lbl; };
  275. friend ostream& operator << (ostream& s, const waterGridType &p) {
  276. return s << directionSymbol(p.dir);
  277. }
  278. };
  279. /* ---------------------------------------------------------------------- */
  280. class packed8bit {
  281. protected:
  282. unsigned char value;
  283. public:
  284. packed8bit() : value(0) {};
  285. void setBit(int k, int v=1) { value = (int) value | ((v?1:0)<<k); };
  286. void resetBit(int k) { value &= ~(0x1<<k); };
  287. int getBit(int k) const { return (value >> k) & 1; };
  288. };
  289. static int linear(int i, int j) {
  290. assert(i>=-1 && i<=1 && j>=-1 && j<=1);
  291. return ((i+1)*3+(j+1));
  292. }
  293. static int norm(int k) {
  294. return (k<4 ? k : (k>4?k-1:8));
  295. }
  296. static int norm(int i, int j) {
  297. return norm(linear(i,j));
  298. }
  299. class compressedWaterWindowBaseType : public ijBaseType {
  300. protected: /* 4 */
  301. bfs_depth_type depth; /* 4 */
  302. elevation_type el[9]; /* 18 */
  303. direction_type dir; /* 2 */
  304. /* we only need the depth if the elevation is the same. if so, the
  305. variation is bounded by +/-1. if a cell receives a label from a
  306. lower elevation (ie the center is lower than the cell), then the
  307. recipients depth must be 1 (it's on the edge). if the center is
  308. higher, then we have no interest in the cell. */
  309. unsigned short depth_delta; /* 2 */
  310. packed8bit points; /* 1 whether neighbor points to me */
  311. /* cells are numbered 0,1,2/3,4,5/6,7,8 */
  312. /* bits are 0,1,2,3,5,6,7,8 (skip 4) */
  313. public:
  314. compressedWaterWindowBaseType() : depth(DEPTH_INITIAL),
  315. dir(0) {
  316. for(int i=0; i<9; i++) { el[i] = nodataType::ELEVATION_NODATA; }
  317. };
  318. compressedWaterWindowBaseType(dimension_type gi,
  319. dimension_type gj,
  320. waterWindowBaseType *a,
  321. waterWindowBaseType *b,
  322. waterWindowBaseType *c);
  323. fillPriority getPriority() const;
  324. elevation_type getElevation(int k=4) const { return el[k]; };
  325. elevation_type getElevation(int i,int j) const{return el[linear(i,j)];};
  326. direction_type getDirection() const { return dir; };
  327. int drainsFrom(int i, int j) const {
  328. /* whether we drain water from cell i,j */
  329. return points.getBit(norm(i, j));
  330. };
  331. bfs_depth_type getDepth() const { return depth; };
  332. bfs_depth_type getDepth(int k) const;
  333. bfs_depth_type getDepth(int i, int j) const { return getDepth(norm(i,j)); };
  334. void sanityCheck();
  335. friend ostream& operator<<(ostream& s,
  336. const compressedWaterWindowBaseType &p);
  337. private:
  338. int computeDelta(waterWindowBaseType *center,
  339. int index, waterWindowBaseType *p) const;
  340. };
  341. class compressedWaterWindowType : public compressedWaterWindowBaseType {
  342. protected:
  343. cclabel_type label;
  344. public:
  345. compressedWaterWindowType() : compressedWaterWindowBaseType(),
  346. label(LABEL_UNDEF) {};
  347. compressedWaterWindowType(dimension_type gi,
  348. dimension_type gj,
  349. cclabel_type glabel,
  350. waterWindowBaseType *a,
  351. waterWindowBaseType *b,
  352. waterWindowBaseType *c)
  353. : compressedWaterWindowBaseType(gi, gj, a, b, c),
  354. label(glabel) {
  355. /* if nodata, labels are either depression labels, or undefined or
  356. boundary (a pseudo depression). */
  357. assert(!(is_nodata(getElevation())) ||
  358. (label==LABEL_BOUNDARY || label==LABEL_UNDEF));
  359. }
  360. cclabel_type getLabel() const { return label; };
  361. void setLabel(cclabel_type lbl) { label=lbl; };
  362. labelElevType getCenter() const;
  363. void sanityCheck();
  364. friend ostream& operator<<(ostream& s, const compressedWaterWindowType &p);
  365. };
  366. typedef compressedWaterWindowType waterWindowType;
  367. class ijCmpWaterWindowType {
  368. public:
  369. static int compare(const waterWindowType &a, const waterWindowType &b) {
  370. return ijBaseType::compare(a, b);
  371. }
  372. };
  373. class priorityCmpWaterWindowType {
  374. public:
  375. static int compare(const waterWindowType &a, const waterWindowType &b) {
  376. return fillPriority::compare(a.getPriority(), b.getPriority());
  377. }
  378. };
  379. /* ********************************************************************** */
  380. void
  381. createWaterWindows(AMI_STREAM<waterGridType> *mergedWaterStr,
  382. const dimension_type nrows, const dimension_type ncols,
  383. AMI_STREAM<waterWindowType> *waterWindows);
  384. /* ********************************************************************** */
  385. void
  386. generateWatersheds(AMI_STREAM<waterWindowType> **waterWindows,
  387. const dimension_type nrows, const dimension_type ncols,
  388. AMI_STREAM<labelElevType> *labeledWater,
  389. AMI_STREAM<boundaryType> *boundaryStr);
  390. void
  391. findBoundaries(AMI_STREAM<labelElevType> *labeledWater,
  392. const dimension_type nrows, const dimension_type ncols,
  393. AMI_STREAM<boundaryType> *boundaryStr);
  394. /* ********************************************************************** */
  395. #endif