streams.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714
  1. #include <stdlib.h>
  2. #include <math.h>
  3. #include <grass/raster.h>
  4. #include <grass/glocale.h>
  5. #include "local_proto.h"
  6. double mfd_pow(double base)
  7. {
  8. int i;
  9. double result = base;
  10. for (i = 2; i <= c_fac; i++) {
  11. result *= base;
  12. }
  13. return result;
  14. }
  15. static int continue_stream(CELL stream_id, int r_max, int c_max,
  16. int *stream_no)
  17. {
  18. CELL curr_stream, stream_nbr, old_stream;
  19. int r_nbr, c_nbr;
  20. int asp_r[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 };
  21. int asp_c[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 };
  22. int stream_node_step = 1000;
  23. ASP_FLAG af;
  24. G_debug(3, "continue stream");
  25. cseg_get(&stream, &curr_stream, r_max, c_max);
  26. if (curr_stream <= 0) {
  27. /* no confluence, just continue */
  28. G_debug(3, "no confluence, just continue stream");
  29. curr_stream = stream_id;
  30. cseg_put(&stream, &curr_stream, r_max, c_max);
  31. seg_get(&aspflag, (char *)&af, r_max, c_max);
  32. FLAG_SET(af.flag, STREAMFLAG);
  33. seg_put(&aspflag, (char *)&af, r_max, c_max);
  34. return 0;
  35. }
  36. G_debug(3, "confluence");
  37. /* new confluence */
  38. if (stream_node[curr_stream].r != r_max ||
  39. stream_node[curr_stream].c != c_max) {
  40. size_t new_size;
  41. G_debug(3, "new confluence");
  42. /* set new stream id */
  43. (*stream_no)++;
  44. /* add stream node */
  45. if (*stream_no >= n_alloc_nodes - 1) {
  46. n_alloc_nodes += stream_node_step;
  47. stream_node =
  48. (struct snode *)G_realloc(stream_node,
  49. n_alloc_nodes *
  50. sizeof(struct snode));
  51. }
  52. stream_node[*stream_no].r = r_max;
  53. stream_node[*stream_no].c = c_max;
  54. stream_node[*stream_no].id = *stream_no;
  55. stream_node[*stream_no].n_trib = 0;
  56. stream_node[*stream_no].n_trib_total = 0;
  57. stream_node[*stream_no].n_alloc = 0;
  58. stream_node[*stream_no].trib = NULL;
  59. n_stream_nodes++;
  60. /* debug */
  61. if (n_stream_nodes != *stream_no)
  62. G_warning(_("Stream_no %d and n_stream_nodes %lld out of sync"),
  63. *stream_no, n_stream_nodes);
  64. stream_node[*stream_no].n_alloc += 2;
  65. new_size = stream_node[*stream_no].n_alloc * sizeof(int);
  66. stream_node[*stream_no].trib =
  67. (int *)G_realloc(stream_node[*stream_no].trib, new_size);
  68. /* add the two tributaries */
  69. G_debug(3, "add tributaries");
  70. stream_node[*stream_no].trib[stream_node[*stream_no].n_trib++] =
  71. curr_stream;
  72. stream_node[*stream_no].trib[stream_node[*stream_no].n_trib++] =
  73. stream_id;
  74. /* update stream IDs downstream */
  75. G_debug(3, "update stream IDs downstream");
  76. r_nbr = r_max;
  77. c_nbr = c_max;
  78. old_stream = curr_stream;
  79. curr_stream = *stream_no;
  80. cseg_put(&stream, &curr_stream, r_nbr, c_nbr);
  81. seg_get(&aspflag, (char *)&af, r_nbr, c_nbr);
  82. while (af.asp > 0) {
  83. r_nbr = r_nbr + asp_r[(int)af.asp];
  84. c_nbr = c_nbr + asp_c[(int)af.asp];
  85. cseg_get(&stream, &stream_nbr, r_nbr, c_nbr);
  86. if (stream_nbr != old_stream)
  87. af.asp = -1;
  88. else {
  89. cseg_put(&stream, &curr_stream, r_nbr, c_nbr);
  90. seg_get(&aspflag, (char *)&af, r_nbr, c_nbr);
  91. }
  92. }
  93. }
  94. else {
  95. /* stream node already existing here */
  96. G_debug(3, "existing confluence");
  97. /* add new tributary to stream node */
  98. if (stream_node[curr_stream].n_trib >=
  99. stream_node[curr_stream].n_alloc) {
  100. size_t new_size;
  101. stream_node[curr_stream].n_alloc += 2;
  102. new_size = stream_node[curr_stream].n_alloc * sizeof(int);
  103. stream_node[curr_stream].trib =
  104. (int *)G_realloc(stream_node[curr_stream].trib, new_size);
  105. }
  106. stream_node[curr_stream].trib[stream_node[curr_stream].n_trib++] =
  107. stream_id;
  108. }
  109. G_debug(3, "%d tribs", stream_node[curr_stream].n_trib);
  110. if (stream_node[curr_stream].n_trib == 1)
  111. G_warning(_("BUG: stream node %d has only 1 tributary: %d"), curr_stream,
  112. stream_node[curr_stream].trib[0]);
  113. return 1;
  114. }
  115. /*
  116. * accumulate surface flow
  117. */
  118. int do_accum(double d8cut)
  119. {
  120. int r, c, dr, dc;
  121. CELL ele_val, *ele_nbr;
  122. DCELL value, *wat_nbr;
  123. struct Cell_head window;
  124. int mfd_cells, astar_not_set;
  125. double *dist_to_nbr, *weight, sum_weight, max_weight;
  126. double dx, dy;
  127. int r_nbr, c_nbr, ct_dir, np_side;
  128. int is_worked;
  129. double prop;
  130. int edge;
  131. int asp_r[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 };
  132. int asp_c[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 };
  133. int nextdr[8] = { 1, -1, 0, 0, -1, 1, 1, -1 };
  134. int nextdc[8] = { 0, 0, -1, 1, 1, -1, 1, -1 };
  135. GW_LARGE_INT workedon, killer;
  136. char *flag_nbr;
  137. POINT astarpoint;
  138. WAT_ALT wa;
  139. ASP_FLAG af, af_nbr;
  140. G_message(_("Calculating flow accumulation..."));
  141. /* distances to neighbours */
  142. dist_to_nbr = (double *)G_malloc(sides * sizeof(double));
  143. weight = (double *)G_malloc(sides * sizeof(double));
  144. flag_nbr = (char *)G_malloc(sides * sizeof(char));
  145. wat_nbr = (DCELL *)G_malloc(sides * sizeof(DCELL));
  146. ele_nbr = (CELL *)G_malloc(sides * sizeof(CELL));
  147. G_get_set_window(&window);
  148. for (ct_dir = 0; ct_dir < sides; ct_dir++) {
  149. /* get r, c (r_nbr, c_nbr) for neighbours */
  150. r_nbr = nextdr[ct_dir];
  151. c_nbr = nextdc[ct_dir];
  152. /* account for rare cases when ns_res != ew_res */
  153. dy = abs(r_nbr) * window.ns_res;
  154. dx = abs(c_nbr) * window.ew_res;
  155. if (ct_dir < 4)
  156. dist_to_nbr[ct_dir] = dx + dy;
  157. else
  158. dist_to_nbr[ct_dir] = sqrt(dx * dx + dy * dy);
  159. }
  160. /* distribute and accumulate */
  161. for (killer = 0; killer < n_points; killer++) {
  162. G_percent(killer, n_points, 1);
  163. seg_get(&astar_pts, (char *)&astarpoint, 0, killer);
  164. r = astarpoint.r;
  165. c = astarpoint.c;
  166. seg_get(&aspflag, (char *)&af, r, c);
  167. /* do not distribute flow along edges or out of real depressions */
  168. if (af.asp <= 0) {
  169. FLAG_UNSET(af.flag, WORKEDFLAG);
  170. seg_put(&aspflag, (char *)&af, r, c);
  171. continue;
  172. }
  173. if (af.asp) {
  174. dr = r + asp_r[abs((int)af.asp)];
  175. dc = c + asp_c[abs((int)af.asp)];
  176. }
  177. seg_get(&watalt, (char *)&wa, r, c);
  178. value = wa.wat;
  179. /* WORKEDFLAG has been set during A* Search
  180. * reversed meaning here: 0 = done, 1 = not yet done */
  181. FLAG_UNSET(af.flag, WORKEDFLAG);
  182. seg_put(&aspflag, (char *)&af, r, c);
  183. /***************************************/
  184. /* get weights for flow distribution */
  185. /***************************************/
  186. max_weight = 0;
  187. sum_weight = 0;
  188. np_side = -1;
  189. mfd_cells = 0;
  190. astar_not_set = 1;
  191. ele_val = wa.ele;
  192. edge = 0;
  193. /* this loop is needed to get the sum of weights */
  194. for (ct_dir = 0; ct_dir < sides; ct_dir++) {
  195. /* get r_nbr, c_nbr for neighbours */
  196. r_nbr = r + nextdr[ct_dir];
  197. c_nbr = c + nextdc[ct_dir];
  198. weight[ct_dir] = -1;
  199. wat_nbr[ct_dir] = 0;
  200. ele_nbr[ct_dir] = 0;
  201. /* check that neighbour is within region */
  202. if (r_nbr >= 0 && r_nbr < nrows && c_nbr >= 0 && c_nbr < ncols) {
  203. seg_get(&aspflag, (char *)&af_nbr, r_nbr, c_nbr);
  204. flag_nbr[ct_dir] = af_nbr.flag;
  205. if ((edge = FLAG_GET(flag_nbr[ct_dir], NULLFLAG)))
  206. break;
  207. seg_get(&watalt, (char *)&wa, r_nbr, c_nbr);
  208. wat_nbr[ct_dir] = wa.wat;
  209. ele_nbr[ct_dir] = wa.ele;
  210. /* WORKEDFLAG has been set during A* Search
  211. * reversed meaning here: 0 = done, 1 = not yet done */
  212. is_worked = FLAG_GET(flag_nbr[ct_dir], WORKEDFLAG) == 0;
  213. if (is_worked == 0) {
  214. if (ele_nbr[ct_dir] <= ele_val) {
  215. if (ele_nbr[ct_dir] < ele_val) {
  216. weight[ct_dir] =
  217. mfd_pow((ele_val -
  218. ele_nbr[ct_dir]) / dist_to_nbr[ct_dir]);
  219. }
  220. if (ele_nbr[ct_dir] == ele_val) {
  221. weight[ct_dir] =
  222. mfd_pow(0.5 / dist_to_nbr[ct_dir]);
  223. }
  224. sum_weight += weight[ct_dir];
  225. mfd_cells++;
  226. if (weight[ct_dir] > max_weight) {
  227. max_weight = weight[ct_dir];
  228. }
  229. if (dr == r_nbr && dc == c_nbr) {
  230. astar_not_set = 0;
  231. }
  232. }
  233. }
  234. if (dr == r_nbr && dc == c_nbr)
  235. np_side = ct_dir;
  236. }
  237. else
  238. edge = 1;
  239. if (edge)
  240. break;
  241. }
  242. /* do not distribute flow along edges, this causes artifacts */
  243. if (edge) {
  244. G_debug(3, "edge");
  245. continue;
  246. }
  247. /* honour A * path
  248. * mfd_cells == 0: fine, SFD along A * path
  249. * mfd_cells == 1 && astar_not_set == 0: fine, SFD along A * path
  250. * mfd_cells > 0 && astar_not_set == 1: A * path not included, add to mfd_cells
  251. */
  252. /************************************/
  253. /* distribute and accumulate flow */
  254. /************************************/
  255. /* MFD, A * path not included, add to mfd_cells */
  256. if (mfd_cells > 0 && astar_not_set == 1) {
  257. mfd_cells++;
  258. sum_weight += max_weight;
  259. weight[np_side] = max_weight;
  260. }
  261. /* use SFD (D8) if d8cut threshold exceeded */
  262. if (fabs(value) > d8cut)
  263. mfd_cells = 0;
  264. if (mfd_cells > 1) {
  265. prop = 0.0;
  266. for (ct_dir = 0; ct_dir < sides; ct_dir++) {
  267. /* get r, c (r_nbr, c_nbr) for neighbours */
  268. r_nbr = r + nextdr[ct_dir];
  269. c_nbr = c + nextdc[ct_dir];
  270. /* check that neighbour is within region */
  271. if (r_nbr >= 0 && r_nbr < nrows && c_nbr >= 0 &&
  272. c_nbr < ncols && weight[ct_dir] > -0.5) {
  273. is_worked = FLAG_GET(flag_nbr[ct_dir], WORKEDFLAG) == 0;
  274. if (is_worked == 0) {
  275. weight[ct_dir] = weight[ct_dir] / sum_weight;
  276. /* check everything sums up to 1.0 */
  277. prop += weight[ct_dir];
  278. wa.wat = wat_nbr[ct_dir] + value * weight[ct_dir];
  279. wa.ele = ele_nbr[ct_dir];
  280. seg_put(&watalt, (char *)&wa, r_nbr, c_nbr);
  281. }
  282. else if (ct_dir == np_side) {
  283. /* check for consistency with A * path */
  284. workedon++;
  285. }
  286. }
  287. }
  288. if (fabs(prop - 1.0) > 5E-6f) {
  289. G_warning(_("MFD: cumulative proportion of flow distribution not 1.0 but %f"),
  290. prop);
  291. }
  292. }
  293. /* get out of depression in SFD mode */
  294. else {
  295. wa.wat = wat_nbr[np_side] + value;
  296. wa.ele = ele_nbr[np_side];
  297. seg_put(&watalt, (char *)&wa, dr, dc);
  298. }
  299. }
  300. G_percent(1, 1, 2);
  301. G_free(dist_to_nbr);
  302. G_free(weight);
  303. G_free(wat_nbr);
  304. G_free(ele_nbr);
  305. G_free(flag_nbr);
  306. return 1;
  307. }
  308. /*
  309. * extracts streams for threshold, accumulation is provided
  310. */
  311. int extract_streams(double threshold, double mont_exp, int internal_acc)
  312. {
  313. int r, c, dr, dc;
  314. CELL is_swale, ele_val, *ele_nbr;
  315. DCELL value, valued, *wat_nbr;
  316. struct Cell_head window;
  317. int mfd_cells, stream_cells, swale_cells;
  318. double *dist_to_nbr;
  319. double dx, dy;
  320. int r_nbr, c_nbr, r_max, c_max, ct_dir, np_side, max_side;
  321. int is_worked;
  322. double max_acc;
  323. int edge, flat;
  324. int asp_r[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 };
  325. int asp_c[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 };
  326. int nextdr[8] = { 1, -1, 0, 0, -1, 1, 1, -1 };
  327. int nextdc[8] = { 0, 0, -1, 1, 1, -1, 1, -1 };
  328. /* sides */
  329. /*
  330. * | 7 | 1 | 4 |
  331. * | 2 | | 3 |
  332. * | 5 | 0 | 6 |
  333. */
  334. GW_LARGE_INT workedon, killer;
  335. int stream_no = 0, stream_node_step = 1000;
  336. double slope, diag;
  337. char *flag_nbr;
  338. POINT astarpoint;
  339. WAT_ALT wa;
  340. ASP_FLAG af, af_nbr;
  341. G_message(_("Extracting streams..."));
  342. /* init stream nodes */
  343. n_alloc_nodes = stream_node_step;
  344. stream_node =
  345. (struct snode *)G_malloc(n_alloc_nodes * sizeof(struct snode));
  346. n_stream_nodes = 0;
  347. /* init outlet nodes */
  348. n_alloc_outlets = stream_node_step;
  349. outlets =
  350. (POINT *)G_malloc(n_alloc_outlets * sizeof(POINT));
  351. n_outlets = 0;
  352. /* distances to neighbours */
  353. dist_to_nbr = (double *)G_malloc(sides * sizeof(double));
  354. flag_nbr = (char *)G_malloc(sides * sizeof(char));
  355. wat_nbr = (DCELL *)G_malloc(sides * sizeof(DCELL));
  356. ele_nbr = (CELL *)G_malloc(sides * sizeof(CELL));
  357. G_get_set_window(&window);
  358. for (ct_dir = 0; ct_dir < sides; ct_dir++) {
  359. /* get r, c (r_nbr, c_nbr) for neighbours */
  360. r_nbr = nextdr[ct_dir];
  361. c_nbr = nextdc[ct_dir];
  362. /* account for rare cases when ns_res != ew_res */
  363. dy = abs(r_nbr) * window.ns_res;
  364. dx = abs(c_nbr) * window.ew_res;
  365. if (ct_dir < 4)
  366. dist_to_nbr[ct_dir] = dx + dy;
  367. else
  368. dist_to_nbr[ct_dir] = sqrt(dx * dx + dy * dy);
  369. }
  370. diag = sqrt(2);
  371. workedon = 0;
  372. /* extract streams */
  373. for (killer = 0; killer < n_points; killer++) {
  374. G_percent(killer, n_points, 1);
  375. seg_get(&astar_pts, (char *)&astarpoint, 0, killer);
  376. r = astarpoint.r;
  377. c = astarpoint.c;
  378. seg_get(&aspflag, (char *)&af, r, c);
  379. /* internal acc: SET, external acc: UNSET */
  380. if (internal_acc)
  381. FLAG_SET(af.flag, WORKEDFLAG);
  382. else
  383. FLAG_UNSET(af.flag, WORKEDFLAG);
  384. seg_put(&aspflag, (char *)&af, r, c);
  385. /* do not distribute flow along edges */
  386. if (af.asp <= 0) {
  387. G_debug(3, "edge");
  388. is_swale = FLAG_GET(af.flag, STREAMFLAG);
  389. if (is_swale) {
  390. G_debug(2, "edge outlet");
  391. /* add outlet point */
  392. if (n_outlets >= n_alloc_outlets) {
  393. n_alloc_outlets += stream_node_step;
  394. outlets =
  395. (POINT *)G_realloc(outlets,
  396. n_alloc_outlets *
  397. sizeof(POINT));
  398. }
  399. outlets[n_outlets].r = r;
  400. outlets[n_outlets].c = c;
  401. n_outlets++;
  402. }
  403. if (af.asp == 0) {
  404. /* can only happen with real depressions */
  405. if (!have_depressions)
  406. G_fatal_error(_("Bug in stream extraction"));
  407. G_debug(2, "bottom of real depression");
  408. }
  409. continue;
  410. }
  411. if (af.asp) {
  412. dr = r + asp_r[abs((int)af.asp)];
  413. dc = c + asp_c[abs((int)af.asp)];
  414. }
  415. else {
  416. /* can only happen with real depressions,
  417. * but should not get to here */
  418. dr = r;
  419. dc = c;
  420. }
  421. r_nbr = r_max = dr;
  422. c_nbr = c_max = dc;
  423. seg_get(&watalt, (char *)&wa, r, c);
  424. value = wa.wat;
  425. /**********************************/
  426. /* find main drainage direction */
  427. /**********************************/
  428. max_acc = -1;
  429. max_side = np_side = -1;
  430. mfd_cells = 0;
  431. stream_cells = 0;
  432. swale_cells = 0;
  433. ele_val = wa.ele;
  434. edge = 0;
  435. flat = 1;
  436. /* find main drainage direction */
  437. for (ct_dir = 0; ct_dir < sides; ct_dir++) {
  438. /* get r_nbr, c_nbr for neighbours */
  439. r_nbr = r + nextdr[ct_dir];
  440. c_nbr = c + nextdc[ct_dir];
  441. wat_nbr[ct_dir] = 0;
  442. ele_nbr[ct_dir] = 0;
  443. flag_nbr[ct_dir] = 0;
  444. /* check that neighbour is within region */
  445. if (r_nbr >= 0 && r_nbr < nrows && c_nbr >= 0 && c_nbr < ncols) {
  446. if (dr == r_nbr && dc == c_nbr)
  447. np_side = ct_dir;
  448. seg_get(&aspflag, (char *)&af_nbr, r_nbr, c_nbr);
  449. flag_nbr[ct_dir] = af_nbr.flag;
  450. if ((edge = FLAG_GET(flag_nbr[ct_dir], NULLFLAG)))
  451. break;
  452. seg_get(&watalt, (char *)&wa, r_nbr, c_nbr);
  453. wat_nbr[ct_dir] = wa.wat;
  454. ele_nbr[ct_dir] = wa.ele;
  455. /* check for swale cells */
  456. is_swale = FLAG_GET(flag_nbr[ct_dir], STREAMFLAG);
  457. if (is_swale)
  458. swale_cells++;
  459. /* check for stream cells */
  460. valued = fabs(wat_nbr[ct_dir]);
  461. /* check all upstream neighbours */
  462. if (valued >= threshold && ct_dir != np_side &&
  463. ele_nbr[ct_dir] > ele_val)
  464. stream_cells++;
  465. is_worked = FLAG_GET(flag_nbr[ct_dir], WORKEDFLAG);
  466. if (!internal_acc)
  467. is_worked = is_worked == 0;
  468. if (is_worked == 0) {
  469. if (ele_nbr[ct_dir] != ele_val)
  470. flat = 0;
  471. if (ele_nbr[ct_dir] <= ele_val) {
  472. mfd_cells++;
  473. /* set main drainage direction */
  474. if (valued >= max_acc) {
  475. max_acc = valued;
  476. r_max = r_nbr;
  477. c_max = c_nbr;
  478. max_side = ct_dir;
  479. }
  480. }
  481. }
  482. else if (ct_dir == np_side && !edge) {
  483. /* check for consistency with A * path */
  484. workedon++;
  485. }
  486. }
  487. else
  488. edge = 1;
  489. if (edge)
  490. break;
  491. }
  492. is_swale = FLAG_GET(af.flag, STREAMFLAG);
  493. /* do not continue streams along edges, these are artifacts */
  494. if (edge) {
  495. G_debug(3, "edge");
  496. if (is_swale) {
  497. G_debug(2, "edge outlet");
  498. /* add outlet point */
  499. if (n_outlets >= n_alloc_outlets) {
  500. n_alloc_outlets += stream_node_step;
  501. outlets =
  502. (POINT *)G_realloc(outlets,
  503. n_alloc_outlets *
  504. sizeof(POINT));
  505. }
  506. outlets[n_outlets].r = r;
  507. outlets[n_outlets].c = c;
  508. n_outlets++;
  509. if (af.asp > 0) {
  510. af.asp = -1 * drain[r - r_nbr + 1][c - c_nbr + 1];
  511. seg_put(&aspflag, (char *)&af, r, c);
  512. }
  513. }
  514. continue;
  515. }
  516. if (np_side < 0)
  517. G_fatal_error("np_side < 0");
  518. /* set main drainage direction to A* path if possible */
  519. if (mfd_cells > 0 && max_side != np_side) {
  520. if (fabs(wat_nbr[np_side] >= max_acc)) {
  521. max_acc = fabs(wat_nbr[np_side]);
  522. r_max = dr;
  523. c_max = dc;
  524. max_side = np_side;
  525. }
  526. }
  527. if (mfd_cells == 0) {
  528. flat = 0;
  529. r_max = dr;
  530. c_max = dc;
  531. max_side = np_side;
  532. }
  533. /* update aspect */
  534. /* r_max == r && c_max == c should not happen */
  535. if ((r_max != dr || c_max != dc) && (r_max != r || c_max != c)) {
  536. af.asp = drain[r - r_max + 1][c - c_max + 1];
  537. seg_put(&aspflag, (char *)&af, r, c);
  538. }
  539. /**********************/
  540. /* start new stream */
  541. /**********************/
  542. /* Montgomery's stream initiation acc * (tan(slope))^mont_exp */
  543. /* uses whatever unit is accumulation */
  544. if (mont_exp > 0) {
  545. if (r_max == r && c_max == c)
  546. G_warning
  547. (_("Can't use Montgomery's method, no stream direction found"));
  548. else {
  549. slope = (double)(ele_val - ele_nbr[max_side]) / ele_scale;
  550. if (max_side > 3)
  551. slope /= diag;
  552. value *= pow(fabs(slope), mont_exp);
  553. }
  554. }
  555. if (!is_swale && fabs(value) >= threshold && stream_cells < 1 &&
  556. swale_cells < 1 && !flat) {
  557. G_debug(2, "start new stream");
  558. is_swale = ++stream_no;
  559. cseg_put(&stream, &is_swale, r, c);
  560. FLAG_SET(af.flag, STREAMFLAG);
  561. seg_put(&aspflag, (char *)&af, r, c);
  562. /* add stream node */
  563. if (stream_no >= n_alloc_nodes - 1) {
  564. n_alloc_nodes += stream_node_step;
  565. stream_node =
  566. (struct snode *)G_realloc(stream_node,
  567. n_alloc_nodes *
  568. sizeof(struct snode));
  569. }
  570. stream_node[stream_no].r = r;
  571. stream_node[stream_no].c = c;
  572. stream_node[stream_no].id = stream_no;
  573. stream_node[stream_no].n_trib = 0;
  574. stream_node[stream_no].n_trib_total = 0;
  575. stream_node[stream_no].n_alloc = 0;
  576. stream_node[stream_no].trib = NULL;
  577. n_stream_nodes++;
  578. /* debug */
  579. if (n_stream_nodes != stream_no)
  580. G_warning(_("Stream_no %d and n_stream_nodes %lld out of sync"),
  581. stream_no, n_stream_nodes);
  582. }
  583. /*********************/
  584. /* continue stream */
  585. /*********************/
  586. if (is_swale > 0) {
  587. cseg_get(&stream, &is_swale, r, c);
  588. if (r_max == r && c_max == c) {
  589. /* can't continue stream, add outlet point
  590. * r_max == r && c_max == c should not happen */
  591. G_debug(1, "can't continue stream at r %d c %d", r, c);
  592. if (n_outlets >= n_alloc_outlets) {
  593. n_alloc_outlets += stream_node_step;
  594. outlets =
  595. (POINT *)G_malloc(n_alloc_outlets *
  596. sizeof(POINT));
  597. }
  598. outlets[n_outlets].r = r;
  599. outlets[n_outlets].c = c;
  600. n_outlets++;
  601. }
  602. else {
  603. continue_stream(is_swale, r_max, c_max, &stream_no);
  604. }
  605. }
  606. }
  607. G_percent(1, 1, 2);
  608. if (workedon)
  609. G_warning(_("MFD: A * path already processed when setting drainage direction: %lld of %lld cells"),
  610. workedon, n_points);
  611. G_free(dist_to_nbr);
  612. G_free(wat_nbr);
  613. G_free(ele_nbr);
  614. G_free(flag_nbr);
  615. G_debug(1, "%lld outlets", n_outlets);
  616. G_debug(1, "%lld nodes", n_stream_nodes);
  617. G_debug(1, "%d streams", stream_no);
  618. return 1;
  619. }