water.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  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. stats->comment("creating windows", opt->verbose);
  171. waterWindower winfo(waterWindows);
  172. waterWindowBaseType nodata;
  173. assert(mergedWaterStr->stream_len() > 0);
  174. stats->comment("warning: using slower scan", opt->verbose);
  175. scan3(*mergedWaterStr, nrows, ncols, nodata, winfo);
  176. }
  177. /* ********************************************************************** */
  178. /* ********************************************************************** */
  179. /*
  180. * push labels to upslope neighbors
  181. */
  182. void
  183. generateWatersheds(AMI_STREAM<waterWindowType> **waterWindows,
  184. const dimension_type nrows, const dimension_type ncols,
  185. AMI_STREAM<labelElevType> *labeledWater,
  186. AMI_STREAM<boundaryType> *boundaryStr) {
  187. AMI_err ae;
  188. waterWindowType *winp, prevWin;
  189. assert(prevWin.getDepth() == DEPTH_INITIAL);
  190. EMPQueueAdaptive<fillPLabel, fillPriority> *pq;
  191. stats->comment("generateWatersheds", opt->verbose);
  192. assert((*waterWindows)->stream_len() == (nrows * ncols));
  193. WATER_DEBUG cout << "sort waterWindowsStream (by priority): ";
  194. sort(waterWindows, priorityCmpWaterWindowType());
  195. pq = new EMPQueueAdaptive<fillPLabel, fillPriority>();
  196. /* if(GETOPT("alwaysUseExternalPQ")) { */
  197. /* pq->makeExternal(); */
  198. /* } */
  199. /* if(GETOPT("useDebugPQ")) { */
  200. /* pq->makeExternalDebug(); */
  201. /* } */
  202. stats->comment("starting generate watersheds main loop", opt->verbose);
  203. assert((*waterWindows)->stream_len() == (nrows * ncols));
  204. /* not really in a grid, so row, col are not valid (but count correct) */
  205. for(dimension_type row=0; row<nrows; row++) {
  206. for(dimension_type col=0; col<ncols; col++) {
  207. ae = (*waterWindows)->read_item(&winp);
  208. assert(ae == AMI_ERROR_NO_ERROR);
  209. /* make sure it's sorted; prevWin default constructor should be ok */
  210. assert(winp->getPriority() > prevWin.getPriority());
  211. prevWin = *winp;
  212. XXX winp->sanityCheck();
  213. /* cout << "--- PROC: " << *winp << endl; */
  214. /* get my label(s) */
  215. fillPLabel plabel; /* from the PQ */
  216. fillPriority prio;
  217. cclabel_type label = winp->getLabel();
  218. #ifndef NDEBUG
  219. {
  220. /* check to see if things are coming out of the pq in
  221. order. just peek at the next one */
  222. fillPLabel tmp;
  223. XXX winp->sanityCheck();
  224. pq->min(tmp);
  225. /* XXX pq->verify(); */
  226. XXX winp->sanityCheck();
  227. assert(pq->is_empty() || winp->getPriority() <= tmp.getPriority());
  228. }
  229. #endif
  230. while(pq->min(plabel) &&
  231. ((prio=plabel.getPriority()) == winp->getPriority())) {
  232. /* XXX pq->verify(); */
  233. XXX winp->sanityCheck();
  234. pq->extract_min(plabel);
  235. /* XXX pq->verify(); */
  236. XXX winp->sanityCheck();
  237. if(label == LABEL_UNDEF) label = plabel.getLabel();
  238. }
  239. /* no label! assign a new one */
  240. if((label==LABEL_UNDEF) && (!is_nodata(winp->getElevation()))) {
  241. #ifndef NDEBUG
  242. {
  243. /* check to see if things are coming out of the pq in
  244. order. just peek at the next one */
  245. fillPLabel tmp;
  246. XXX winp->sanityCheck();
  247. pq->min(tmp);
  248. /* XXX pq->verify(); */
  249. XXX winp->sanityCheck();
  250. assert(pq->is_empty() || winp->getPriority() <= tmp.getPriority());
  251. }
  252. #endif
  253. if(IS_BOUNDARY(winp->i,winp->j,nrows, ncols)) { /* edge of grid */
  254. assert(!is_nodata(winp->getElevation()));
  255. label = LABEL_BOUNDARY; /* reserved for watersheds draining
  256. out of grid */
  257. } else {
  258. label = labelFactory::getNewLabel();
  259. }
  260. }
  261. winp->setLabel(label);
  262. /* push label to 'upslope' neighbors. let's assume that the
  263. * edges cause no problems, since they have no directions... */
  264. if(label != LABEL_UNDEF) {
  265. int k=0;
  266. for(int i=-1; i<2; i++) {
  267. for(int j=-1; j<2; j++) {
  268. assert(k==linear(i,j));
  269. if(!is_nodata(winp->getElevation(k))
  270. && winp->drainsFrom(i,j)) { /* points to me */
  271. assert(i || j);
  272. prio = fillPriority(winp->getElevation(k),
  273. winp->getDepth(k),
  274. winp->i + i, winp->j + j);
  275. #ifndef NDEBUG
  276. /* dont insert if preceeds us */
  277. if(winp->getPriority() < prio) {
  278. fillPLabel plabel(prio, label);
  279. pq->insert(plabel);
  280. } else { /* trying to send a label backward */
  281. cerr << "WARNING: time travel attempted" << endl;
  282. cerr << "inst priority is " << prio << endl;
  283. cerr << "source is " << *winp << "; prio="
  284. << winp->getPriority() << endl;
  285. assert(0);
  286. }
  287. #else
  288. fillPLabel plabel(prio, label);
  289. pq->insert(plabel);
  290. #endif
  291. }
  292. k++;
  293. }
  294. }
  295. }
  296. /* write myself to output */
  297. ae = labeledWater->write_item(winp->getCenter());
  298. assert(ae == AMI_ERROR_NO_ERROR);
  299. }
  300. }
  301. assert(pq->is_empty());
  302. delete pq;
  303. stats->comment("done with generate watersheds", opt->verbose);
  304. }
  305. /* ********************************************************************** */
  306. class boundaryDetector {
  307. private:
  308. const dimension_type nrows, ncols;
  309. AMI_STREAM<boundaryType> *boundaryStr;
  310. void processPair(labelElevType &pt,
  311. dimension_type i, dimension_type j, labelElevType &n);
  312. public:
  313. boundaryDetector(AMI_STREAM<boundaryType> *str,
  314. const dimension_type gnrows, const dimension_type gncols)
  315. : nrows(gnrows), ncols(gncols), boundaryStr(str) {};
  316. void processWindow(dimension_type i, dimension_type j,
  317. labelElevType &point,
  318. labelElevType *a,
  319. labelElevType *b,
  320. labelElevType *c);
  321. };
  322. template<class T>
  323. T mymax(T a, T b) {
  324. return (a>b?a:b);
  325. }
  326. void
  327. boundaryDetector::processPair(labelElevType &pt,
  328. dimension_type i, dimension_type j,
  329. labelElevType &n) {
  330. if(n.getLabel() != LABEL_UNDEF && pt.getLabel() != n.getLabel()) {
  331. boundaryType bt(pt, mymax(pt.getElevation(), n.getElevation()),
  332. n.getLabel());
  333. AMI_err ae = boundaryStr->write_item(bt);
  334. assert(ae == AMI_ERROR_NO_ERROR);
  335. } else if(IS_BOUNDARY(i,j,nrows, ncols) && pt.getLabel() != LABEL_BOUNDARY) {
  336. /* this part makes sure that regions on the grid edge
  337. are considered 'boundary' */
  338. boundaryType bt(pt, LABEL_BOUNDARY);
  339. AMI_err ae = boundaryStr->write_item(bt);
  340. assert(ae == AMI_ERROR_NO_ERROR);
  341. }
  342. }
  343. void
  344. boundaryDetector::processWindow(dimension_type i, dimension_type j,
  345. labelElevType &point,
  346. labelElevType *a,
  347. labelElevType *b,
  348. labelElevType *c) {
  349. if(point.getLabel() == LABEL_UNDEF) return;
  350. /* NODATA_FIX */
  351. /* don't use the nodata as the boundary. */
  352. /* if(point.getLabel() == LABEL_NODATA) return; */
  353. assert(point.getLabel() != LABEL_NODATA);
  354. for(int k=0; k<3; k++) {
  355. processPair(point, i, j, a[k]);
  356. processPair(point, i, j, b[k]);
  357. processPair(point, i, j, c[k]);
  358. }
  359. /* processPair(point, i, j, b[0]); */
  360. }
  361. /* ********************************************************************** */
  362. void
  363. findBoundaries(AMI_STREAM<labelElevType> *labeledWater,
  364. const dimension_type nrows, const dimension_type ncols,
  365. AMI_STREAM<boundaryType> *boundaryStr) {
  366. stats->comment("creating windows", opt->verbose);
  367. boundaryDetector det(boundaryStr, nrows, ncols);
  368. /* cerr << "WARNING: using scan3 instead of scan2" << endl; */
  369. scan3(*labeledWater, nrows, ncols, labelElevType(), det);
  370. /* NODATA_FIX
  371. assert(LABEL_BOUNDARY < LABEL_NODATA);
  372. boundaryType bt(-1, -1, ELEVATION_MIN, LABEL_BOUNDARY, LABEL_NODATA);
  373. AMI_err ae = boundaryStr->write_item(bt);
  374. assert(ae == AMI_ERROR_NO_ERROR);
  375. */
  376. }
  377. /* ********************************************************************** */
  378. int
  379. compressedWaterWindowBaseType::computeDelta(waterWindowBaseType *center,
  380. int index,
  381. waterWindowBaseType *p) const{
  382. if(center->el != p->el) {
  383. assert(p->depth == 1 || center->el > p->el);
  384. return 0;
  385. }
  386. if(index > 7) return 0; /* we store our depth elsewhere */
  387. int d = p->depth - center->depth + 1;
  388. assert(d >= 0);
  389. #ifndef NDEBUG
  390. if(d>2) {
  391. cerr << "whoops - assertion failure" << endl;
  392. cerr << "center = " << *center << endl;
  393. cerr << "p = " << *p << endl;
  394. cerr << "this = " << *this << endl;
  395. }
  396. #endif
  397. assert(d <= 2);
  398. return d<<(2*index);
  399. }
  400. compressedWaterWindowBaseType::compressedWaterWindowBaseType(dimension_type gi,
  401. dimension_type gj,
  402. waterWindowBaseType *a,
  403. waterWindowBaseType *b,
  404. waterWindowBaseType *c)
  405. : ijBaseType(gi, gj) {
  406. for(int i=0; i<3; i++) {
  407. el[i] = a[i].el;
  408. el[i+3] = b[i].el;
  409. el[i+6] = c[i].el;
  410. }
  411. for(int i=0; i<3; i++) {
  412. const direction_type mask_a[] = {2, 4, 8};
  413. const direction_type mask_b[] = {1, 0, 16};
  414. const direction_type mask_c[] = {128, 64, 32};
  415. points.setBit(i, a[i].dir & mask_a[i]);
  416. points.setBit(norm(i+3), b[i].dir & mask_b[i]);
  417. points.setBit(i+5, c[i].dir & mask_c[i]);
  418. }
  419. dir = b[1].dir;
  420. depth = b[1].depth;
  421. depth_delta = 0;
  422. /* nodata is not processed. */
  423. if(is_nodata(b[1].el)) {
  424. return;
  425. }
  426. for(int i=0; i<3; i++) {
  427. depth_delta |= computeDelta(b+1, norm(-1,i-1), a+i);
  428. depth_delta |= computeDelta(b+1, norm(0,i-1), b+i);
  429. depth_delta |= computeDelta(b+1, norm(1,i-1), c+i);
  430. }
  431. }
  432. fillPriority
  433. compressedWaterWindowBaseType::getPriority() const {
  434. return fillPriority(getElevation(), getDepth(), i, j);
  435. }
  436. bfs_depth_type
  437. compressedWaterWindowBaseType::getDepth(int k) const {
  438. if(getElevation() != getElevation(k)) return DEPTH_INITIAL;
  439. return depth + ((depth_delta >> (norm(k)*2)) & 0x3) - 1;
  440. }
  441. void
  442. compressedWaterWindowBaseType::sanityCheck() {
  443. assert(i >= -1);
  444. assert(j >= -1);
  445. assert(depth >= DEPTH_INITIAL);
  446. }
  447. ostream&
  448. operator<<(ostream& s, const compressedWaterWindowBaseType &p) {
  449. return s << "[compressedWaterWindowBaseType "
  450. << p.i << "," << p.j
  451. << " " << directionSymbol(p.getDirection())
  452. << " e=" << p.getElevation()
  453. << " d =" << p.getDepth() << "]";
  454. }
  455. /* ********************************************************************** */
  456. labelElevType
  457. compressedWaterWindowType::getCenter() const {
  458. return labelElevType(i, j, getElevation(), label);
  459. }
  460. void
  461. compressedWaterWindowType::sanityCheck() {
  462. assert(label >= LABEL_UNDEF);
  463. compressedWaterWindowBaseType::sanityCheck();
  464. }
  465. ostream&
  466. operator<<(ostream& s, const compressedWaterWindowType &p) {
  467. return s << "[compressedWaterWindowType "
  468. << p.i << "," << p.j
  469. << " " << directionSymbol(p.getDirection())
  470. << " e=" << p.getElevation()
  471. << " d=" << p.getDepth()
  472. << " l=" << p.label;
  473. }