main.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789
  1. /****************************************************************************
  2. *
  3. * MODULE: r.drain
  4. *
  5. * AUTHOR(S): Kewan Q. Khawaja <kewan techlogix.com>
  6. * Update to FP (2000): Pierre de Mouveaux <pmx@audiovu.com> <pmx@free.fr>
  7. * bugfix in FCELL, DCELL: Markus Neteler 12/2000
  8. * Rewritten by Roger Miller 7/2001 based on subroutines from
  9. * r.fill.dir and on the original r.drain.
  10. * 24 July 2004: WebValley 2004, error checking and vector points added by
  11. * Matteo Franchi Liceo Leonardo Da Vinci Trento
  12. * Roberto Flor ITC-irst
  13. * New code added by Colin Nielsen <colin.nielsen at gmail dot com> *
  14. * to use movement direction surface from r.walk and r.cost, and to
  15. * output vector paths 2/2009
  16. *
  17. * PURPOSE: This is the main program for tracing out the path that a
  18. * drop of water would take if released at a certain location
  19. * on an input elevation map.
  20. * COPYRIGHT: (C) 2000,2009 by the GRASS Development Team
  21. *
  22. * This program is free software under the GNU General Public
  23. * License (>=v2). Read the file COPYING that comes with GRASS
  24. * for details.
  25. *
  26. *****************************************************************************/
  27. #include <grass/config.h>
  28. #include <stdlib.h>
  29. #include <stdio.h>
  30. #include <string.h>
  31. #include <math.h>
  32. #include <float.h>
  33. /* for using the "open" statement */
  34. #include <sys/types.h>
  35. #include <sys/stat.h>
  36. #include <fcntl.h>
  37. /* for using the close statement */
  38. #include <unistd.h>
  39. #include <grass/gis.h>
  40. #include <grass/raster.h>
  41. #include <grass/glocale.h>
  42. #include <grass/vector.h>
  43. #define DEBUG
  44. #include "tinf.h"
  45. #include "local.h"
  46. /* should probably be updated to a pointer array & malloc/realloc as needed */
  47. #define POINTS_INCREMENT 1024
  48. /* define a data structure to hold the point data */
  49. struct point
  50. {
  51. int row;
  52. int col;
  53. struct point *next;
  54. double value;
  55. };
  56. int main(int argc, char **argv)
  57. {
  58. int fe, fd, dir_fd;
  59. int i, have_points = 0;
  60. int new_id;
  61. int nrows, ncols;
  62. int *points_row = NULL, *points_col = NULL, npoints;
  63. int increment_count;
  64. int cell_open(), cell_open_new();
  65. int map_id, dir_id;
  66. char map_name[GNAME_MAX], new_map_name[GNAME_MAX], dir_name[GNAME_MAX];
  67. char *tempfile1, *tempfile2, *tempfile3;
  68. struct History history;
  69. struct Cell_head window;
  70. struct Option *opt1, *opt2, *coordopt, *vpointopt, *opt3, *opt4;
  71. struct Flag *flag1, *flag2, *flag3, *flag4;
  72. struct GModule *module;
  73. int in_type;
  74. void *in_buf;
  75. void *dir_buf;
  76. CELL *out_buf;
  77. struct band3 bnd, bndC;
  78. struct metrics *m = NULL;
  79. struct point *list;
  80. struct point *thispoint;
  81. int ival, start_row, start_col, mode;
  82. off_t bsz;
  83. int costmode = 0;
  84. double east, north, val;
  85. struct point *drain(int, struct point *, int, int);
  86. struct point *drain_cost(int, struct point *, int, int);
  87. int bsort(int, struct point *);
  88. struct line_pnts *Points;
  89. struct line_cats *Cats;
  90. struct Map_info vout;
  91. int cat;
  92. double x, y;
  93. G_gisinit(argv[0]);
  94. module = G_define_module();
  95. G_add_keyword(_("raster"));
  96. G_add_keyword(_("hydrology"));
  97. G_add_keyword(_("cost surface"));
  98. module->description =
  99. _("Traces a flow through an elevation model or cost surface on a raster map.");
  100. opt1 = G_define_standard_option(G_OPT_R_INPUT);
  101. opt1->description = _("Name of input elevation or cost surface raster map");
  102. opt3 = G_define_standard_option(G_OPT_R_INPUT);
  103. opt3->key = "direction";
  104. opt3->description =
  105. _("Name of input movement direction map associated with the cost surface");
  106. opt3->required = NO;
  107. opt3->guisection = _("Cost surface");
  108. opt2 = G_define_standard_option(G_OPT_R_OUTPUT);
  109. opt4 = G_define_standard_option(G_OPT_V_OUTPUT);
  110. opt4->key = "drain";
  111. opt4->required = NO;
  112. opt4->label =
  113. _("Name for output drain vector map");
  114. opt4->description = _("Recommended for cost surface made using knight's move");
  115. coordopt = G_define_standard_option(G_OPT_M_COORDS);
  116. coordopt->key = "start_coordinates";
  117. coordopt->description = _("Coordinates of starting point(s) (E,N)");
  118. coordopt->guisection = _("Start");
  119. vpointopt = G_define_standard_option(G_OPT_V_INPUTS);
  120. vpointopt->key = "start_points";
  121. vpointopt->required = NO;
  122. vpointopt->label = _("Name of starting vector points map(s)");
  123. vpointopt->description = NULL;
  124. vpointopt->guisection = _("Start");
  125. flag1 = G_define_flag();
  126. flag1->key = 'c';
  127. flag1->description = _("Copy input cell values on output");
  128. flag2 = G_define_flag();
  129. flag2->key = 'a';
  130. flag2->description = _("Accumulate input values along the path");
  131. flag2->guisection = _("Path settings");
  132. flag3 = G_define_flag();
  133. flag3->key = 'n';
  134. flag3->description = _("Count cell numbers along the path");
  135. flag3->guisection = _("Path settings");
  136. flag4 = G_define_flag();
  137. flag4->key = 'd';
  138. flag4->description =
  139. _("The input raster map is a cost surface (direction surface must also be specified)");
  140. flag4->guisection = _("Cost surface");
  141. if (G_parser(argc, argv))
  142. exit(EXIT_FAILURE);
  143. strcpy(map_name, opt1->answer);
  144. strcpy(new_map_name, opt2->answer);
  145. if (flag4->answer) {
  146. costmode = 1;
  147. G_verbose_message(_("Directional drain selected... checking for direction raster map"));
  148. }
  149. else {
  150. G_verbose_message(_("Surface/Hydrology drain selected"));
  151. }
  152. if (costmode == 1) {
  153. if (!opt3->answer) {
  154. G_fatal_error(_("Direction raster map <%s> not specified, if direction flag is on, "
  155. "a direction raster must be given"), opt3->key);
  156. }
  157. strcpy(dir_name, opt3->answer);
  158. }
  159. if (costmode == 0) {
  160. if (opt3->answer) {
  161. G_fatal_error(_("Direction raster map <%s> should not be specified for Surface/Hydrology drains"),
  162. opt3->answer);
  163. }
  164. }
  165. if (opt4->answer) {
  166. if (0 > Vect_open_new(&vout, opt4->answer, 0)) {
  167. G_fatal_error(_("Unable to create vector map <%s>"),
  168. opt4->answer);
  169. }
  170. Vect_hist_command(&vout);
  171. }
  172. /* allocate cell buf for the map layer */
  173. in_type = Rast_map_type(map_name, "");
  174. /* set the pointers for multi-typed functions */
  175. set_func_pointers(in_type);
  176. if ((flag1->answer + flag2->answer + flag3->answer) > 1)
  177. G_fatal_error(_("Specify just one of the -c, -a and -n flags"));
  178. mode = 0;
  179. if (flag1->answer)
  180. mode = 1;
  181. if (flag2->answer)
  182. mode = 2;
  183. if (flag3->answer)
  184. mode = 3;
  185. /* get the window information */
  186. G_get_window(&window);
  187. nrows = Rast_window_rows();
  188. ncols = Rast_window_cols();
  189. /* calculate true cell resolution */
  190. m = (struct metrics *)G_malloc(nrows * sizeof(struct metrics));
  191. points_row = (int*)G_calloc(POINTS_INCREMENT, sizeof(int));
  192. points_col = (int*)G_calloc(POINTS_INCREMENT, sizeof(int));
  193. increment_count = 1;
  194. npoints = 0;
  195. if (coordopt->answer) {
  196. for (i = 0; coordopt->answers[i] != NULL; i += 2) {
  197. G_scan_easting(coordopt->answers[i], &east, G_projection());
  198. G_scan_northing(coordopt->answers[i + 1], &north, G_projection());
  199. start_col = (int)Rast_easting_to_col(east, &window);
  200. start_row = (int)Rast_northing_to_row(north, &window);
  201. if (start_row < 0 || start_row > nrows ||
  202. start_col < 0 || start_col > ncols) {
  203. G_warning(_("Starting point %d is outside the current region"),
  204. i + 1);
  205. continue;
  206. }
  207. points_row[npoints] = start_row;
  208. points_col[npoints] = start_col;
  209. npoints++;
  210. if (npoints == POINTS_INCREMENT * increment_count)
  211. {
  212. increment_count++;
  213. points_row = (int*)G_realloc(points_row, POINTS_INCREMENT * increment_count * sizeof(int));
  214. points_col = (int*)G_realloc(points_col, POINTS_INCREMENT * increment_count * sizeof(int));
  215. }
  216. have_points = 1;
  217. }
  218. }
  219. if (vpointopt->answers) {
  220. for (i = 0; vpointopt->answers[i] != NULL; i++) {
  221. struct Map_info In;
  222. struct bound_box box;
  223. int type;
  224. Points = Vect_new_line_struct();
  225. Cats = Vect_new_cats_struct();
  226. Vect_set_open_level(1); /* topology not required */
  227. if (1 > Vect_open_old(&In, vpointopt->answers[i], ""))
  228. G_fatal_error(_("Unable to open vector map <%s>"), vpointopt->answers[i]);
  229. G_message(_("Reading vector map <%s> with start points..."),
  230. Vect_get_full_name(&In));
  231. Vect_rewind(&In);
  232. Vect_region_box(&window, &box);
  233. while (1) {
  234. /* register line */
  235. type = Vect_read_next_line(&In, Points, Cats);
  236. /* Note: check for dead lines is not needed, because they are skipped by V1_read_next_line_nat() */
  237. if (type == -1) {
  238. G_warning(_("Unable to read vector map"));
  239. continue;
  240. }
  241. else if (type == -2) {
  242. break;
  243. }
  244. if (!Vect_point_in_box(Points->x[0], Points->y[0], 0, &box))
  245. continue;
  246. start_col = (int)Rast_easting_to_col(Points->x[0], &window);
  247. start_row = (int)Rast_northing_to_row(Points->y[0], &window);
  248. /* effectively just a duplicate check to G_site_in_region() ??? */
  249. if (start_row < 0 || start_row > nrows || start_col < 0 ||
  250. start_col > ncols)
  251. continue;
  252. points_row[npoints] = start_row;
  253. points_col[npoints] = start_col;
  254. npoints++;
  255. if (npoints == POINTS_INCREMENT * increment_count)
  256. {
  257. increment_count++;
  258. points_row = (int*)G_realloc(points_row, POINTS_INCREMENT * increment_count * sizeof(int));
  259. points_col = (int*)G_realloc(points_col, POINTS_INCREMENT * increment_count * sizeof(int));
  260. }
  261. have_points = 1;
  262. }
  263. Vect_close(&In);
  264. /* only catches maps out of range until something is found, not after */
  265. if (!have_points) {
  266. G_warning(_("Starting vector map <%s> contains no points in the current region"),
  267. vpointopt->answers[i]);
  268. }
  269. Vect_destroy_line_struct(Points);
  270. Vect_destroy_cats_struct(Cats);
  271. }
  272. }
  273. if (have_points == 0)
  274. G_fatal_error(_("No start/stop point(s) specified"));
  275. /* determine the drainage paths */
  276. /* allocate storage for the first point */
  277. thispoint = (struct point *)G_malloc(sizeof(struct point));
  278. list = thispoint;
  279. thispoint->next = NULL;
  280. G_begin_distance_calculations();
  281. {
  282. double e1, n1, e2, n2;
  283. e1 = window.east;
  284. n1 = window.north;
  285. e2 = e1 + window.ew_res;
  286. n2 = n1 - window.ns_res;
  287. for (i = 0; i < nrows; i++) {
  288. m[i].ew_res = G_distance(e1, n1, e2, n1);
  289. m[i].ns_res = G_distance(e1, n1, e1, n2);
  290. m[i].diag_res = G_distance(e1, n1, e2, n2);
  291. e2 = e1 + window.ew_res;
  292. n2 = n1 - window.ns_res;
  293. }
  294. }
  295. /* buffers for internal use */
  296. bndC.ns = ncols;
  297. bndC.sz = sizeof(CELL) * ncols;
  298. bndC.b[0] = G_calloc(ncols, sizeof(CELL));
  299. bndC.b[1] = G_calloc(ncols, sizeof(CELL));
  300. bndC.b[2] = G_calloc(ncols, sizeof(CELL));
  301. /* buffers for external use */
  302. bnd.ns = ncols;
  303. bnd.sz = ncols * bpe();
  304. bnd.b[0] = G_calloc(ncols, bpe());
  305. bnd.b[1] = G_calloc(ncols, bpe());
  306. bnd.b[2] = G_calloc(ncols, bpe());
  307. /* an input buffer */
  308. in_buf = get_buf();
  309. /* open the original map and get its file id */
  310. map_id = Rast_open_old(map_name, "");
  311. /* get some temp files */
  312. tempfile1 = G_tempfile();
  313. tempfile2 = G_tempfile();
  314. fe = open(tempfile1, O_RDWR | O_CREAT, 0666);
  315. fd = open(tempfile2, O_RDWR | O_CREAT, 0666);
  316. /* transfer the input map to a temp file */
  317. for (i = 0; i < nrows; i++) {
  318. get_row(map_id, in_buf, i);
  319. write(fe, in_buf, bnd.sz);
  320. }
  321. Rast_close(map_id);
  322. if (costmode == 1) {
  323. dir_buf = Rast_allocate_d_buf();
  324. dir_id = Rast_open_old(dir_name, "");
  325. tempfile3 = G_tempfile();
  326. dir_fd = open(tempfile3, O_RDWR | O_CREAT, 0666);
  327. for (i = 0; i < nrows; i++) {
  328. Rast_get_d_row(dir_id, dir_buf, i);
  329. write(dir_fd, dir_buf, ncols * sizeof(DCELL));
  330. }
  331. Rast_close(dir_id);
  332. }
  333. /* only necessary for non-dir drain */
  334. if (costmode == 0) {
  335. G_message(_("Calculating flow directions..."));
  336. /* fill one-cell pits and take a first stab at flow directions */
  337. filldir(fe, fd, nrows, &bnd, m);
  338. /* determine flow directions for more ambiguous cases */
  339. resolve(fd, nrows, &bndC);
  340. }
  341. /* free the buffers already used */
  342. G_free(bndC.b[0]);
  343. G_free(bndC.b[1]);
  344. G_free(bndC.b[2]);
  345. G_free(bnd.b[0]);
  346. G_free(bnd.b[1]);
  347. G_free(bnd.b[2]);
  348. /* determine the drainage paths */
  349. /* repeat for each starting point */
  350. for (i = 0; i < npoints; i++) {
  351. /* use the flow directions to determine the drainage path
  352. * results are compiled as a linked list of points in downstream order */
  353. thispoint->row = points_row[i];
  354. thispoint->col = points_col[i];
  355. thispoint->next = NULL;
  356. /* drain algorithm selection (dir or non-dir) */
  357. if (costmode == 0) {
  358. thispoint = drain(fd, thispoint, nrows, ncols);
  359. }
  360. if (costmode == 1) {
  361. thispoint = drain_cost(dir_fd, thispoint, nrows, ncols);
  362. }
  363. }
  364. /* do the output */
  365. if (mode == 0 || mode == 3) {
  366. /* Output will be a cell map */
  367. /* open a new file and allocate an output buffer */
  368. new_id = Rast_open_c_new(new_map_name);
  369. out_buf = Rast_allocate_c_buf();
  370. /* mark each cell */
  371. thispoint = list;
  372. while (thispoint->next != NULL) {
  373. thispoint->value = 1;
  374. thispoint = thispoint->next;
  375. }
  376. if (mode == 3) {
  377. /* number each cell downstream */
  378. thispoint = list;
  379. ival = 0;
  380. while (thispoint->next != NULL) {
  381. if (thispoint->row == INT_MAX) {
  382. ival = 0;
  383. thispoint = thispoint->next;
  384. continue;
  385. }
  386. thispoint->value += ival;
  387. ival = thispoint->value;
  388. thispoint = thispoint->next;
  389. }
  390. }
  391. /* build the output map */
  392. G_message(_("Writing output raster map..."));
  393. for (i = 0; i < nrows; i++) {
  394. G_percent(i, nrows, 2);
  395. Rast_set_c_null_value(out_buf, ncols);
  396. thispoint = list;
  397. while (thispoint->next != NULL) {
  398. if (thispoint->row == i)
  399. out_buf[thispoint->col] = (int)thispoint->value;
  400. thispoint = thispoint->next;
  401. }
  402. Rast_put_c_row(new_id, out_buf);
  403. }
  404. G_percent(1, 1, 1);
  405. }
  406. else { /* mode = 1 or 2 */
  407. /* Output will be of the same type as input */
  408. /* open a new file and allocate an output buffer */
  409. new_id = Rast_open_new(new_map_name, in_type);
  410. out_buf = get_buf();
  411. bsz = ncols * bpe();
  412. /* loop through each point in the list and store the map values */
  413. thispoint = list;
  414. while (thispoint->next != NULL) {
  415. if (thispoint->row == INT_MAX) {
  416. thispoint = thispoint->next;
  417. continue;
  418. }
  419. lseek(fe, (off_t) thispoint->row * bsz, SEEK_SET);
  420. read(fe, in_buf, bsz);
  421. memcpy(&thispoint->value, (char *)in_buf + bpe() * thispoint->col,
  422. bpe());
  423. thispoint = thispoint->next;
  424. }
  425. if (mode == 2) {
  426. /* accumulate the input map values downstream */
  427. thispoint = list;
  428. val = 0.;
  429. while (thispoint->next != NULL) {
  430. if (thispoint->row == INT_MAX) {
  431. val = 0.;
  432. thispoint = thispoint->next;
  433. continue;
  434. }
  435. sum(&thispoint->value, &val);
  436. memcpy(&val, &thispoint->value, bpe());
  437. thispoint = thispoint->next;
  438. }
  439. }
  440. /* build the output map */
  441. G_message(_("Writing raster map <%s>..."),
  442. new_map_name);
  443. for (i = 0; i < nrows; i++) {
  444. G_percent(i, nrows, 2);
  445. set_null_value(out_buf, ncols);
  446. thispoint = list;
  447. while (thispoint->next != NULL) {
  448. if (thispoint->row == i)
  449. memcpy((char *)out_buf + bpe() * thispoint->col,
  450. &(thispoint->value), bpe());
  451. thispoint = thispoint->next;
  452. }
  453. put_row(new_id, out_buf);
  454. }
  455. G_percent(1, 1, 1);
  456. }
  457. /* Output a vector path */
  458. if (opt4->answer) {
  459. Points = Vect_new_line_struct();
  460. Cats = Vect_new_cats_struct();
  461. /* Need to modify for multiple paths */
  462. thispoint = list;
  463. i = 1;
  464. while (thispoint->next != NULL) {
  465. if (thispoint->row == INT_MAX) {
  466. thispoint = thispoint->next;
  467. Vect_cat_set(Cats, 1, i);
  468. Vect_write_line(&vout, GV_LINE, Points, Cats);
  469. Vect_reset_line(Points);
  470. Vect_reset_cats(Cats);
  471. i++;
  472. continue;
  473. }
  474. if (Vect_cat_get(Cats, 1, &cat) == 0) {
  475. Vect_cat_set(Cats, 1, i);
  476. }
  477. /* Need to convert row and col to coordinates
  478. * y = cell_head.north - ((double) p->row + 0.5) * cell_head.ns_res;
  479. * x = cell_head.west + ((double) p->col + 0.5) * cell_head.ew_res;
  480. */
  481. x = window.west + ((double)thispoint->col + 0.5) * window.ew_res;
  482. y = window.north - ((double)thispoint->row + 0.5) * window.ns_res;
  483. Vect_append_point(Points, x, y, 0.0);
  484. thispoint = thispoint->next;
  485. } /* End while */
  486. Vect_build(&vout);
  487. Vect_close(&vout);
  488. }
  489. /* close files and free buffers */
  490. Rast_close(new_id);
  491. Rast_put_cell_title(new_map_name, "Surface flow trace");
  492. Rast_short_history(new_map_name, "raster", &history);
  493. Rast_command_history(&history);
  494. Rast_write_history(new_map_name, &history);
  495. close(fe);
  496. close(fd);
  497. unlink(tempfile1);
  498. unlink(tempfile2);
  499. G_free(in_buf);
  500. G_free(out_buf);
  501. if(points_row)
  502. G_free(points_row);
  503. if(points_col)
  504. G_free(points_col);
  505. if (costmode == 1) {
  506. close(dir_fd);
  507. unlink(tempfile3);
  508. G_free(dir_buf);
  509. }
  510. exit(EXIT_SUCCESS);
  511. }
  512. struct point *drain(int fd, struct point *list, int nrow, int ncol)
  513. {
  514. int go = 1, next_row, next_col;
  515. CELL direction;
  516. CELL *dir;
  517. dir = Rast_allocate_c_buf();
  518. next_row = list->row;
  519. next_col = list->col;
  520. /* begin loop */
  521. while (go) {
  522. /* find flow direction at this point */
  523. lseek(fd, (off_t) list->row * ncol * sizeof(CELL), SEEK_SET);
  524. read(fd, dir, ncol * sizeof(CELL));
  525. direction = *(dir + list->col);
  526. go = 0;
  527. /* identify next downstream cell */
  528. if (direction > 0 && direction < 256) {
  529. if (direction == 1 || direction == 2 || direction == 4)
  530. next_col += 1;
  531. else if (direction == 16 || direction == 32 || direction == 64)
  532. next_col -= 1;
  533. if (direction == 64 || direction == 128 || direction == 1)
  534. next_row -= 1;
  535. else if (direction == 4 || direction == 8 || direction == 16)
  536. next_row += 1;
  537. if (next_col >= 0 && next_col < ncol
  538. && next_row >= 0 && next_row < nrow) {
  539. /* allocate and fill the next point structure */
  540. list->next = (struct point *)G_malloc(sizeof(struct point));
  541. list = list->next;
  542. list->row = next_row;
  543. list->col = next_col;
  544. go = 1;
  545. }
  546. }
  547. } /* end while */
  548. /* allocate and fill the end-of-path flag */
  549. list->next = (struct point *)G_malloc(sizeof(struct point));
  550. list = list->next;
  551. list->row = INT_MAX;
  552. /* return a pointer to an empty structure */
  553. list->next = (struct point *)G_malloc(sizeof(struct point));
  554. list = list->next;
  555. list->next = NULL;
  556. G_free(dir);
  557. return list;
  558. }
  559. struct point *drain_cost(int dir_fd, struct point *list, int nrow, int ncol)
  560. {
  561. /*
  562. * The idea is that each cell of the direction surface has a value representing
  563. * the direction towards the next cell in the path. The direction is read from
  564. * the input raster, and a simple case/switch is used to determine which cell to
  565. * read next. This is repeated via a while loop until a null direction is found.
  566. */
  567. int neighbour, next_row, next_col, go = 1;
  568. DCELL direction;
  569. DCELL *dir_buf;
  570. dir_buf = Rast_allocate_d_buf();
  571. next_row = list->row;
  572. next_col = list->col;
  573. while (go) {
  574. go = 0;
  575. /* Directional algorithm
  576. * 1) read cell direction
  577. * 2) shift to cell in that direction
  578. */
  579. /* find the direction recorded at row,col */
  580. lseek(dir_fd, (off_t) list->row * ncol * sizeof(DCELL), SEEK_SET);
  581. read(dir_fd, dir_buf, ncol * sizeof(DCELL));
  582. direction = *(dir_buf + list->col);
  583. neighbour = direction * 10;
  584. if (G_verbose() > 2)
  585. G_message(_("direction read: %lf, neighbour found: %i"),
  586. direction, neighbour);
  587. switch (neighbour) {
  588. case 225: /* ENE */
  589. next_row = list->row - 1;
  590. next_col = list->col + 2;
  591. break;
  592. case 450: /* NE */
  593. next_row = list->row - 1;
  594. next_col = list->col + 1;
  595. break;
  596. case 675: /* NNE */
  597. next_row = list->row - 2;
  598. next_col = list->col + 1;
  599. break;
  600. case 900: /* N */
  601. next_row = list->row - 1;
  602. next_col = list->col;
  603. break;
  604. case 1125: /* NNW */
  605. next_row = list->row - 2;
  606. next_col = list->col - 1;
  607. break;
  608. case 1350: /* NW */
  609. next_col = list->col - 1;
  610. next_row = list->row - 1;
  611. break;
  612. case 1575: /* WNW */
  613. next_col = list->col - 2;
  614. next_row = list->row - 1;
  615. break;
  616. case 1800: /* W*/
  617. next_row = list->row;
  618. next_col = list->col - 1;
  619. break;
  620. case 2025: /* WSW */
  621. next_row = list->row + 1;
  622. next_col = list->col - 2;
  623. break;
  624. case 2250: /* SW */
  625. next_row = list->row + 1;
  626. next_col = list->col - 1;
  627. break;
  628. case 2475: /* SSW */
  629. next_row = list->row + 2;
  630. next_col = list->col - 1;
  631. break;
  632. case 2700: /* S */
  633. next_row = list->row + 1;
  634. next_col = list->col;
  635. break;
  636. case 2925: /* SSE */
  637. next_row = list->row + 2;
  638. next_col = list->col + 1;
  639. break;
  640. case 3150: /* SE */
  641. next_row = list->row + 1;
  642. next_col = list->col + 1;
  643. break;
  644. case 3375: /* ESE */
  645. next_row = list->row + 1;
  646. next_col = list->col + 2;
  647. break;
  648. case 3600: /* E */
  649. next_row = list->row;
  650. next_col = list->col + 1;
  651. break;
  652. /* default:
  653. break;
  654. Should probably add something here for the possibility of a non-direction map
  655. G_fatal_error(_("Invalid direction given (possibly not a direction map)")); */
  656. } /* end switch/case */
  657. if (next_col >= 0 && next_col < ncol && next_row >= 0 &&
  658. next_row < nrow) {
  659. list->next = (struct point *)G_malloc(sizeof(struct point));
  660. list = list->next;
  661. list->row = next_row;
  662. list->col = next_col;
  663. next_row = -1;
  664. next_col = -1;
  665. go = 1;
  666. }
  667. } /* end while */
  668. /* allocate and fill the end-of-path flag */
  669. list->next = (struct point *)G_malloc(sizeof(struct point));
  670. list = list->next;
  671. list->row = INT_MAX;
  672. /* return a pointer to an empty structure */
  673. list->next = (struct point *)G_malloc(sizeof(struct point));
  674. list = list->next;
  675. list->next = NULL;
  676. G_free(dir_buf);
  677. return list;
  678. }