water.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  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 <iostream>
  20. using namespace std;
  21. #include <grass/iostream/ami.h>
  22. #include "3scan.h"
  23. #include "water.h"
  24. #include "streamutils.h"
  25. #include "sortutils.h"
  26. #define WATER_DEBUG if(0)
  27. #define XXX if(0)
  28. char *
  29. labelElevType::printLabel(const labelElevType &p) {
  30. static char buf[8];
  31. sprintf(buf, CCLABEL_FMT, p.label);
  32. return buf;
  33. }
  34. /* smaller elevation, depth is smaller priority */
  35. int
  36. fillPriority::compare(const fillPriority &a, const fillPriority &b) {
  37. if(a.el < b.el) return -1;
  38. if(a.el > b.el) return 1;
  39. if(a.depth < b.depth) return -1;
  40. if(a.depth > b.depth) return 1;
  41. if(a.i < b.i) return -1;
  42. if(a.i > b.i) return 1;
  43. if(a.j < b.j) return -1;
  44. if(a.j > b.j) return 1;
  45. return 0;
  46. }
  47. int
  48. fillPriority::qscompare(const void *a, const void *b) {
  49. fillPriority *x = (fillPriority*)a;
  50. fillPriority *y = (fillPriority*)b;
  51. return compare(*x, *y);
  52. }
  53. int
  54. operator<(const fillPriority &a, const fillPriority &b) {
  55. if(a.el < b.el) return 1;
  56. if(a.el > b.el) return 0;
  57. if(a.depth < b.depth) return 1;
  58. if(a.depth > b.depth) return 0;
  59. if(a.i < b.i) return 1;
  60. if(a.i > b.i) return 0;
  61. if(a.j < b.j) return 1;
  62. if(a.j > b.j) return 0;
  63. return 0;
  64. }
  65. int
  66. operator<=(const fillPriority &a, const fillPriority &b) {
  67. if(a.el < b.el) return 1;
  68. if(a.el > b.el) return 0;
  69. if(a.depth < b.depth) return 1;
  70. if(a.depth > b.depth) return 0;
  71. if(a.i < b.i) return 1;
  72. if(a.i > b.i) return 0;
  73. if(a.j < b.j) return 1;
  74. if(a.j > b.j) return 0;
  75. return 1;
  76. }
  77. int
  78. operator>(const fillPriority &a, const fillPriority &b) {
  79. if(a.el < b.el) return 0;
  80. if(a.el > b.el) return 1;
  81. if(a.depth < b.depth) return 0;
  82. if(a.depth > b.depth) return 1;
  83. if(a.i < b.i) return 0;
  84. if(a.i > b.i) return 1;
  85. if(a.j < b.j) return 0;
  86. if(a.j > b.j) return 1;
  87. return 0;
  88. }
  89. int
  90. operator==(const fillPriority &a, const fillPriority &b) {
  91. return (a.el == b.el)
  92. && (a.depth == b.depth)
  93. && (a.i == b.i)
  94. && (a.j == b.j);
  95. }
  96. int
  97. operator!=(const fillPriority &a, const fillPriority &b) {
  98. return (a.el != b.el)
  99. || (a.depth != b.depth)
  100. || (a.i != b.i)
  101. || (a.j != b.j);
  102. }
  103. ostream&
  104. operator << (ostream& s, const fillPriority &p) {
  105. return s << "[fillPriority el=" << p.el
  106. << ", d=" << p.depth << ", "
  107. << p.i << ","
  108. << p.j << "]";
  109. }
  110. /* ********************************************************************** */
  111. ostream&
  112. operator << (ostream& s, const labelElevType &p) {
  113. return s << (ijBaseType)p << " "
  114. << "el=" << p.el << ", "
  115. << p.label;
  116. }
  117. /* ********************************************************************** */
  118. char *
  119. waterType::printLabel(const waterType &p) {
  120. static char buf[8];
  121. sprintf(buf, CCLABEL_FMT, p.label);
  122. return buf;
  123. }
  124. /* ********************************************************************** */
  125. char *
  126. boundaryType::print(const boundaryType &p) {
  127. static char buf[4];
  128. if(p.isValid()) {
  129. buf[0] = '1';
  130. } else {
  131. buf[0] = '0';
  132. }
  133. buf[1] = '\0';
  134. return buf;
  135. }
  136. ostream&
  137. operator << (ostream& s, const boundaryType &p) {
  138. return s << "[boundaryType "
  139. << (labelElevType)p << ", "
  140. << p.label2 << "]";
  141. }
  142. /* ********************************************************************** */
  143. /* ********************************************************************** */
  144. class waterWindower {
  145. private:
  146. AMI_STREAM<waterWindowType> *waterWindows;
  147. public:
  148. waterWindower(AMI_STREAM<waterWindowType> *str) :
  149. waterWindows(str) {};
  150. void processWindow(dimension_type i, dimension_type j,
  151. waterGridType &point,
  152. waterWindowBaseType *a,
  153. waterWindowBaseType *b,
  154. waterWindowBaseType *c);
  155. };
  156. void
  157. waterWindower::processWindow(dimension_type i, dimension_type j,
  158. waterGridType &point,
  159. waterWindowBaseType *a,
  160. waterWindowBaseType *b,
  161. waterWindowBaseType *c) {
  162. waterWindowType win = waterWindowType(i, j, point.getLabel(), a, b, c);
  163. AMI_err ae = waterWindows->write_item(win);
  164. assert(ae == AMI_ERROR_NO_ERROR);
  165. }
  166. void
  167. createWaterWindows(AMI_STREAM<waterGridType> *mergedWaterStr,
  168. const dimension_type nrows, const dimension_type ncols,
  169. AMI_STREAM<waterWindowType> *waterWindows) {
  170. if (stats)
  171. stats->comment("creating windows", opt->verbose);
  172. waterWindower winfo(waterWindows);
  173. waterWindowBaseType nodata;
  174. assert(mergedWaterStr->stream_len() > 0);
  175. if (stats)
  176. stats->comment("warning: using slower scan", opt->verbose);
  177. scan3(*mergedWaterStr, nrows, ncols, nodata, winfo);
  178. }
  179. /* ********************************************************************** */
  180. /* ********************************************************************** */
  181. /*
  182. * push labels to upslope neighbors
  183. */
  184. void
  185. generateWatersheds(AMI_STREAM<waterWindowType> **waterWindows,
  186. const dimension_type nrows, const dimension_type ncols,
  187. AMI_STREAM<labelElevType> *labeledWater,
  188. AMI_STREAM<boundaryType> *boundaryStr) {
  189. AMI_err ae;
  190. waterWindowType *winp, prevWin;
  191. assert(prevWin.getDepth() == DEPTH_INITIAL);
  192. EMPQueueAdaptive<fillPLabel, fillPriority> *pq;
  193. if (stats)
  194. stats->comment("generateWatersheds", opt->verbose);
  195. assert((*waterWindows)->stream_len() == (nrows * ncols));
  196. WATER_DEBUG cout << "sort waterWindowsStream (by priority): ";
  197. sort(waterWindows, priorityCmpWaterWindowType());
  198. pq = new EMPQueueAdaptive<fillPLabel, fillPriority>();
  199. /* if(GETOPT("alwaysUseExternalPQ")) { */
  200. /* pq->makeExternal(); */
  201. /* } */
  202. /* if(GETOPT("useDebugPQ")) { */
  203. /* pq->makeExternalDebug(); */
  204. /* } */
  205. if (stats)
  206. stats->comment("starting generate watersheds main loop", opt->verbose);
  207. assert((*waterWindows)->stream_len() == (nrows * ncols));
  208. /* not really in a grid, so row, col are not valid (but count correct) */
  209. for(dimension_type row=0; row<nrows; row++) {
  210. for(dimension_type col=0; col<ncols; col++) {
  211. ae = (*waterWindows)->read_item(&winp);
  212. assert(ae == AMI_ERROR_NO_ERROR);
  213. /* make sure it's sorted; prevWin default constructor should be ok */
  214. assert(winp->getPriority() > prevWin.getPriority());
  215. prevWin = *winp;
  216. XXX winp->sanityCheck();
  217. /* cout << "--- PROC: " << *winp << endl; */
  218. /* get my label(s) */
  219. fillPLabel plabel; /* from the PQ */
  220. fillPriority prio;
  221. cclabel_type label = winp->getLabel();
  222. #ifndef NDEBUG
  223. {
  224. /* check to see if things are coming out of the pq in
  225. order. just peek at the next one */
  226. fillPLabel tmp;
  227. XXX winp->sanityCheck();
  228. pq->min(tmp);
  229. /* XXX pq->verify(); */
  230. XXX winp->sanityCheck();
  231. assert(pq->is_empty() || winp->getPriority() <= tmp.getPriority());
  232. }
  233. #endif
  234. while(pq->min(plabel) &&
  235. ((prio=plabel.getPriority()) == winp->getPriority())) {
  236. /* XXX pq->verify(); */
  237. XXX winp->sanityCheck();
  238. pq->extract_min(plabel);
  239. /* XXX pq->verify(); */
  240. XXX winp->sanityCheck();
  241. if(label == LABEL_UNDEF) label = plabel.getLabel();
  242. }
  243. /* no label! assign a new one */
  244. if((label==LABEL_UNDEF) && (!is_nodata(winp->getElevation()))) {
  245. #ifndef NDEBUG
  246. {
  247. /* check to see if things are coming out of the pq in
  248. order. just peek at the next one */
  249. fillPLabel tmp;
  250. XXX winp->sanityCheck();
  251. pq->min(tmp);
  252. /* XXX pq->verify(); */
  253. XXX winp->sanityCheck();
  254. assert(pq->is_empty() || winp->getPriority() <= tmp.getPriority());
  255. }
  256. #endif
  257. if(IS_BOUNDARY(winp->i,winp->j,nrows, ncols)) { /* edge of grid */
  258. assert(!is_nodata(winp->getElevation()));
  259. label = LABEL_BOUNDARY; /* reserved for watersheds draining
  260. out of grid */
  261. } else {
  262. label = labelFactory::getNewLabel();
  263. }
  264. }
  265. winp->setLabel(label);
  266. /* push label to 'upslope' neighbors. let's assume that the
  267. * edges cause no problems, since they have no directions... */
  268. if(label != LABEL_UNDEF) {
  269. int k=0;
  270. for(int i=-1; i<2; i++) {
  271. for(int j=-1; j<2; j++) {
  272. assert(k==linear(i,j));
  273. if(!is_nodata(winp->getElevation(k))
  274. && winp->drainsFrom(i,j)) { /* points to me */
  275. assert(i || j);
  276. prio = fillPriority(winp->getElevation(k),
  277. winp->getDepth(k),
  278. winp->i + i, winp->j + j);
  279. #ifndef NDEBUG
  280. /* dont insert if preceeds us */
  281. if(winp->getPriority() < prio) {
  282. fillPLabel plabel(prio, label);
  283. pq->insert(plabel);
  284. } else { /* trying to send a label backward */
  285. cerr << "WARNING: time travel attempted" << endl;
  286. cerr << "inst priority is " << prio << endl;
  287. cerr << "source is " << *winp << "; prio="
  288. << winp->getPriority() << endl;
  289. assert(0);
  290. }
  291. #else
  292. fillPLabel plabel(prio, label);
  293. pq->insert(plabel);
  294. #endif
  295. }
  296. k++;
  297. }
  298. }
  299. }
  300. /* write myself to output */
  301. ae = labeledWater->write_item(winp->getCenter());
  302. assert(ae == AMI_ERROR_NO_ERROR);
  303. }
  304. }
  305. assert(pq->is_empty());
  306. delete pq;
  307. if (stats)
  308. stats->comment("done with generate watersheds", opt->verbose);
  309. }
  310. /* ********************************************************************** */
  311. class boundaryDetector {
  312. private:
  313. const dimension_type nrows, ncols;
  314. AMI_STREAM<boundaryType> *boundaryStr;
  315. void processPair(labelElevType &pt,
  316. dimension_type i, dimension_type j, labelElevType &n);
  317. public:
  318. boundaryDetector(AMI_STREAM<boundaryType> *str,
  319. const dimension_type gnrows, const dimension_type gncols)
  320. : nrows(gnrows), ncols(gncols), boundaryStr(str) {};
  321. void processWindow(dimension_type i, dimension_type j,
  322. labelElevType &point,
  323. labelElevType *a,
  324. labelElevType *b,
  325. labelElevType *c);
  326. };
  327. template<class T>
  328. T mymax(T a, T b) {
  329. return (a>b?a:b);
  330. }
  331. void
  332. boundaryDetector::processPair(labelElevType &pt,
  333. dimension_type i, dimension_type j,
  334. labelElevType &n) {
  335. if(n.getLabel() != LABEL_UNDEF && pt.getLabel() != n.getLabel()) {
  336. boundaryType bt(pt, mymax(pt.getElevation(), n.getElevation()),
  337. n.getLabel());
  338. AMI_err ae = boundaryStr->write_item(bt);
  339. assert(ae == AMI_ERROR_NO_ERROR);
  340. } else if(IS_BOUNDARY(i,j,nrows, ncols) && pt.getLabel() != LABEL_BOUNDARY) {
  341. /* this part makes sure that regions on the grid edge
  342. are considered 'boundary' */
  343. boundaryType bt(pt, LABEL_BOUNDARY);
  344. AMI_err ae = boundaryStr->write_item(bt);
  345. assert(ae == AMI_ERROR_NO_ERROR);
  346. }
  347. }
  348. void
  349. boundaryDetector::processWindow(dimension_type i, dimension_type j,
  350. labelElevType &point,
  351. labelElevType *a,
  352. labelElevType *b,
  353. labelElevType *c) {
  354. if(point.getLabel() == LABEL_UNDEF) return;
  355. /* NODATA_FIX */
  356. /* don't use the nodata as the boundary. */
  357. /* if(point.getLabel() == LABEL_NODATA) return; */
  358. assert(point.getLabel() != LABEL_NODATA);
  359. for(int k=0; k<3; k++) {
  360. processPair(point, i, j, a[k]);
  361. processPair(point, i, j, b[k]);
  362. processPair(point, i, j, c[k]);
  363. }
  364. /* processPair(point, i, j, b[0]); */
  365. }
  366. /* ********************************************************************** */
  367. void
  368. findBoundaries(AMI_STREAM<labelElevType> *labeledWater,
  369. const dimension_type nrows, const dimension_type ncols,
  370. AMI_STREAM<boundaryType> *boundaryStr) {
  371. if (stats)
  372. stats->comment("creating windows", opt->verbose);
  373. boundaryDetector det(boundaryStr, nrows, ncols);
  374. /* cerr << "WARNING: using scan3 instead of scan2" << endl; */
  375. scan3(*labeledWater, nrows, ncols, labelElevType(), det);
  376. /* NODATA_FIX
  377. assert(LABEL_BOUNDARY < LABEL_NODATA);
  378. boundaryType bt(-1, -1, ELEVATION_MIN, LABEL_BOUNDARY, LABEL_NODATA);
  379. AMI_err ae = boundaryStr->write_item(bt);
  380. assert(ae == AMI_ERROR_NO_ERROR);
  381. */
  382. }
  383. /* ********************************************************************** */
  384. int
  385. compressedWaterWindowBaseType::computeDelta(waterWindowBaseType *center,
  386. int index,
  387. waterWindowBaseType *p) const{
  388. if(center->el != p->el) {
  389. assert(p->depth == 1 || center->el > p->el);
  390. return 0;
  391. }
  392. if(index > 7) return 0; /* we store our depth elsewhere */
  393. int d = p->depth - center->depth + 1;
  394. assert(d >= 0);
  395. #ifndef NDEBUG
  396. if(d>2) {
  397. cerr << "whoops - assertion failure" << endl;
  398. cerr << "center = " << *center << endl;
  399. cerr << "p = " << *p << endl;
  400. cerr << "this = " << *this << endl;
  401. }
  402. #endif
  403. assert(d <= 2);
  404. return d<<(2*index);
  405. }
  406. compressedWaterWindowBaseType::compressedWaterWindowBaseType(dimension_type gi,
  407. dimension_type gj,
  408. waterWindowBaseType *a,
  409. waterWindowBaseType *b,
  410. waterWindowBaseType *c)
  411. : ijBaseType(gi, gj) {
  412. for(int i=0; i<3; i++) {
  413. el[i] = a[i].el;
  414. el[i+3] = b[i].el;
  415. el[i+6] = c[i].el;
  416. }
  417. for(int i=0; i<3; i++) {
  418. const direction_type mask_a[] = {2, 4, 8};
  419. const direction_type mask_b[] = {1, 0, 16};
  420. const direction_type mask_c[] = {128, 64, 32};
  421. points.setBit(i, a[i].dir & mask_a[i]);
  422. points.setBit(norm(i+3), b[i].dir & mask_b[i]);
  423. points.setBit(i+5, c[i].dir & mask_c[i]);
  424. }
  425. dir = b[1].dir;
  426. depth = b[1].depth;
  427. depth_delta = 0;
  428. /* nodata is not processed. */
  429. if(is_nodata(b[1].el)) {
  430. return;
  431. }
  432. for(int i=0; i<3; i++) {
  433. depth_delta |= computeDelta(b+1, norm(-1,i-1), a+i);
  434. depth_delta |= computeDelta(b+1, norm(0,i-1), b+i);
  435. depth_delta |= computeDelta(b+1, norm(1,i-1), c+i);
  436. }
  437. }
  438. fillPriority
  439. compressedWaterWindowBaseType::getPriority() const {
  440. return fillPriority(getElevation(), getDepth(), i, j);
  441. }
  442. bfs_depth_type
  443. compressedWaterWindowBaseType::getDepth(int k) const {
  444. if(getElevation() != getElevation(k)) return DEPTH_INITIAL;
  445. return depth + ((depth_delta >> (norm(k)*2)) & 0x3) - 1;
  446. }
  447. void
  448. compressedWaterWindowBaseType::sanityCheck() {
  449. assert(i >= -1);
  450. assert(j >= -1);
  451. assert(depth >= DEPTH_INITIAL);
  452. }
  453. ostream&
  454. operator<<(ostream& s, const compressedWaterWindowBaseType &p) {
  455. return s << "[compressedWaterWindowBaseType "
  456. << p.i << "," << p.j
  457. << " " << directionSymbol(p.getDirection())
  458. << " e=" << p.getElevation()
  459. << " d =" << p.getDepth() << "]";
  460. }
  461. /* ********************************************************************** */
  462. labelElevType
  463. compressedWaterWindowType::getCenter() const {
  464. return labelElevType(i, j, getElevation(), label);
  465. }
  466. void
  467. compressedWaterWindowType::sanityCheck() {
  468. assert(label >= LABEL_UNDEF);
  469. compressedWaterWindowBaseType::sanityCheck();
  470. }
  471. ostream&
  472. operator<<(ostream& s, const compressedWaterWindowType &p) {
  473. return s << "[compressedWaterWindowType "
  474. << p.i << "," << p.j
  475. << " " << directionSymbol(p.getDirection())
  476. << " e=" << p.getElevation()
  477. << " d=" << p.getDepth()
  478. << " l=" << p.label;
  479. }