stream_topology.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. #include "local_proto.h"
  2. double get_distance(int r, int c, int d)
  3. {
  4. double northing, easting, next_northing, next_easting;
  5. int next_r, next_c;
  6. next_r = NR(d);
  7. next_c = NC(d);
  8. northing = window.north - (r + .5) * window.ns_res;
  9. easting = window.west + (c + .5) * window.ew_res;
  10. next_northing = window.north - (next_r + .5) * window.ns_res;
  11. next_easting = window.west + (next_c + .5) * window.ew_res;
  12. return G_distance(easting, northing, next_easting, next_northing);
  13. }
  14. int ram_trib_nums(int r, int c, CELL ** streams, CELL ** dirs)
  15. { /* calculate number of tributaries */
  16. int trib_num = 0;
  17. int i, j;
  18. int next_r, next_c;
  19. for (i = 1; i < 9; ++i) {
  20. if (NOT_IN_REGION(i))
  21. continue;
  22. j = DIAG(i);
  23. next_r = NR(i);
  24. next_c = NC(i);
  25. if (streams[next_r][next_c] > 0 && dirs[next_r][next_c] == j)
  26. trib_num++;
  27. }
  28. if (trib_num > 1)
  29. for (i = 1; i < 9; ++i) {
  30. if (NOT_IN_REGION(i))
  31. continue;
  32. j = DIAG(i);
  33. next_r = NR(i);
  34. next_c = NC(i);
  35. if (streams[next_r][next_c] == streams[r][c] &&
  36. dirs[next_r][next_c] == j)
  37. trib_num--;
  38. }
  39. if (trib_num > 5)
  40. G_fatal_error(_("Error finding inits. Stream and direction maps probably do not match"));
  41. if (trib_num > 3)
  42. G_warning(_("Stream network may be too dense"));
  43. return trib_num;
  44. } /* end trib_num */
  45. int seg_trib_nums(int r, int c, SEGMENT *streams, SEGMENT *dirs)
  46. { /* calculate number of tributaries */
  47. int trib_num = 0;
  48. int i, j;
  49. int next_r, next_c;
  50. int streams_cell, streams_next_cell, dirs_next_cell;
  51. Segment_get(streams, &streams_cell, r, c);
  52. for (i = 1; i < 9; ++i) {
  53. if (NOT_IN_REGION(i))
  54. continue;
  55. j = DIAG(i);
  56. next_r = NR(i);
  57. next_c = NC(i);
  58. Segment_get(streams, &streams_next_cell, next_r, next_c);
  59. Segment_get(dirs, &dirs_next_cell, next_r, next_c);
  60. if (streams_next_cell > 0 && dirs_next_cell == j)
  61. trib_num++;
  62. }
  63. if (trib_num > 1)
  64. for (i = 1; i < 9; ++i) {
  65. if (NOT_IN_REGION(i))
  66. continue;
  67. j = DIAG(i);
  68. next_r = NR(i);
  69. next_c = NC(i);
  70. Segment_get(streams, &streams_next_cell, next_r, next_c);
  71. Segment_get(dirs, &dirs_next_cell, next_r, next_c);
  72. if (streams_next_cell == streams_cell && dirs_next_cell == j)
  73. trib_num--;
  74. }
  75. if (trib_num > 5)
  76. G_fatal_error(_("Error finding inits. Stream and direction maps probably do not match"));
  77. if (trib_num > 3)
  78. G_warning(_("Stream network may be too dense"));
  79. return trib_num;
  80. } /* end trib_num */
  81. int ram_number_of_streams(CELL **streams, CELL **dirs, int *ordered)
  82. {
  83. int r, c;
  84. int stream_num = 0;
  85. int one = 0, two = 0;
  86. for (r = 0; r < nrows; ++r)
  87. for (c = 0; c < ncols; ++c)
  88. if (streams[r][c] > 0)
  89. if (ram_trib_nums(r, c, streams, dirs) != 1) {
  90. stream_num++;
  91. if (streams[r][c] == 1)
  92. one++;
  93. if (streams[r][c] == 2)
  94. two++;
  95. }
  96. *ordered = (one > 1 || two > 1) ? 1 : 0;
  97. /* if there is more than 1 stream with identifier 1 or 2 network is ordered */
  98. return stream_num;
  99. }
  100. int seg_number_of_streams(SEGMENT *streams, SEGMENT *dirs, int *ordered)
  101. {
  102. int r, c;
  103. int stream_num = 0;
  104. int one = 0, two = 0;
  105. int streams_cell;
  106. for (r = 0; r < nrows; ++r)
  107. for (c = 0; c < ncols; ++c) {
  108. Segment_get(streams, &streams_cell, r, c);
  109. if (streams_cell > 0)
  110. if (seg_trib_nums(r, c, streams, dirs) != 1) {
  111. stream_num++;
  112. if (streams_cell == 1)
  113. one++;
  114. if (streams_cell == 2)
  115. two++;
  116. }
  117. }
  118. *ordered = (one > 1 || two > 1) ? 1 : 0;
  119. /* if there is more than 1 stream with identifier 1 or 2 network is ordered */
  120. return stream_num;
  121. }
  122. int ram_build_streamlines(CELL **streams, CELL **dirs, FCELL **elevation,
  123. int number_of_streams)
  124. {
  125. int r, c, i;
  126. int d, next_d;
  127. int prev_r, prev_c;
  128. int stream_num = 1, cell_num = 0;
  129. int contrib_cell;
  130. STREAM *SA;
  131. int border_dir;
  132. stream_attributes =
  133. (STREAM *) G_malloc(number_of_streams * sizeof(STREAM));
  134. G_message(_("Finding inits..."));
  135. SA = stream_attributes;
  136. for (r = 0; r < nrows; ++r)
  137. for (c = 0; c < ncols; ++c)
  138. if (streams[r][c])
  139. if (ram_trib_nums(r, c, streams, dirs) != 1) { /* adding inits */
  140. if (stream_num > number_of_streams)
  141. G_fatal_error(_("Error finding inits. Stream and direction maps probably do not match"));
  142. SA[stream_num].stream = stream_num;
  143. SA[stream_num].init = INDEX(r, c);
  144. stream_num++;
  145. }
  146. for (i = 1; i < stream_num; ++i) {
  147. r = (int)SA[i].init / ncols;
  148. c = (int)SA[i].init % ncols;
  149. SA[i].order = streams[r][c];
  150. SA[i].number_of_cells = 0;
  151. do {
  152. SA[i].number_of_cells++;
  153. d = abs(dirs[r][c]);
  154. if (NOT_IN_REGION(d) || d == 0)
  155. break;
  156. r = NR(d);
  157. c = NC(d);
  158. } while (streams[r][c] == SA[i].order);
  159. SA[i].number_of_cells += 2; /* add two extra points for init+ and outlet+ */
  160. }
  161. for (i = 1; i < number_of_streams; ++i) {
  162. SA[i].points = (unsigned long int *)
  163. G_malloc((SA[i].number_of_cells) * sizeof(unsigned long int));
  164. SA[i].elevation = (float *)
  165. G_malloc((SA[i].number_of_cells) * sizeof(float));
  166. SA[i].distance = (double *)
  167. G_malloc((SA[i].number_of_cells) * sizeof(double));
  168. r = (int)SA[i].init / ncols;
  169. c = (int)SA[i].init % ncols;
  170. contrib_cell = ram_find_contributing_cell(r, c, dirs, elevation);
  171. prev_r = NR(contrib_cell);
  172. prev_c = NC(contrib_cell);
  173. /* add one point contributing to init to calculate parameters */
  174. /* what to do if there is no contributing points? */
  175. SA[i].points[0] = (contrib_cell == 0) ? -1 : INDEX(prev_r, prev_c);
  176. SA[i].elevation[0] = (contrib_cell == 0) ? -99999 :
  177. elevation[prev_r][prev_c];
  178. d = (contrib_cell == 0) ? dirs[r][c] : dirs[prev_r][prev_c];
  179. SA[i].distance[0] = (contrib_cell == 0) ? get_distance(r, c, d) :
  180. get_distance(prev_r, prev_c, d);
  181. SA[i].points[1] = INDEX(r, c);
  182. SA[i].elevation[1] = elevation[r][c];
  183. d = abs(dirs[r][c]);
  184. SA[i].distance[1] = get_distance(r, c, d);
  185. cell_num = 2;
  186. do {
  187. d = abs(dirs[r][c]);
  188. if (NOT_IN_REGION(d) || d == 0) {
  189. SA[i].points[cell_num] = -1;
  190. SA[i].distance[cell_num] = SA[i].distance[cell_num - 1];
  191. SA[i].elevation[cell_num] =
  192. 2 * SA[i].elevation[cell_num - 1] -
  193. SA[i].elevation[cell_num - 2];
  194. border_dir = convert_border_dir(r, c, dirs[r][c]);
  195. SA[i].last_cell_dir = border_dir;
  196. break;
  197. }
  198. r = NR(d);
  199. c = NC(d);
  200. SA[i].last_cell_dir = dirs[r][c];
  201. SA[i].points[cell_num] = INDEX(r, c);
  202. SA[i].elevation[cell_num] = elevation[r][c];
  203. next_d = (abs(dirs[r][c]) == 0) ? d : abs(dirs[r][c]);
  204. SA[i].distance[cell_num] = get_distance(r, c, next_d);
  205. cell_num++;
  206. if (cell_num > SA[i].number_of_cells)
  207. G_fatal_error(_("To many points in stream line"));
  208. } while (streams[r][c] == SA[i].order);
  209. if (SA[i].elevation[0] == -99999)
  210. SA[i].elevation[0] = 2 * SA[i].elevation[1] - SA[i].elevation[2];
  211. }
  212. return 0;
  213. }
  214. int seg_build_streamlines(SEGMENT *streams, SEGMENT *dirs,
  215. SEGMENT *elevation, int number_of_streams)
  216. {
  217. int r, c, i;
  218. int d, next_d;
  219. int prev_r, prev_c;
  220. int stream_num = 1, cell_num = 0;
  221. int contrib_cell;
  222. STREAM *SA;
  223. int border_dir;
  224. int streams_cell, dirs_cell;
  225. int dirs_prev_cell;
  226. float elevation_cell, elevation_prev_cell;
  227. stream_attributes =
  228. (STREAM *) G_malloc(number_of_streams * sizeof(STREAM));
  229. G_message(_("Finding inits..."));
  230. SA = stream_attributes;
  231. /* finding inits */
  232. for (r = 0; r < nrows; ++r)
  233. for (c = 0; c < ncols; ++c) {
  234. Segment_get(streams, &streams_cell, r, c);
  235. if (streams_cell)
  236. if (seg_trib_nums(r, c, streams, dirs) != 1) { /* adding inits */
  237. if (stream_num > number_of_streams)
  238. G_fatal_error(_("Error finding inits. Stream and direction maps probably do not match"));
  239. SA[stream_num].stream = stream_num;
  240. SA[stream_num].init = INDEX(r, c);
  241. stream_num++;
  242. }
  243. }
  244. /* building streamline */
  245. for (i = 1; i < stream_num; ++i) {
  246. r = (int)SA[i].init / ncols;
  247. c = (int)SA[i].init % ncols;
  248. Segment_get(streams, &streams_cell, r, c);
  249. SA[i].order = streams_cell;
  250. SA[i].number_of_cells = 0;
  251. do {
  252. SA[i].number_of_cells++;
  253. Segment_get(dirs, &dirs_cell, r, c);
  254. d = abs(dirs_cell);
  255. if (NOT_IN_REGION(d) || d == 0)
  256. break;
  257. r = NR(d);
  258. c = NC(d);
  259. Segment_get(streams, &streams_cell, r, c);
  260. } while (streams_cell == SA[i].order);
  261. SA[i].number_of_cells += 2; /* add two extra points for point before init and after outlet */
  262. }
  263. for (i = 1; i < number_of_streams; ++i) {
  264. SA[i].points = (unsigned long int *)
  265. G_malloc((SA[i].number_of_cells) * sizeof(unsigned long int));
  266. SA[i].elevation = (float *)
  267. G_malloc((SA[i].number_of_cells) * sizeof(float));
  268. SA[i].distance = (double *)
  269. G_malloc((SA[i].number_of_cells) * sizeof(double));
  270. r = (int)SA[i].init / ncols;
  271. c = (int)SA[i].init % ncols;
  272. contrib_cell = seg_find_contributing_cell(r, c, dirs, elevation);
  273. prev_r = NR(contrib_cell);
  274. prev_c = NC(contrib_cell);
  275. /* add one point contributing to init to calculate parameters */
  276. /* what to do if there is no contributing points? */
  277. Segment_get(dirs, &dirs_cell, r, c);
  278. Segment_get(dirs, &dirs_prev_cell, prev_r, prev_c);
  279. Segment_get(elevation, &elevation_prev_cell, prev_r, prev_c);
  280. Segment_get(elevation, &elevation_cell, r, c);
  281. SA[i].points[0] = (contrib_cell == 0) ? -1 : INDEX(prev_r, prev_c);
  282. SA[i].elevation[0] = (contrib_cell == 0) ? -99999 :
  283. elevation_prev_cell;
  284. d = (contrib_cell == 0) ? dirs_cell : dirs_prev_cell;
  285. SA[i].distance[0] = (contrib_cell == 0) ? get_distance(r, c, d) :
  286. get_distance(prev_r, prev_c, d);
  287. SA[i].points[1] = INDEX(r, c);
  288. SA[i].elevation[1] = elevation_cell;
  289. d = abs(dirs_cell);
  290. SA[i].distance[1] = get_distance(r, c, d);
  291. cell_num = 2;
  292. do {
  293. Segment_get(dirs, &dirs_cell, r, c);
  294. d = abs(dirs_cell);
  295. if (NOT_IN_REGION(d) || d == 0) {
  296. SA[i].points[cell_num] = -1;
  297. SA[i].distance[cell_num] = SA[i].distance[cell_num - 1];
  298. SA[i].elevation[cell_num] =
  299. 2 * SA[i].elevation[cell_num - 1] -
  300. SA[i].elevation[cell_num - 2];
  301. border_dir = convert_border_dir(r, c, dirs_cell);
  302. SA[i].last_cell_dir = border_dir;
  303. break;
  304. }
  305. r = NR(d);
  306. c = NC(d);
  307. Segment_get(dirs, &dirs_cell, r, c);
  308. SA[i].last_cell_dir = dirs_cell;
  309. SA[i].points[cell_num] = INDEX(r, c);
  310. Segment_get(elevation, &SA[i].elevation[cell_num], r, c);
  311. next_d = (abs(dirs_cell) == 0) ? d : abs(dirs_cell);
  312. SA[i].distance[cell_num] = get_distance(r, c, next_d);
  313. cell_num++;
  314. if (cell_num > SA[i].number_of_cells)
  315. G_fatal_error(_("To much points in stream line"));
  316. Segment_get(streams, &streams_cell, r, c);
  317. } while (streams_cell == SA[i].order);
  318. if (SA[i].elevation[0] == -99999)
  319. SA[i].elevation[0] = 2 * SA[i].elevation[1] - SA[i].elevation[2];
  320. }
  321. return 0;
  322. }
  323. int ram_find_contributing_cell(int r, int c, CELL **dirs, FCELL **elevation)
  324. {
  325. int i, j = 0;
  326. int next_r, next_c;
  327. float elev_min = 9999;
  328. for (i = 1; i < 9; ++i) {
  329. if (NOT_IN_REGION(i))
  330. continue;
  331. next_r = NR(i);
  332. next_c = NC(i);
  333. if (dirs[next_r][next_c] == DIAG(i) &&
  334. elevation[next_r][next_c] < elev_min) {
  335. elev_min = elevation[next_r][next_c];
  336. j = i;
  337. }
  338. }
  339. return j;
  340. }
  341. int seg_find_contributing_cell(int r, int c, SEGMENT *dirs,
  342. SEGMENT *elevation)
  343. {
  344. int i, j = 0;
  345. int next_r, next_c;
  346. float elev_min = 9999;
  347. int dirs_next_cell;
  348. float elevation_next_cell;
  349. for (i = 1; i < 9; ++i) {
  350. if (NOT_IN_REGION(i))
  351. continue;
  352. next_r = NR(i);
  353. next_c = NC(i);
  354. Segment_get(elevation, &elevation_next_cell, next_r, next_c);
  355. Segment_get(dirs, &dirs_next_cell, next_r, next_c);
  356. if (dirs_next_cell == DIAG(i) && elevation_next_cell < elev_min) {
  357. elev_min = elevation_next_cell;
  358. j = i;
  359. }
  360. }
  361. return j;
  362. }
  363. int ram_fill_streams(CELL **unique_streams, int number_of_streams)
  364. {
  365. int r, c;
  366. int i, j;
  367. STREAM *SA;
  368. SA = stream_attributes;
  369. for (i = 1; i < number_of_streams; ++i) {
  370. for (j = 1; j < SA[i].number_of_cells - 1; ++j) {
  371. r = (int)SA[i].points[j] / ncols;
  372. c = (int)SA[i].points[j] % ncols;
  373. unique_streams[r][c] = SA[i].stream;
  374. }
  375. }
  376. return 0;
  377. }
  378. int seg_fill_streams(SEGMENT *unique_streams, int number_of_streams)
  379. {
  380. int r, c;
  381. int i, j;
  382. STREAM *SA;
  383. SA = stream_attributes;
  384. for (i = 1; i < number_of_streams; ++i) {
  385. for (j = 1; j < SA[i].number_of_cells - 1; ++j) {
  386. r = (int)SA[i].points[j] / ncols;
  387. c = (int)SA[i].points[j] % ncols;
  388. Segment_put(unique_streams, &SA[i].stream, r, c);
  389. }
  390. }
  391. return 0;
  392. }
  393. int ram_identify_next_stream(CELL **streams, int number_of_streams)
  394. {
  395. int r, c;
  396. int i;
  397. STREAM *SA;
  398. SA = stream_attributes;
  399. for (i = 1; i < number_of_streams; ++i) {
  400. if (SA[i].points[SA[i].number_of_cells - 1] == -1) {
  401. SA[i].next_stream = -1;
  402. SA[i].outlet = -1;
  403. }
  404. else {
  405. r = (int)SA[i].points[SA[i].number_of_cells - 1] / ncols;
  406. c = (int)SA[i].points[SA[i].number_of_cells - 1] % ncols;
  407. SA[i].next_stream = streams[r][c];
  408. SA[i].outlet = SA[i].points[SA[i].number_of_cells - 1];
  409. }
  410. }
  411. return 0;
  412. }
  413. int seg_identify_next_stream(SEGMENT *streams, int number_of_streams)
  414. {
  415. int r, c;
  416. int i;
  417. STREAM *SA;
  418. SA = stream_attributes;
  419. for (i = 1; i < number_of_streams; ++i) {
  420. if (SA[i].points[SA[i].number_of_cells - 1] == -1) {
  421. SA[i].next_stream = -1;
  422. SA[i].outlet = -1;
  423. }
  424. else {
  425. r = (int)SA[i].points[SA[i].number_of_cells - 1] / ncols;
  426. c = (int)SA[i].points[SA[i].number_of_cells - 1] % ncols;
  427. Segment_get(streams, &SA[i].next_stream, r, c);
  428. SA[i].outlet = SA[i].points[SA[i].number_of_cells - 1];
  429. }
  430. }
  431. return 0;
  432. }
  433. int free_attributes(int number_of_streams)
  434. {
  435. int i;
  436. STREAM *SA;
  437. SA = stream_attributes;
  438. for (i = 1; i < number_of_streams; ++i) {
  439. G_free(SA[i].points);
  440. G_free(SA[i].elevation);
  441. G_free(SA[i].distance);
  442. G_free(SA[i].sector_breakpoints);
  443. G_free(SA[i].sector_cats);
  444. G_free(SA[i].sector_directions);
  445. G_free(SA[i].sector_lengths);
  446. G_free(SA[i].sector_drops);
  447. }
  448. G_free(stream_attributes);
  449. return 0;
  450. }
  451. int convert_border_dir(int r, int c, int dir)
  452. {
  453. /* this function must be added to other modules */
  454. /* this is added to fix r.stream.extract issue with broader cell direction */
  455. if (dir)
  456. return dir;
  457. if (r == 0 && c == 0)
  458. return -3;
  459. else if (r == 0 && c == ncols - 1)
  460. return -1;
  461. else if (r == nrows - 1 && c == ncols - 1)
  462. return -7;
  463. else if (r == nrows - 1 && c == 0)
  464. return -5;
  465. else if (r == 0)
  466. return -2;
  467. else if (r == nrows - 1)
  468. return -6;
  469. else if (c == 0)
  470. return -4;
  471. else if (c == ncols - 1)
  472. return -8;
  473. else
  474. return 0;
  475. }