water.cpp 15 KB

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