main.c 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165
  1. /****************************************************************************
  2. *
  3. * MODULE: r.path
  4. *
  5. * AUTHOR(S): based on r.drain
  6. * Markus Metz
  7. *
  8. * PURPOSE: Tracing paths from starting points following
  9. * input directions.
  10. * COPYRIGHT: (C) 2017 by the GRASS Development Team
  11. *
  12. * This program is free software under the GNU General Public
  13. * License (>=v2). Read the file COPYING that comes with GRASS
  14. * for details.
  15. *
  16. *****************************************************************************/
  17. #include <grass/config.h>
  18. #include <stdlib.h>
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <math.h>
  22. #include <float.h>
  23. /* for using the "open" statement */
  24. #include <sys/types.h>
  25. #include <sys/stat.h>
  26. #include <fcntl.h>
  27. /* for using the close statement */
  28. #include <unistd.h>
  29. #include <grass/gis.h>
  30. #include <grass/raster.h>
  31. #include <grass/vector.h>
  32. #include <grass/glocale.h>
  33. #include "local.h"
  34. #include "pavlrc.h"
  35. /* should probably be updated to a pointer array & malloc/realloc as needed */
  36. #define POINTS_INCREMENT 1024
  37. /* start points */
  38. struct point
  39. {
  40. int row;
  41. int col;
  42. double value;
  43. struct point *next;
  44. };
  45. /* stack points for bitmask directions */
  46. struct spoint
  47. {
  48. int row;
  49. int col;
  50. int dir;
  51. double value;
  52. struct spoint *next;
  53. };
  54. /* output path points */
  55. struct ppoint
  56. {
  57. int row;
  58. int col;
  59. double value;
  60. };
  61. /* managed list of output path points */
  62. struct point_list
  63. {
  64. struct ppoint *p;
  65. int n;
  66. int nalloc;
  67. };
  68. int dir_degree(int dir_fd, int val_fd, struct point *startp, struct Cell_head *window,
  69. struct Map_info *Out, struct point_list *pl, int out_mode);
  70. int dir_bitmask(int dir_fd, int val_fd, struct point *startp, struct Cell_head *window,
  71. struct Map_info *Out, struct point_list *pl, int out_mode);
  72. void pl_add(struct point_list *, struct ppoint *);
  73. /* comparing path points with qsort */
  74. int cmp_pp(const void *a, const void *b)
  75. {
  76. const struct ppoint *ap = (const struct ppoint *)a;
  77. const struct ppoint *bp = (const struct ppoint *)b;
  78. /* 1. ascending by row */
  79. if (ap->row != bp->row)
  80. return (ap->row - bp->row);
  81. /* 2. ascending by col */
  82. if (ap->col != bp->col)
  83. return (ap->col - bp->col);
  84. /* 3. descending by value */
  85. if (ap->value > bp->value)
  86. return -1;
  87. return (ap->value < bp->value);
  88. }
  89. int main(int argc, char **argv)
  90. {
  91. int fd, dir_fd, val_fd;
  92. int i, j, have_points = 0;
  93. int nrows, ncols;
  94. int npoints;
  95. int out_id, dir_id, dir_format;
  96. struct FPRange drange;
  97. DCELL dmin, dmax;
  98. char map_name[GNAME_MAX], out_name[GNAME_MAX], dir_name[GNAME_MAX];
  99. char *tempfile1, *tempfile2;
  100. struct History history;
  101. struct Cell_head window;
  102. struct
  103. {
  104. struct Option *dir;
  105. struct Option *format;
  106. struct Option *val;
  107. struct Option *coord;
  108. struct Option *vpoint;
  109. struct Option *rast;
  110. struct Option *vect;
  111. } opt;
  112. struct
  113. {
  114. struct Flag *copy;
  115. struct Flag *accum;
  116. struct Flag *count;
  117. } flag;
  118. struct GModule *module;
  119. void *dir_buf;
  120. struct point *head_start_pt = NULL;
  121. struct point *next_start_pt;
  122. struct point_list pl, *ppl;
  123. int start_row, start_col, out_mode;
  124. double east, north;
  125. struct line_pnts *Points;
  126. struct line_cats *Cats;
  127. struct Map_info vout, *pvout;
  128. char *desc = NULL;
  129. G_gisinit(argv[0]);
  130. module = G_define_module();
  131. G_add_keyword(_("raster"));
  132. G_add_keyword(_("hydrology"));
  133. G_add_keyword(_("cost surface"));
  134. module->description =
  135. _("Traces paths from starting points following input directions.");
  136. opt.dir = G_define_standard_option(G_OPT_R_INPUT);
  137. opt.dir->label = _("Name of input direction");
  138. opt.dir->description =
  139. _("Direction in degrees CCW from east, or bitmask encoded");
  140. opt.format = G_define_option();
  141. opt.format->type = TYPE_STRING;
  142. opt.format->key = "format";
  143. opt.format->label = _("Format of the input direction map");
  144. opt.format->required = YES;
  145. opt.format->options = "auto,degree,45degree,bitmask";
  146. opt.format->answer = "auto";
  147. G_asprintf(&desc,
  148. "auto;%s;degree;%s;45degree;%s;bitmask;%s",
  149. _("auto-detect direction format"),
  150. _("degrees CCW from East"),
  151. _("degrees CCW from East divided by 45 (e.g. r.watershed directions)"),
  152. _("bitmask encoded directions (e.g. r.cost -b)"));
  153. opt.format->descriptions = desc;
  154. opt.val = G_define_standard_option(G_OPT_R_INPUT);
  155. opt.val->key = "values";
  156. opt.val->label =
  157. _("Name of input raster values to be used for output");
  158. opt.val->required = NO;
  159. opt.rast = G_define_standard_option(G_OPT_R_OUTPUT);
  160. opt.rast->key = "raster_path";
  161. opt.rast->required = NO;
  162. opt.rast->label = _("Name for output raster path map");
  163. opt.vect = G_define_standard_option(G_OPT_V_OUTPUT);
  164. opt.vect->key = "vector_path";
  165. opt.vect->required = NO;
  166. opt.vect->label = _("Name for output vector path map");
  167. opt.coord = G_define_standard_option(G_OPT_M_COORDS);
  168. opt.coord->key = "start_coordinates";
  169. opt.coord->multiple = YES;
  170. opt.coord->description = _("Coordinates of starting point(s) (E,N)");
  171. opt.coord->guisection = _("Start");
  172. opt.vpoint = G_define_standard_option(G_OPT_V_INPUTS);
  173. opt.vpoint->key = "start_points";
  174. opt.vpoint->required = NO;
  175. opt.vpoint->label = _("Name of starting vector points map(s)");
  176. opt.vpoint->guisection = _("Start");
  177. flag.copy = G_define_flag();
  178. flag.copy->key = 'c';
  179. flag.copy->description = _("Copy input cell values on output");
  180. flag.copy->guisection = _("Path settings");
  181. flag.accum = G_define_flag();
  182. flag.accum->key = 'a';
  183. flag.accum->description = _("Accumulate input values along the path");
  184. flag.accum->guisection = _("Path settings");
  185. flag.count = G_define_flag();
  186. flag.count->key = 'n';
  187. flag.count->description = _("Count cell numbers along the path");
  188. flag.count->guisection = _("Path settings");
  189. G_option_required(opt.rast, opt.vect, NULL);
  190. G_option_exclusive(flag.copy, flag.accum, flag.count, NULL);
  191. G_option_requires_all(flag.copy, opt.rast, opt.val, NULL);
  192. G_option_requires_all(flag.accum, opt.rast, opt.val, NULL);
  193. G_option_requires_all(flag.count, opt.rast, NULL);
  194. if (G_parser(argc, argv))
  195. exit(EXIT_FAILURE);
  196. strcpy(dir_name, opt.dir->answer);
  197. *map_name = '\0';
  198. *out_name = '\0';
  199. if (opt.rast->answer) {
  200. strcpy(out_name, opt.rast->answer);
  201. if (opt.val->answer)
  202. strcpy(map_name, opt.val->answer);
  203. }
  204. pvout = NULL;
  205. if (opt.vect->answer) {
  206. if (0 > Vect_open_new(&vout, opt.vect->answer, 0)) {
  207. G_fatal_error(_("Unable to create vector map <%s>"),
  208. opt.vect->answer);
  209. }
  210. Vect_hist_command(&vout);
  211. pvout = &vout;
  212. }
  213. if (flag.copy->answer)
  214. out_mode = OUT_CPY;
  215. else if (flag.accum->answer)
  216. out_mode = OUT_ACC;
  217. else if (flag.count->answer)
  218. out_mode = OUT_CNT;
  219. else
  220. out_mode = OUT_PID;
  221. /* get the window information */
  222. G_get_window(&window);
  223. nrows = Rast_window_rows();
  224. ncols = Rast_window_cols();
  225. npoints = 0;
  226. /* TODO: use r.cost method to create a list of start points */
  227. if (opt.coord->answer) {
  228. for (i = 0; opt.coord->answers[i] != NULL; i += 2) {
  229. G_scan_easting(opt.coord->answers[i], &east, G_projection());
  230. G_scan_northing(opt.coord->answers[i + 1], &north, G_projection());
  231. start_col = (int)Rast_easting_to_col(east, &window);
  232. start_row = (int)Rast_northing_to_row(north, &window);
  233. if (start_row < 0 || start_row > nrows ||
  234. start_col < 0 || start_col > ncols) {
  235. G_warning(_("Starting point %d is outside the current region"),
  236. i + 1);
  237. continue;
  238. }
  239. npoints++;
  240. have_points = 1;
  241. next_start_pt =
  242. (struct point *)(G_malloc(sizeof(struct point)));
  243. next_start_pt->row = start_row;
  244. next_start_pt->col = start_col;
  245. next_start_pt->value = npoints;
  246. next_start_pt->next = head_start_pt;
  247. head_start_pt = next_start_pt;
  248. }
  249. }
  250. if (opt.vpoint->answers) {
  251. for (i = 0; opt.vpoint->answers[i] != NULL; i++) {
  252. struct Map_info In;
  253. struct bound_box box;
  254. int cat, type;
  255. Points = Vect_new_line_struct();
  256. Cats = Vect_new_cats_struct();
  257. Vect_set_open_level(1); /* topology not required */
  258. if (1 > Vect_open_old(&In, opt.vpoint->answers[i], ""))
  259. G_fatal_error(_("Unable to open vector map <%s>"), opt.vpoint->answers[i]);
  260. G_verbose_message(_("Reading vector map <%s> with start points..."),
  261. Vect_get_full_name(&In));
  262. Vect_rewind(&In);
  263. Vect_region_box(&window, &box);
  264. box.T = box.B = 0;
  265. while (1) {
  266. /* register line */
  267. type = Vect_read_next_line(&In, Points, Cats);
  268. /* Note: check for dead lines is not needed, because they are skipped by V1_read_next_line_nat() */
  269. if (type == -1) {
  270. G_warning(_("Unable to read vector map"));
  271. continue;
  272. }
  273. else if (type == -2) {
  274. break;
  275. }
  276. if (!Vect_point_in_box(Points->x[0], Points->y[0], 0, &box))
  277. continue;
  278. start_col = (int)Rast_easting_to_col(Points->x[0], &window);
  279. start_row = (int)Rast_northing_to_row(Points->y[0], &window);
  280. /* effectively just a duplicate check to G_site_in_region() ??? */
  281. if (start_row < 0 || start_row > nrows || start_col < 0 ||
  282. start_col > ncols)
  283. continue;
  284. npoints++;
  285. have_points = 1;
  286. next_start_pt =
  287. (struct point *)(G_malloc(sizeof(struct point)));
  288. next_start_pt->row = start_row;
  289. next_start_pt->col = start_col;
  290. Vect_cat_get(Cats, 1, &cat);
  291. next_start_pt->value = cat;
  292. next_start_pt->next = head_start_pt;
  293. head_start_pt = next_start_pt;
  294. }
  295. Vect_close(&In);
  296. /* only catches maps out of range until something is found, not after */
  297. if (!have_points) {
  298. G_warning(_("Starting vector map <%s> contains no points in the current region"),
  299. opt.vpoint->answers[i]);
  300. }
  301. Vect_destroy_line_struct(Points);
  302. Vect_destroy_cats_struct(Cats);
  303. }
  304. }
  305. if (have_points == 0)
  306. G_fatal_error(_("No start point(s) specified"));
  307. /* determine the drainage paths */
  308. /* get some temp files */
  309. val_fd = -1;
  310. tempfile1 = NULL;
  311. if (opt.val->answer && opt.rast->answer) {
  312. DCELL *map_buf;
  313. G_verbose_message(_("Reading raster values map <%s> ..."), map_name);
  314. tempfile1 = G_tempfile();
  315. val_fd = open(tempfile1, O_RDWR | O_CREAT, 0666);
  316. map_buf = Rast_allocate_d_buf();
  317. fd = Rast_open_old(map_name, "");
  318. /* transfer the values map to a temp file */
  319. for (i = 0; i < nrows; i++) {
  320. Rast_get_d_row(fd, map_buf, i);
  321. if (write(val_fd, map_buf, ncols * sizeof(DCELL)) !=
  322. ncols * sizeof(DCELL)) {
  323. G_fatal_error(_("Unable to write to tempfile"));
  324. }
  325. }
  326. Rast_close(fd);
  327. G_free(map_buf);
  328. }
  329. if (Rast_read_fp_range(dir_name, "", &drange) < 0)
  330. G_fatal_error(_("Unable to read range file"));
  331. Rast_get_fp_range_min_max(&drange, &dmin, &dmax);
  332. if (dmax <= 0)
  333. G_fatal_error(_("Invalid directions map <%s>"), dir_name);
  334. dir_format = -1;
  335. if (strcmp(opt.format->answer, "degree") == 0) {
  336. if (dmax > 360)
  337. G_fatal_error(_("Directional degrees can not be > 360"));
  338. dir_format = DIR_DEG;
  339. }
  340. else if (strcmp(opt.format->answer, "45degree") == 0) {
  341. if (dmax > 8)
  342. G_fatal_error(_("Directional degrees divided by 45 can not be > 8"));
  343. dir_format = DIR_DEG45;
  344. }
  345. else if (strcmp(opt.format->answer, "bitmask") == 0) {
  346. if (dmax > (1 << 16) - 1)
  347. G_fatal_error(_("Bitmask encoded directions can not be > %d"), (1 << 16) - 1);
  348. dir_format = DIR_BIT;
  349. }
  350. else if (strcmp(opt.format->answer, "auto") == 0) {
  351. if (dmax <= 8) {
  352. dir_format = DIR_DEG45;
  353. G_important_message(_("Input direction format assumed to be degrees CCW from East divided by 45"));
  354. }
  355. else if (dmax <= (1 << 8) - 1) {
  356. dir_format = DIR_BIT;
  357. G_important_message(_("Input direction format assumed to be bitmask encoded without Knight's move"));
  358. }
  359. else if (dmax <= 360) {
  360. dir_format = DIR_DEG;
  361. G_important_message(_("Input direction format assumed to be degrees CCW from East"));
  362. }
  363. else if (dmax <= (1 << 16) - 1) {
  364. dir_format = DIR_BIT;
  365. G_important_message(_("Input direction format assumed to be bitmask encoded with Knight's move"));
  366. }
  367. else
  368. G_fatal_error(_("Unable to detect format of input direction map <%s>"), dir_name);
  369. }
  370. if (dir_format <= 0)
  371. G_fatal_error(_("Invalid directions format '%s'"), opt.format->answer);
  372. G_verbose_message(_("Reading direction map <%s> ..."), dir_name);
  373. dir_id = Rast_open_old(dir_name, "");
  374. tempfile2 = G_tempfile();
  375. dir_fd = open(tempfile2, O_RDWR | O_CREAT, 0666);
  376. if (dir_format == DIR_BIT) {
  377. dir_buf = Rast_allocate_c_buf();
  378. for (i = 0; i < nrows; i++) {
  379. Rast_get_c_row(dir_id, dir_buf, i);
  380. if (write(dir_fd, dir_buf, ncols * sizeof(CELL)) !=
  381. ncols * sizeof(CELL)) {
  382. G_fatal_error(_("Unable to write to tempfile"));
  383. }
  384. }
  385. }
  386. else {
  387. dir_buf = Rast_allocate_d_buf();
  388. for (i = 0; i < nrows; i++) {
  389. Rast_get_d_row(dir_id, dir_buf, i);
  390. if (dir_format == DIR_DEG45) {
  391. DCELL *dp;
  392. dp = (DCELL *)dir_buf;
  393. for (j = 0; j < ncols; j++, dp++)
  394. *dp *= 45;
  395. }
  396. if (write(dir_fd, dir_buf, ncols * sizeof(DCELL)) !=
  397. ncols * sizeof(DCELL)) {
  398. G_fatal_error(_("Unable to write to tempfile"));
  399. }
  400. }
  401. }
  402. Rast_close(dir_id);
  403. G_free(dir_buf);
  404. ppl = NULL;
  405. if (opt.rast->answer) {
  406. /* raster output */
  407. pl.p = NULL;
  408. pl.n = 0;
  409. pl.nalloc = 0;
  410. ppl = &pl;
  411. }
  412. /* determine the drainage paths */
  413. /* repeat for each starting point */
  414. G_verbose_message(_("Processing start points..."));
  415. next_start_pt = head_start_pt;
  416. while (next_start_pt) {
  417. /* follow directions from start points to determine paths */
  418. /* path tracing algorithm selection */
  419. if (dir_format == DIR_BIT) {
  420. struct Map_info Tmp;
  421. if (pvout) {
  422. if (Vect_open_tmp_new(&Tmp, NULL, 0) < 0)
  423. G_fatal_error(_("Unable to create temporary vector map"));
  424. pvout = &Tmp;
  425. }
  426. if (!dir_bitmask(dir_fd, val_fd, next_start_pt, &window,
  427. pvout, ppl, out_mode)) {
  428. G_warning(_("No path at row %d, col %d"),
  429. next_start_pt->row, next_start_pt->col);
  430. }
  431. if (pvout) {
  432. Vect_build_partial(&Tmp, GV_BUILD_BASE);
  433. G_message(_("Breaking lines..."));
  434. Vect_break_lines(&Tmp, GV_LINE, NULL);
  435. Vect_copy_map_lines(&Tmp, &vout);
  436. Vect_set_release_support(&Tmp);
  437. Vect_close(&Tmp); /* temporary map is deleted automatically */
  438. pvout = &vout;
  439. }
  440. }
  441. else {
  442. if (!dir_degree(dir_fd, val_fd, next_start_pt, &window,
  443. pvout, ppl, out_mode)) {
  444. G_warning(_("No path at row %d, col %d"),
  445. next_start_pt->row, next_start_pt->col);
  446. }
  447. }
  448. next_start_pt = next_start_pt->next;
  449. }
  450. /* raster output */
  451. if (opt.rast->answer) {
  452. int row;
  453. if (pl.n > 1) {
  454. /* sort points */
  455. qsort(pl.p, pl.n, sizeof(struct ppoint), cmp_pp);
  456. /* remove duplicates */
  457. j = 1;
  458. for (i = 1; i < pl.n; i++) {
  459. if (pl.p[j - 1].row != pl.p[i].row ||
  460. pl.p[j - 1].col != pl.p[i].col) {
  461. pl.p[j].row = pl.p[i].row;
  462. pl.p[j].col = pl.p[i].col;
  463. pl.p[j].value = pl.p[i].value;
  464. j++;
  465. }
  466. }
  467. pl.n = j;
  468. }
  469. if (out_mode == OUT_PID || out_mode == OUT_CNT) {
  470. CELL *out_buf;
  471. /* Output will be a cell map */
  472. /* open a new file and allocate an output buffer */
  473. out_id = Rast_open_c_new(out_name);
  474. out_buf = Rast_allocate_c_buf();
  475. Rast_set_c_null_value(out_buf, window.cols);
  476. row = 0;
  477. /* build the output map */
  478. G_message(_("Writing output raster map..."));
  479. for (i = 0; i < pl.n; i++) {
  480. while (row < pl.p[i].row) {
  481. G_percent(row, nrows, 2);
  482. Rast_put_c_row(out_id, out_buf);
  483. Rast_set_c_null_value(out_buf, window.cols);
  484. row++;
  485. }
  486. out_buf[pl.p[i].col] = pl.p[i].value;
  487. }
  488. while (row < window.rows) {
  489. G_percent(row, nrows, 2);
  490. Rast_put_c_row(out_id, out_buf);
  491. Rast_set_c_null_value(out_buf, window.cols);
  492. row++;
  493. }
  494. G_percent(1, 1, 1);
  495. G_free(out_buf);
  496. }
  497. else { /* mode = OUT_CPY or OUT_ACC */
  498. DCELL *out_buf;
  499. /* Output could be of the same type as input */
  500. /* open a new file and allocate an output buffer */
  501. out_id = Rast_open_new(out_name, DCELL_TYPE);
  502. out_buf = Rast_allocate_d_buf();
  503. Rast_set_d_null_value(out_buf, window.cols);
  504. row = 0;
  505. /* build the output map */
  506. G_message(_("Writing output raster map..."));
  507. for (i = 0; i < pl.n; i++) {
  508. while (row < pl.p[i].row) {
  509. G_percent(row, nrows, 2);
  510. Rast_put_d_row(out_id, out_buf);
  511. Rast_set_d_null_value(out_buf, window.cols);
  512. row++;
  513. }
  514. out_buf[pl.p[i].col] = pl.p[i].value;
  515. }
  516. while (row < window.rows) {
  517. G_percent(row, nrows, 2);
  518. Rast_put_d_row(out_id, out_buf);
  519. Rast_set_d_null_value(out_buf, window.cols);
  520. row++;
  521. }
  522. G_percent(1, 1, 1);
  523. G_free(out_buf);
  524. }
  525. Rast_close(out_id);
  526. Rast_put_cell_title(out_name, "Path trace");
  527. Rast_short_history(out_name, "raster", &history);
  528. Rast_command_history(&history);
  529. Rast_write_history(out_name, &history);
  530. }
  531. /* vector output */
  532. if (opt.vect->answer) {
  533. Vect_build(&vout);
  534. Vect_close(&vout);
  535. }
  536. /* close files and free buffers */
  537. close(dir_fd);
  538. unlink(tempfile2);
  539. if (opt.val->answer && opt.rast->answer) {
  540. close(val_fd);
  541. unlink(tempfile1);
  542. }
  543. G_done_msg(" ");
  544. exit(EXIT_SUCCESS);
  545. }
  546. void pl_add(struct point_list *pl, struct ppoint *p)
  547. {
  548. if (pl->n == pl->nalloc) {
  549. pl->nalloc += POINTS_INCREMENT;
  550. pl->p = (struct ppoint *)G_realloc(pl->p, pl->nalloc * sizeof(struct ppoint));
  551. if (!pl->p)
  552. G_fatal_error(_("Unable to increase point list"));
  553. }
  554. pl->p[pl->n] = *p;
  555. pl->n++;
  556. }
  557. /* Jenson Domingue 1988, r.fill.dir:
  558. * bitmask encoded directions CW from North
  559. * value log2(value) direction
  560. * 1 0 NE
  561. * 2 1 E
  562. * 4 2 SE
  563. * 8 3 S
  564. * 16 4 SW
  565. * 32 5 W
  566. * 64 6 NW
  567. * 128 7 N
  568. * 256 8 NEN
  569. * 512 9 ENE
  570. * 1024 10 ESE
  571. * 2048 11 SES
  572. * 4096 12 SWS
  573. * 8192 13 WSW
  574. * 16384 14 WNW
  575. * 32768 15 NWN
  576. *
  577. *
  578. * 8 neighbours
  579. * 64 128 1
  580. * 32 x 2
  581. * 16 8 4
  582. *
  583. * log2(value) CW from North starting at NE
  584. * expanded for Knight's move
  585. *
  586. * 15 8
  587. * 14 6 7 0 9
  588. * 5 X 1
  589. * 13 4 3 2 10
  590. * 12 11
  591. */
  592. int dir_bitmask(int dir_fd, int val_fd, struct point *startp, struct Cell_head *window,
  593. struct Map_info *Out, struct point_list *pl, int out_mode)
  594. {
  595. int go = 1, next_row, next_col, next_dir;
  596. int npoints;
  597. int dir_row = -1, val_row = -1;
  598. CELL direction;
  599. CELL *dir_buf;
  600. DCELL *val_buf;
  601. struct spoint *stackp, *newp;
  602. struct pavlrc_table *visited;
  603. struct pavlrc ngbr_rc;
  604. struct ppoint pp;
  605. int is_stack;
  606. int cur_dir, i, npaths;
  607. struct line_pnts *Points;
  608. struct line_cats *Cats;
  609. double x, y;
  610. double value;
  611. int col_offset[16] = { 1, 1, 1, 0, -1, -1, -1, 0,
  612. 1, 2, 2, 1, -1, -2, -2, -1 };
  613. int row_offset[16] = { -1, 0, 1, 1, 1, 0, -1, -1,
  614. -2, -1, 1, 2, 2, 1, -1, -2 };
  615. dir_buf = Rast_allocate_c_buf();
  616. val_buf = NULL;
  617. stackp = (struct spoint *)G_malloc(sizeof(struct spoint));
  618. stackp->row = startp->row;
  619. stackp->col = startp->col;
  620. stackp->value = startp->value;
  621. value = startp->value;
  622. stackp->dir = -1;
  623. stackp->next = NULL;
  624. visited = pavlrc_create(NULL);
  625. ngbr_rc.row = stackp->row;
  626. ngbr_rc.col = stackp->col;
  627. pavlrc_insert(visited, &ngbr_rc);
  628. if (Out) {
  629. Points = Vect_new_line_struct();
  630. Cats = Vect_new_cats_struct();
  631. Vect_cat_set(Cats, 1, (int)stackp->value);
  632. }
  633. if (pl) {
  634. if (out_mode == OUT_CNT)
  635. value = 1;
  636. else if (out_mode == OUT_CPY || out_mode == OUT_ACC) {
  637. /* read input raster */
  638. val_buf = Rast_allocate_d_buf();
  639. if (val_row != stackp->row) {
  640. lseek(val_fd, (off_t) stackp->row * window->cols * sizeof(DCELL),
  641. SEEK_SET);
  642. if (read(val_fd, val_buf, window->cols * sizeof(DCELL)) !=
  643. window->cols * sizeof(DCELL)) {
  644. G_fatal_error(_("Unable to read from temp file"));
  645. }
  646. val_row = stackp->row;
  647. }
  648. value = val_buf[stackp->col];
  649. }
  650. stackp->value = value;
  651. }
  652. /* multi-path tracing:
  653. * multiple paths from the same starting point */
  654. npoints = 0;
  655. while (stackp) {
  656. is_stack = 1;
  657. stackp->dir++;
  658. next_row = stackp->row;
  659. next_col = stackp->col;
  660. value = stackp->value;
  661. /* begin loop */
  662. go = 1;
  663. while (go) {
  664. go = 0;
  665. /* find direction from this point */
  666. if (dir_row != next_row) {
  667. lseek(dir_fd, (off_t) next_row * window->cols * sizeof(CELL),
  668. SEEK_SET);
  669. if (read(dir_fd, dir_buf, window->cols * sizeof(CELL)) !=
  670. window->cols * sizeof(CELL)) {
  671. G_fatal_error(_("Unable to read from temp file"));
  672. }
  673. dir_row = next_row;
  674. }
  675. direction = *(dir_buf + next_col);
  676. if (direction <= 0 || Rast_is_c_null_value(&direction)) {
  677. /* end of current path: write out the result */
  678. if (Out && Points->n_points > 1) {
  679. Vect_write_line(Out, GV_LINE, Points, Cats);
  680. }
  681. /* leave this loop */
  682. if (is_stack) {
  683. newp = stackp->next;
  684. G_free(stackp);
  685. stackp = newp;
  686. }
  687. break;
  688. }
  689. /* start direction */
  690. cur_dir = 0;
  691. if (is_stack)
  692. cur_dir = stackp->dir;
  693. /* count paths going from current point and
  694. * get next direction as log2(direction) */
  695. next_dir = -1;
  696. npaths = 0;
  697. for (i = cur_dir; i < 16; i++) {
  698. if ((direction & (1 << i)) != 0) {
  699. npaths++;
  700. if (next_dir < 0)
  701. next_dir = i;
  702. }
  703. }
  704. if (is_stack) {
  705. if (npaths > 0) {
  706. stackp->dir = next_dir;
  707. /* start a new path */
  708. if (Out) {
  709. Vect_reset_line(Points);
  710. x = window->west + (next_col + 0.5) * window->ew_res;
  711. y = window->north - (next_row + 0.5) * window->ns_res;
  712. Vect_append_point(Points, x, y, 0.0);
  713. }
  714. if (pl) {
  715. value = stackp->value;
  716. pp.row = next_row;
  717. pp.col = next_col;
  718. pp.value = value;
  719. pl_add(pl, &pp);
  720. }
  721. npoints++;
  722. }
  723. else {
  724. /* stack point without path ? */
  725. if (stackp->dir == 0)
  726. G_warning(_("No path from row %d, col %d"),
  727. stackp->row, stackp->col);
  728. /* drop this point from the stack */
  729. G_debug(1, "drop point from stack");
  730. newp = stackp->next;
  731. G_free(stackp);
  732. stackp = newp;
  733. break;
  734. }
  735. }
  736. else { /* not a stack point */
  737. if (npaths == 0) {
  738. /* should not happen */
  739. G_fatal_error(_("Invalid direction %d"), direction);
  740. }
  741. if (npaths > 1) {
  742. /* write out the result */
  743. if (Out && Points->n_points > 1) {
  744. Vect_write_line(Out, GV_LINE, Points, Cats);
  745. }
  746. ngbr_rc.row = next_row;
  747. ngbr_rc.col = next_col;
  748. /* add it to the stack and leave this loop */
  749. G_debug(1, "add point to stack: row %d, col %d, dir %d",
  750. next_row, next_col, next_dir);
  751. newp = (struct spoint *)G_malloc(sizeof(struct spoint));
  752. newp->row = next_row;
  753. newp->col = next_col;
  754. newp->dir = next_dir - 1;
  755. newp->value = value;
  756. newp->next = stackp;
  757. stackp = newp;
  758. break;
  759. }
  760. }
  761. is_stack = 0;
  762. /* identify next downstream cell */
  763. next_row += row_offset[next_dir];
  764. next_col += col_offset[next_dir];
  765. G_debug(1, "next cell at row %d, col %d", next_row, next_col);
  766. if (next_col >= 0 && next_col < window->cols
  767. && next_row >= 0 && next_row < window->rows) {
  768. /* add point */
  769. if (Out) {
  770. x = window->west + (next_col + 0.5) * window->ew_res;
  771. y = window->north - (next_row + 0.5) * window->ns_res;
  772. Vect_append_point(Points, x, y, 0.0);
  773. }
  774. if (pl) {
  775. if (out_mode == OUT_CNT)
  776. value += 1;
  777. else if (out_mode == OUT_CPY || out_mode == OUT_ACC) {
  778. /* read input raster */
  779. if (val_row != next_row) {
  780. lseek(val_fd, (off_t) next_row * window->cols * sizeof(DCELL),
  781. SEEK_SET);
  782. if (read(val_fd, val_buf, window->cols * sizeof(DCELL)) !=
  783. window->cols * sizeof(DCELL)) {
  784. G_fatal_error(_("Unable to read from temp file"));
  785. }
  786. val_row = next_row;
  787. }
  788. if (out_mode == OUT_CPY)
  789. value = val_buf[next_col];
  790. else
  791. value += val_buf[next_col];
  792. }
  793. pp.row = next_row;
  794. pp.col = next_col;
  795. pp.value = value;
  796. pl_add(pl, &pp);
  797. }
  798. /* avoid circular paths
  799. * avoid tracing the same path segment several times:
  800. * a path can split and later on merge again,
  801. * then split again, merge again
  802. * path segments are identical from every merge point
  803. * to the next split point */
  804. ngbr_rc.row = next_row;
  805. ngbr_rc.col = next_col;
  806. if (!pavlrc_insert(visited, &ngbr_rc)) {
  807. go = 1;
  808. npoints++;
  809. }
  810. else {
  811. /* reached a merge point */
  812. /* write out the result */
  813. if (Out && Points->n_points > 1) {
  814. Vect_write_line(Out, GV_LINE, Points, Cats);
  815. }
  816. }
  817. }
  818. else {
  819. G_warning(_("Path is leaving the current region"));
  820. }
  821. } /* end while */
  822. }
  823. pavlrc_destroy(visited);
  824. G_free(dir_buf);
  825. if (val_buf)
  826. G_free(val_buf);
  827. if (Out) {
  828. Vect_destroy_line_struct(Points);
  829. Vect_destroy_cats_struct(Cats);
  830. }
  831. return (npoints > 1);
  832. }
  833. int dir_degree(int dir_fd, int val_fd, struct point *startp, struct Cell_head *window,
  834. struct Map_info *Out, struct point_list *pl, int out_mode)
  835. {
  836. /*
  837. * The idea is that each cell of the direction surface has a value representing
  838. * the direction towards the next cell in the path. The direction is read from
  839. * the input raster, and a simple case/switch is used to determine which cell to
  840. * read next. This is repeated via a while loop until a null direction is found.
  841. *
  842. * directions are degrees CCW from East with East = 360
  843. */
  844. int neighbour, next_row, next_col, go = 1;
  845. int npoints;
  846. int dir_row = -1, val_row = -1;
  847. DCELL direction;
  848. DCELL *dir_buf;
  849. DCELL *val_buf;
  850. double x, y;
  851. double value;
  852. struct ppoint pp;
  853. struct line_pnts *Points;
  854. struct line_cats *Cats;
  855. dir_buf = Rast_allocate_d_buf();
  856. val_buf = NULL;
  857. next_row = startp->row;
  858. next_col = startp->col;
  859. value = startp->value;
  860. if (Out) {
  861. Points = Vect_new_line_struct();
  862. Cats = Vect_new_cats_struct();
  863. Vect_cat_set(Cats, 1, (int)value);
  864. x = window->west + (next_col + 0.5) * window->ew_res;
  865. y = window->north - (next_row + 0.5) * window->ns_res;
  866. Vect_append_point(Points, x, y, 0.0);
  867. }
  868. if (pl) {
  869. if (out_mode == OUT_CNT)
  870. value = 1;
  871. else if (out_mode == OUT_CPY || out_mode == OUT_ACC) {
  872. /* read input raster */
  873. val_buf = Rast_allocate_d_buf();
  874. if (val_row != next_row) {
  875. lseek(val_fd, (off_t) next_row * window->cols * sizeof(DCELL),
  876. SEEK_SET);
  877. if (read(val_fd, val_buf, window->cols * sizeof(DCELL)) !=
  878. window->cols * sizeof(DCELL)) {
  879. G_fatal_error(_("Unable to read from temp file"));
  880. }
  881. val_row = next_row;
  882. }
  883. value = val_buf[next_col];
  884. }
  885. pp.row = next_row;
  886. pp.col = next_col;
  887. pp.value = value;
  888. pl_add(pl, &pp);
  889. }
  890. npoints = 1;
  891. while (go) {
  892. go = 0;
  893. /* Directional algorithm
  894. * 1) read cell direction
  895. * 2) shift to cell in that direction
  896. */
  897. /* find the direction recorded at row,col */
  898. if (dir_row != next_row) {
  899. lseek(dir_fd, (off_t) next_row * window->cols * sizeof(DCELL),
  900. SEEK_SET);
  901. if (read(dir_fd, dir_buf, window->cols * sizeof(DCELL)) !=
  902. window->cols * sizeof(DCELL)) {
  903. G_fatal_error(_("Unable to read from temp file"));
  904. }
  905. dir_row = next_row;
  906. }
  907. direction = *(dir_buf + next_col);
  908. neighbour = 0;
  909. if (!Rast_is_d_null_value(&direction)) {
  910. neighbour = direction * 10;
  911. G_debug(2, "direction read: %lf, neighbour found: %i",
  912. direction, neighbour);
  913. }
  914. switch (neighbour) {
  915. case 225: /* ENE */
  916. next_row -= 1;
  917. next_col += 2;
  918. break;
  919. case 450: /* NE */
  920. next_row -= 1;
  921. next_col += 1;
  922. break;
  923. case 675: /* NNE */
  924. next_row -= 2;
  925. next_col += 1;
  926. break;
  927. case 900: /* N */
  928. next_row -= 1;
  929. break;
  930. case 1125: /* NNW */
  931. next_row -= 2;
  932. next_col -= 1;
  933. break;
  934. case 1350: /* NW */
  935. next_col -= 1;
  936. next_row -= 1;
  937. break;
  938. case 1575: /* WNW */
  939. next_col -= 2;
  940. next_row -= 1;
  941. break;
  942. case 1800: /* W*/
  943. next_col -= 1;
  944. break;
  945. case 2025: /* WSW */
  946. next_row += 1;
  947. next_col -= 2;
  948. break;
  949. case 2250: /* SW */
  950. next_row += 1;
  951. next_col -= 1;
  952. break;
  953. case 2475: /* SSW */
  954. next_row += 2;
  955. next_col -= 1;
  956. break;
  957. case 2700: /* S */
  958. next_row += 1;
  959. break;
  960. case 2925: /* SSE */
  961. next_row += 2;
  962. next_col += 1;
  963. break;
  964. case 3150: /* SE */
  965. next_row += 1;
  966. next_col += 1;
  967. break;
  968. case 3375: /* ESE */
  969. next_row += 1;
  970. next_col += 2;
  971. break;
  972. case 3600: /* E */
  973. next_col += 1;
  974. break;
  975. default:
  976. /* end of path */
  977. next_row = -1;
  978. next_col = -1;
  979. break;
  980. } /* end switch/case */
  981. if (next_col >= 0 && next_col < window->cols && next_row >= 0 &&
  982. next_row < window->rows) {
  983. if (Out) {
  984. x = window->west + (next_col + 0.5) * window->ew_res;
  985. y = window->north - (next_row + 0.5) * window->ns_res;
  986. Vect_append_point(Points, x, y, 0.0);
  987. }
  988. if (pl) {
  989. if (out_mode == OUT_CNT)
  990. value += 1;
  991. else if (out_mode == OUT_CPY || out_mode == OUT_ACC) {
  992. /* read input raster */
  993. if (val_row != next_row) {
  994. lseek(val_fd, (off_t) next_row * window->cols * sizeof(DCELL),
  995. SEEK_SET);
  996. if (read(val_fd, val_buf, window->cols * sizeof(DCELL)) !=
  997. window->cols * sizeof(DCELL)) {
  998. G_fatal_error(_("Unable to read from temp file"));
  999. }
  1000. val_row = next_row;
  1001. }
  1002. if (out_mode == OUT_CPY)
  1003. value = val_buf[next_col];
  1004. else
  1005. value += val_buf[next_col];
  1006. }
  1007. pp.row = next_row;
  1008. pp.col = next_col;
  1009. pp.value = value;
  1010. pl_add(pl, &pp);
  1011. }
  1012. go = 1;
  1013. npoints++;
  1014. }
  1015. } /* end while */
  1016. if (Out && Points->n_points > 1) {
  1017. Vect_write_line(Out, GV_LINE, Points, Cats);
  1018. }
  1019. G_free(dir_buf);
  1020. if (val_buf)
  1021. G_free(val_buf);
  1022. if (Out) {
  1023. Vect_destroy_line_struct(Points);
  1024. Vect_destroy_cats_struct(Cats);
  1025. }
  1026. return (npoints > 1);
  1027. }