main.c 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554
  1. /****************************************************************************
  2. *
  3. * MODULE: r.walk
  4. * AUTHOR(S): Based on r.cost written by :
  5. * Antony Awaida,
  6. * Intelligent Engineering
  7. * Systems Laboratory,
  8. * M.I.T.
  9. * James Westervelt,
  10. * U.S.Army Construction Engineering Research Laboratory
  11. *
  12. * Updated for Grass 5
  13. * Pierre de Mouveaux (pmx@audiovu.com)
  14. *
  15. * Initial version of r.walk:
  16. * Steno Fontanari, 2002, ITC-irst
  17. *
  18. * GRASS 6.0 version of r.walk:
  19. * Franceschetti Simone, Sorrentino Diego, Mussi Fabiano and Pasolli Mattia
  20. * Correction by: Fontanari Steno, Napolitano Maurizio and Flor Roberto
  21. * In collaboration with: Franchi Matteo, Vaglia Beatrice, Bartucca Luisa,
  22. * Fava Valentina and Tolotti Mathias, 2004
  23. *
  24. * Updated for GRASS 6.1
  25. * Roberto Flor and Markus Neteler
  26. * Glynn Clements <glynn gclements.plus.com>, Soeren Gebbert <soeren.gebbert gmx.de>
  27. * Updated for calculation errors and directional surface generation
  28. * Colin Nielsen <colin.nielsen gmail com>
  29. * Updated for GRASS 7
  30. * Markus Metz
  31. * PURPOSE: anisotropic movements on cost surfaces
  32. * COPYRIGHT: (C) 1999-2015 by the GRASS Development Team
  33. *
  34. * This program is free software under the GNU General Public
  35. * License (>=v2). Read the file COPYING that comes with GRASS
  36. * for details.
  37. *
  38. *****************************************************************************/
  39. /*********************************************************************
  40. *
  41. * This is the main program for the minimum path cost analysis.
  42. * It generates a cumulative cost map (output) from an elevation (inputdtm
  43. * and cost map (inputcost) with respect to starting locations (coor).
  44. *
  45. * It takes as input the following:
  46. * 1) Cost of traversing each grid cell as given by an elevation map and
  47. * a cost map cell (inputcost).
  48. * 2) If starting points are not specified on the command line
  49. * then the output map must exist and contain the starting locations
  50. *
  51. * Otherwise the output map need not exist and the coor points
  52. * from the command line are used.
  53. *
  54. *********************************************************************/
  55. /*********************************************************************
  56. * The walking energy is computed for the human walk, based on Aitken,
  57. * 1977, Langmuir, 1984:
  58. *
  59. * {T= [(a)x(Delta S)] + [(b)x(Delta H Climb)]
  60. * +[(c)*(Delta H moderate downhill)]+[(d)*(Delta H steep downhill]}
  61. *
  62. * where T is time in seconds, Delta S distance in meter, Delta H the heigth difference
  63. *
  64. * The default a,b,c,d parameters used below have been measured using oxygen consumption in biomechanical
  65. * experiments.
  66. * Refs:
  67. * * Aitken, R. 1977. Wilderness areas in Scotland. Unpublished Ph.D. thesis. University of Aberdeen.
  68. * * Steno Fontanari, University of Trento, Italy, Ingegneria per l'Ambiente e
  69. * il Territorio, 2000-2001. Svilluppo di metodologie GIS per la determinazione dell'accessibilita'
  70. * territoriale come supporto alle decisioni nella gestione ambientale.
  71. * * Langmuir, E. 1984. Mountaincraft and leadership. The Scottish Sports Council/MLTB. Cordee,
  72. * Leicester.
  73. *
  74. * The total cost is computed as a linear combination of walking energy and a given friction cost map:
  75. *
  76. * TOTAL COST = [(WALKING ENERGY ) + (LAMBDA*FRICTION)]
  77. *
  78. * TODO: generalize formula to other species
  79. *************/
  80. /*
  81. *
  82. * 20 july 2004 - Pierre de Mouveaux. pmx@audiovu.com
  83. * Updated to use the Grass 5.0 floating point raster cell format.
  84. * Convert floats to double. Done ;)
  85. * 2001: original r.walk by Steno Fontanari, ITC-irst
  86. * 24 July 2004: WebValley 2004, fixed and enhanced by
  87. * Matteo Franchi Liceo Leonardo Da Vinci Trento
  88. * Roberto Flor ITC-irst
  89. * 7 December 2005: Grass 6.1 cleanup
  90. * Roberto Flor ITC-irst
  91. * Markus Neteler CEA
  92. */
  93. #include <stdlib.h>
  94. #include <unistd.h>
  95. #include <string.h>
  96. #include <math.h>
  97. #include <sys/types.h>
  98. #include <sys/stat.h>
  99. #include <fcntl.h>
  100. #include <grass/gis.h>
  101. #include <grass/raster.h>
  102. #include <grass/vector.h>
  103. #include <grass/segment.h>
  104. #include <grass/glocale.h>
  105. #include "cost.h"
  106. #include "stash.h"
  107. #define SEGCOLSIZE 64
  108. struct Cell_head window;
  109. struct start_pt *head_start_pt = NULL;
  110. struct start_pt *head_end_pt = NULL;
  111. int main(int argc, char *argv[])
  112. {
  113. const char *cum_cost_layer, *move_dir_layer;
  114. const char *cost_layer, *dtm_layer;
  115. const char *dtm_mapset, *cost_mapset, *search_mapset;
  116. void *dtm_cell, *cost_cell, *cum_cell, *dir_cell, *cell2 = NULL;
  117. SEGMENT cost_seg, dir_seg;
  118. double *value;
  119. char buf[400];
  120. extern struct Cell_head window;
  121. double NS_fac, EW_fac, DIAG_fac, H_DIAG_fac, V_DIAG_fac;
  122. double fcost_dtm, fcost_cost;
  123. double min_cost, old_min_cost;
  124. FCELL cur_dir;
  125. double zero = 0.0;
  126. int col = 0, row = 0, nrows = 0, ncols = 0;
  127. int maxcost, par_number;
  128. int nseg;
  129. int maxmem;
  130. int segments_in_memory;
  131. int cost_fd, cum_fd, dtm_fd, dir_fd;
  132. int have_stop_points = 0, dir = 0;
  133. double my_dtm, my_cost, check_dtm;
  134. double null_cost, dnullval;
  135. double a, b, c, d, lambda, slope_factor;
  136. int srows, scols;
  137. int total_reviewed;
  138. int keep_nulls = 1;
  139. int start_with_raster_vals = 1;
  140. int neighbor;
  141. long n_processed = 0;
  142. long total_cells;
  143. struct GModule *module;
  144. struct Flag *flag2, *flag3, *flag4, *flag5;
  145. struct Option *opt1, *opt2, *opt3, *opt4, *opt5, *opt6, *opt7, *opt8;
  146. struct Option *opt9, *opt10, *opt11, *opt12, *opt13, *opt14, *opt15;
  147. struct cost *pres_cell;
  148. struct start_pt *pres_start_pt = NULL;
  149. struct start_pt *pres_stop_pt = NULL;
  150. struct cc {
  151. double dtm; /* elevation model */
  152. double cost_in; /* friction costs */
  153. double cost_out; /* cumulative costs */
  154. } costs;
  155. void *ptr1, *ptr2;
  156. RASTER_MAP_TYPE dtm_data_type, cost_data_type, cum_data_type =
  157. DCELL_TYPE, dir_data_type = FCELL_TYPE;
  158. struct History history;
  159. double peak = 0.0;
  160. int dtm_dsize, cost_dsize;
  161. double disk_mb, mem_mb, pq_mb;
  162. /* Definition for dimension and region check */
  163. struct Cell_head dtm_cellhd, cost_cellhd;
  164. G_gisinit(argv[0]);
  165. module = G_define_module();
  166. G_add_keyword(_("raster"));
  167. G_add_keyword(_("cost surface"));
  168. G_add_keyword(_("cumulative costs"));
  169. G_add_keyword(_("cost allocation"));
  170. module->description =
  171. _("Creates a raster map showing the "
  172. "anisotropic cumulative cost of moving between different "
  173. "geographic locations on an input raster map "
  174. "whose cell category values represent cost.");
  175. opt12 = G_define_standard_option(G_OPT_R_ELEV);
  176. opt2 = G_define_standard_option(G_OPT_R_INPUT);
  177. opt2->key = "friction";
  178. opt2->description =
  179. _("Name of input raster map containing friction costs");
  180. opt1 = G_define_standard_option(G_OPT_R_OUTPUT);
  181. opt1->description = _("Name for output raster map to contain walking costs");
  182. opt11 = G_define_standard_option(G_OPT_R_OUTPUT);
  183. opt11->key = "outdir";
  184. opt11->required = NO;
  185. opt11->description =
  186. _("Name for output raster map to contain movement directions");
  187. opt11->guisection = _("Optional outputs");
  188. opt7 = G_define_standard_option(G_OPT_V_INPUT);
  189. opt7->key = "start_points";
  190. opt7->required = NO;
  191. opt7->label = _("Name of starting vector points map");
  192. opt7->guisection = _("Start");
  193. opt8 = G_define_standard_option(G_OPT_V_INPUT);
  194. opt8->key = "stop_points";
  195. opt8->required = NO;
  196. opt8->label = _("Name of stopping vector points map");
  197. opt8->guisection = _("Stop");
  198. opt9 = G_define_standard_option(G_OPT_R_INPUT);
  199. opt9->key = "start_raster";
  200. opt9->required = NO;
  201. opt9->description = _("Name of starting raster points map");
  202. opt9->guisection = _("Start");
  203. opt3 = G_define_standard_option(G_OPT_M_COORDS);
  204. opt3->key = "start_coordinates";
  205. opt3->multiple = YES;
  206. opt3->description =
  207. _("Coordinates of starting point(s) (E,N)");
  208. opt3->guisection = _("Start");
  209. opt4 = G_define_standard_option(G_OPT_M_COORDS);
  210. opt4->key = "stop_coordinates";
  211. opt4->multiple = YES;
  212. opt4->description =
  213. _("Coordinates of stopping point(s) (E,N)");
  214. opt4->guisection = _("Stop");
  215. opt5 = G_define_option();
  216. opt5->key = "max_cost";
  217. opt5->type = TYPE_INTEGER;
  218. opt5->key_desc = "value";
  219. opt5->required = NO;
  220. opt5->multiple = NO;
  221. opt5->answer = "0";
  222. opt5->description = _("Maximum cumulative cost");
  223. opt6 = G_define_option();
  224. opt6->key = "null_cost";
  225. opt6->type = TYPE_DOUBLE;
  226. opt6->key_desc = "value";
  227. opt6->required = NO;
  228. opt6->multiple = NO;
  229. opt6->description =
  230. _("Cost assigned to null cells. By default, null cells are excluded");
  231. opt6->guisection = _("NULL cells");
  232. opt10 = G_define_option();
  233. opt10->key = "memory";
  234. opt10->type = TYPE_INTEGER;
  235. opt10->key_desc = "value";
  236. opt10->required = NO;
  237. opt10->multiple = NO;
  238. opt10->answer = "300";
  239. opt10->description = _("Maximum memory to be used in MB");
  240. opt15 = G_define_option();
  241. opt15->key = "walk_coeff";
  242. opt15->type = TYPE_STRING;
  243. opt15->key_desc = "a,b,c,d";
  244. opt15->required = NO;
  245. opt15->multiple = NO;
  246. opt15->answer = "0.72,6.0,1.9998,-1.9998";
  247. opt15->description =
  248. _("Coefficients for walking energy formula parameters a,b,c,d");
  249. opt15->guisection = _("Settings");
  250. opt14 = G_define_option();
  251. opt14->key = "lambda";
  252. opt14->type = TYPE_DOUBLE;
  253. opt14->required = NO;
  254. opt14->multiple = NO;
  255. opt14->answer = "1.0";
  256. opt14->description =
  257. _("Lambda coefficients for combining walking energy and friction cost");
  258. opt14->guisection = _("Settings");
  259. opt13 = G_define_option();
  260. opt13->key = "slope_factor";
  261. opt13->type = TYPE_DOUBLE;
  262. opt13->required = NO;
  263. opt13->multiple = NO;
  264. opt13->answer = "-0.2125";
  265. opt13->description =
  266. _("Slope factor determines travel energy cost per height step");
  267. opt13->guisection = _("Settings");
  268. flag2 = G_define_flag();
  269. flag2->key = 'k';
  270. flag2->description =
  271. _("Use the 'Knight's move'; slower, but more accurate");
  272. flag3 = G_define_flag();
  273. flag3->key = 'n';
  274. flag3->description = _("Keep null values in output raster map");
  275. flag3->guisection = _("NULL cells");
  276. flag4 = G_define_flag();
  277. flag4->key = 'r';
  278. flag4->description = _("Start with values in raster map");
  279. flag4->guisection = _("Start");
  280. flag5 = G_define_flag();
  281. flag5->key = 'i';
  282. flag5->description = _("Print info about disk space and memory requirements and exit");
  283. /* Parse options */
  284. if (G_parser(argc, argv))
  285. exit(EXIT_FAILURE);
  286. /* If no outdir is specified, set flag to skip all dir */
  287. if (opt11->answer != NULL)
  288. dir = 1;
  289. /* Get database window parameters */
  290. Rast_get_window(&window);
  291. /* Find north-south, east_west and diagonal factors */
  292. EW_fac = window.ew_res; /* Must be the physical distance */
  293. NS_fac = window.ns_res;
  294. DIAG_fac = (double)sqrt((double)(NS_fac * NS_fac + EW_fac * EW_fac));
  295. V_DIAG_fac =
  296. (double)sqrt((double)(4 * NS_fac * NS_fac + EW_fac * EW_fac));
  297. H_DIAG_fac =
  298. (double)sqrt((double)(NS_fac * NS_fac + 4 * EW_fac * EW_fac));
  299. Rast_set_d_null_value(&null_cost, 1);
  300. if (flag2->answer)
  301. total_reviewed = 16;
  302. else
  303. total_reviewed = 8;
  304. keep_nulls = flag3->answer;
  305. start_with_raster_vals = flag4->answer;
  306. {
  307. int count = 0;
  308. if (opt3->answers)
  309. count++;
  310. if (opt7->answers)
  311. count++;
  312. if (opt9->answers)
  313. count++;
  314. if (count != 1)
  315. G_fatal_error(_("Must specify exactly one of start_points, start_rast or coordinate"));
  316. }
  317. if (opt3->answers)
  318. if (!process_answers(opt3->answers, &head_start_pt, &pres_start_pt))
  319. G_fatal_error(_("No start points"));
  320. if (opt4->answers)
  321. have_stop_points =
  322. process_answers(opt4->answers, &head_end_pt, &pres_stop_pt);
  323. if (sscanf(opt5->answer, "%d", &maxcost) != 1 || maxcost < 0)
  324. G_fatal_error(_("Inappropriate maximum cost: %d"), maxcost);
  325. if (sscanf(opt10->answer, "%d", &maxmem) != 1 || maxmem <= 0)
  326. G_fatal_error(_("Inappropriate amount of memory: %d"), maxmem);
  327. /* Getting walking energy formula parameters */
  328. if ((par_number =
  329. sscanf(opt15->answer, "%lf,%lf,%lf,%lf", &a, &b, &c, &d)) != 4)
  330. G_fatal_error(_("Missing required value: got %d instead of 4"),
  331. par_number);
  332. else {
  333. G_message(_("Walking costs are a=%g b=%g c=%g d=%g"), a, b, c, d);
  334. }
  335. /* Getting lambda */
  336. if ((par_number = sscanf(opt14->answer, "%lf", &lambda)) != 1)
  337. G_fatal_error(_("Missing required value: %d"), par_number);
  338. else {
  339. G_message(_("Lambda is %g"), lambda);
  340. }
  341. /* Getting slope_factor */
  342. if ((par_number = sscanf(opt13->answer, "%lf", &slope_factor)) != 1)
  343. G_fatal_error(_("Missing required value: %d"), par_number);
  344. else {
  345. G_message(_("Slope_factor is %g"), slope_factor);
  346. }
  347. if ((opt6->answer == NULL) ||
  348. (sscanf(opt6->answer, "%lf", &null_cost) != 1)) {
  349. G_debug(1, "Null cells excluded from cost evaluation");
  350. Rast_set_d_null_value(&null_cost, 1);
  351. }
  352. else if (keep_nulls)
  353. G_debug(1,"Input null cell will be retained into output map");
  354. if (opt7->answer) {
  355. search_mapset = G_find_vector2(opt7->answer, "");
  356. if (search_mapset == NULL)
  357. G_fatal_error(_("Vector map <%s> not found"), opt7->answer);
  358. }
  359. if (!Rast_is_d_null_value(&null_cost)) {
  360. if (null_cost < 0.0) {
  361. G_warning(_("Assigning negative cost to null cell. Null cells excluded."));
  362. Rast_set_d_null_value(&null_cost, 1);
  363. }
  364. }
  365. else {
  366. keep_nulls = 0; /* handled automagically... */
  367. }
  368. dtm_layer = opt12->answer;
  369. cost_layer = opt2->answer;
  370. cum_cost_layer = opt1->answer;
  371. move_dir_layer = opt11->answer;
  372. /* Find number of rows and columns in window */
  373. nrows = Rast_window_rows();
  374. ncols = Rast_window_cols();
  375. /* Open cost cell layer for reading */
  376. dtm_mapset = G_find_raster2(dtm_layer, "");
  377. if (dtm_mapset == NULL)
  378. G_fatal_error(_("Raster map <%s> not found"), dtm_layer);
  379. dtm_fd = Rast_open_old(dtm_layer, "");
  380. cost_mapset = G_find_raster2(cost_layer, "");
  381. if (cost_mapset == NULL)
  382. G_fatal_error(_("Raster map <%s> not found"), cost_layer);
  383. cost_fd = Rast_open_old(cost_layer, cost_mapset);
  384. Rast_get_cellhd(dtm_layer, "", &dtm_cellhd);
  385. Rast_get_cellhd(cost_layer, "", &cost_cellhd);
  386. dtm_data_type = Rast_get_map_type(dtm_fd);
  387. cost_data_type = Rast_get_map_type(cost_fd);
  388. /* Parameters for map submatrices */
  389. switch (dtm_data_type) {
  390. case (CELL_TYPE):
  391. G_debug(1, "DTM_Source map is: Integer cell type");
  392. break;
  393. case (FCELL_TYPE):
  394. G_debug(1, "DTM_Source map is: Floating point (float) cell type");
  395. break;
  396. case (DCELL_TYPE):
  397. G_debug(1, "DTM_Source map is: Floating point (double) cell type");
  398. break;
  399. }
  400. G_debug(1, "DTM %d rows, %d cols", dtm_cellhd.rows, dtm_cellhd.cols);
  401. switch (cost_data_type) {
  402. case (CELL_TYPE):
  403. G_debug(1, "COST_Source map is: Integer cell type");
  404. break;
  405. case (FCELL_TYPE):
  406. G_debug(1, "COST_Source map is: Floating point (float) cell type");
  407. break;
  408. case (DCELL_TYPE):
  409. G_debug(1, "COST_Source map is: Floating point (double) cell type");
  410. break;
  411. }
  412. G_debug(1, "COST %d rows, %d cols", cost_cellhd.rows, cost_cellhd.cols);
  413. G_debug(1, " %d rows, %d cols", nrows, ncols);
  414. G_format_resolution(window.ew_res, buf, window.proj);
  415. G_debug(1, " EW resolution %s (%g)", buf, window.ew_res);
  416. G_format_resolution(window.ns_res, buf, window.proj);
  417. G_debug(1, " NS resolution %s (%g)", buf, window.ns_res);
  418. /* this is most probably the limitation of r.walk for large datasets
  419. * segment size needs to be reduced to avoid unecessary disk IO
  420. * but it doesn't make sense to go down to 1
  421. * so use 64 segment rows and cols for <= 200 million cells
  422. * for larger regions, 32 segment rows and cols
  423. * maybe go down to 16 for > 500 million cells ? */
  424. if ((double) nrows * ncols > 200000000)
  425. srows = scols = SEGCOLSIZE / 2;
  426. else
  427. srows = scols = SEGCOLSIZE;
  428. /* calculate total number of segments */
  429. nseg = ((nrows + srows - 1) / srows) * ((ncols + scols - 1) / scols);
  430. /* calculate disk space and memory requirements */
  431. /* (nrows + ncols) * 8. * 20.0 / 1048576. for Dijkstra search */
  432. pq_mb = ((double)nrows + ncols) * 8. * 20.0 / 1048576.;
  433. G_debug(1, "pq MB: %g", pq_mb);
  434. maxmem -= pq_mb;
  435. if (maxmem < 10)
  436. maxmem = 10;
  437. if (dir == TRUE) {
  438. disk_mb = (double) nrows * ncols * 28. / 1048576.;
  439. segments_in_memory = maxmem /
  440. ((double) srows * scols * (28. / 1048576.));
  441. if (segments_in_memory < 4)
  442. segments_in_memory = 4;
  443. if (segments_in_memory > nseg)
  444. segments_in_memory = nseg;
  445. mem_mb = (double) srows * scols * (28. / 1048576.) * segments_in_memory;
  446. }
  447. else {
  448. disk_mb = (double) nrows * ncols * 24. / 1048576.;
  449. segments_in_memory = maxmem /
  450. ((double) srows * scols * (24. / 1048576.));
  451. if (segments_in_memory < 4)
  452. segments_in_memory = 4;
  453. if (segments_in_memory > nseg)
  454. segments_in_memory = nseg;
  455. mem_mb = (double) srows * scols * (24. / 1048576.) * segments_in_memory;
  456. }
  457. if (flag5->answer) {
  458. fprintf(stdout, _("Will need at least %.2f MB of disk space"), disk_mb);
  459. fprintf(stdout, "\n");
  460. fprintf(stdout, _("Will need at least %.2f MB of memory"), mem_mb);
  461. fprintf(stdout, "\n");
  462. fprintf(stdout, _("%d of %d segments are kept in memory"),
  463. segments_in_memory, nseg);
  464. fprintf(stdout, "\n");
  465. Rast_close(cost_fd);
  466. Rast_close(dtm_fd);
  467. exit(EXIT_SUCCESS);
  468. }
  469. G_verbose_message("--------------------------------------------");
  470. G_verbose_message(_("Will need at least %.2f MB of disk space"), disk_mb);
  471. G_verbose_message(_("Will need at least %.2f MB of memory"), mem_mb);
  472. G_verbose_message(_("%d of %d segments are kept in memory"),
  473. segments_in_memory, nseg);
  474. G_verbose_message("--------------------------------------------");
  475. /* Create segmented format files for cost layer and output layer */
  476. G_verbose_message(_("Creating some temporary files..."));
  477. if (Segment_open(&cost_seg, G_tempfile(), nrows, ncols, srows, scols,
  478. sizeof(struct cc), segments_in_memory) != 1)
  479. G_fatal_error(_("Can not create temporary file"));
  480. if (dir == 1) {
  481. if (Segment_open(&dir_seg, G_tempfile(), nrows, ncols, srows, scols,
  482. sizeof(FCELL), segments_in_memory) != 1)
  483. G_fatal_error(_("Can not create temporary file"));
  484. }
  485. /* Write the dtm and cost layers in the segmented file */
  486. G_message(_("Reading raster maps <%s> and <%s>, initializing output..."),
  487. G_fully_qualified_name(dtm_layer, dtm_mapset),
  488. G_fully_qualified_name(cost_layer, cost_mapset));
  489. /* read required maps cost and dtm */
  490. {
  491. int skip_nulls;
  492. double p_dtm, p_cost;
  493. Rast_set_d_null_value(&dnullval, 1);
  494. costs.cost_out = dnullval;
  495. total_cells = nrows * ncols;
  496. skip_nulls = Rast_is_d_null_value(&null_cost);
  497. dtm_dsize = Rast_cell_size(dtm_data_type);
  498. cost_dsize = Rast_cell_size(cost_data_type);
  499. dtm_cell = Rast_allocate_buf(dtm_data_type);
  500. cost_cell = Rast_allocate_buf(cost_data_type);
  501. p_dtm = 0.0;
  502. p_cost = 0.0;
  503. for (row = 0; row < nrows; row++) {
  504. G_percent(row, nrows, 2);
  505. Rast_get_row(dtm_fd, dtm_cell, row, dtm_data_type);
  506. Rast_get_row(cost_fd, cost_cell, row, cost_data_type);
  507. /* INPUT NULL VALUES: ??? */
  508. ptr1 = cost_cell;
  509. ptr2 = dtm_cell;
  510. for (col = 0; col < ncols; col++) {
  511. if (Rast_is_null_value(ptr1, cost_data_type)) {
  512. p_cost = null_cost;
  513. if (skip_nulls) {
  514. total_cells--;
  515. }
  516. }
  517. else {
  518. switch (cost_data_type) {
  519. case CELL_TYPE:
  520. p_cost = *(CELL *)ptr1;
  521. break;
  522. case FCELL_TYPE:
  523. p_cost = *(FCELL *)ptr1;
  524. break;
  525. case DCELL_TYPE:
  526. p_cost = *(DCELL *)ptr1;
  527. break;
  528. }
  529. }
  530. costs.cost_in = p_cost;
  531. if (Rast_is_null_value(ptr2, dtm_data_type)) {
  532. p_dtm = null_cost;
  533. if (skip_nulls && !Rast_is_null_value(ptr1, cost_data_type)) {
  534. total_cells--;
  535. }
  536. }
  537. else {
  538. switch (dtm_data_type) {
  539. case CELL_TYPE:
  540. p_dtm = *(CELL *)ptr2;
  541. break;
  542. case FCELL_TYPE:
  543. p_dtm = *(FCELL *)ptr2;
  544. break;
  545. case DCELL_TYPE:
  546. p_dtm = *(DCELL *)ptr2;
  547. break;
  548. }
  549. }
  550. costs.dtm = p_dtm;
  551. Segment_put(&cost_seg, &costs, row, col);
  552. ptr1 = G_incr_void_ptr(ptr1, cost_dsize);
  553. ptr2 = G_incr_void_ptr(ptr2, dtm_dsize);
  554. }
  555. }
  556. G_free(dtm_cell);
  557. G_free(cost_cell);
  558. G_percent(1, 1, 1);
  559. }
  560. if (dir == 1) {
  561. G_message(_("Initializing directional output..."));
  562. for (row = 0; row < nrows; row++) {
  563. G_percent(row, nrows, 2);
  564. for (col = 0; col < ncols; col++) {
  565. Segment_put(&dir_seg, &dnullval, row, col);
  566. }
  567. }
  568. G_percent(1, 1, 1);
  569. }
  570. /* Scan the existing cum_cost_layer searching for starting points.
  571. * Create a heap of starting points ordered by increasing costs.
  572. */
  573. init_heap();
  574. /* read vector with start points */
  575. if (opt7->answer) {
  576. struct Map_info In;
  577. struct line_pnts *Points;
  578. struct line_cats *Cats;
  579. struct bound_box box;
  580. struct start_pt *new_start_pt;
  581. int type, got_one = 0;
  582. Points = Vect_new_line_struct();
  583. Cats = Vect_new_cats_struct();
  584. Vect_set_open_level(1); /* topology not required */
  585. if (1 > Vect_open_old(&In, opt7->answer, ""))
  586. G_fatal_error(_("Unable to open vector map <%s>"), opt7->answer);
  587. G_message(_("Reading vector map <%s> with start points..."),
  588. Vect_get_full_name(&In));
  589. Vect_rewind(&In);
  590. Vect_region_box(&window, &box);
  591. while (1) {
  592. /* register line */
  593. type = Vect_read_next_line(&In, Points, Cats);
  594. /* Note: check for dead lines is not needed, because they are skipped by V1_read_next_line_nat() */
  595. if (type == -1) {
  596. G_warning(_("Unable to read vector map"));
  597. continue;
  598. }
  599. else if (type == -2) {
  600. break;
  601. }
  602. if (!Vect_point_in_box(Points->x[0], Points->y[0], 0, &box))
  603. continue;
  604. got_one = 1;
  605. col = (int)Rast_easting_to_col(Points->x[0], &window);
  606. row = (int)Rast_northing_to_row(Points->y[0], &window);
  607. new_start_pt =
  608. (struct start_pt *)(G_malloc(sizeof(struct start_pt)));
  609. new_start_pt->row = row;
  610. new_start_pt->col = col;
  611. new_start_pt->next = NULL;
  612. if (head_start_pt == NULL) {
  613. head_start_pt = new_start_pt;
  614. pres_start_pt = new_start_pt;
  615. new_start_pt->next = NULL;
  616. }
  617. else {
  618. pres_start_pt->next = new_start_pt;
  619. pres_start_pt = new_start_pt;
  620. }
  621. }
  622. Vect_close(&In);
  623. if (!got_one)
  624. G_fatal_error(_("No start points found in vector <%s>"), opt7->answer);
  625. }
  626. /* read vector with stop points */
  627. if (opt8->answer) {
  628. struct Map_info In;
  629. struct line_pnts *Points;
  630. struct line_cats *Cats;
  631. struct bound_box box;
  632. struct start_pt *new_start_pt;
  633. int type;
  634. G_message(_("Reading vector map <%s> with stop points..."), opt8->answer);
  635. Points = Vect_new_line_struct();
  636. Cats = Vect_new_cats_struct();
  637. Vect_set_open_level(1); /* topology not required */
  638. if (1 > Vect_open_old(&In, opt8->answer, ""))
  639. G_fatal_error(_("Unable to open vector map <%s>"), opt8->answer);
  640. Vect_rewind(&In);
  641. Vect_region_box(&window, &box);
  642. while (1) {
  643. /* register line */
  644. type = Vect_read_next_line(&In, Points, Cats);
  645. /* Note: check for dead lines is not needed, because they are skipped by V1_read_next_line_nat() */
  646. if (type == -1) {
  647. G_warning(_("Unable to read vector map"));
  648. continue;
  649. }
  650. else if (type == -2) {
  651. break;
  652. }
  653. if (!Vect_point_in_box(Points->x[0], Points->y[0], 0, &box))
  654. continue;
  655. have_stop_points = 1;
  656. col = (int)Rast_easting_to_col(Points->x[0], &window);
  657. row = (int)Rast_northing_to_row(Points->y[0], &window);
  658. new_start_pt =
  659. (struct start_pt *)(G_malloc(sizeof(struct start_pt)));
  660. new_start_pt->row = row;
  661. new_start_pt->col = col;
  662. new_start_pt->next = NULL;
  663. if (head_end_pt == NULL) {
  664. head_end_pt = new_start_pt;
  665. pres_stop_pt = new_start_pt;
  666. new_start_pt->next = NULL;
  667. }
  668. else {
  669. pres_stop_pt->next = new_start_pt;
  670. pres_stop_pt = new_start_pt;
  671. }
  672. }
  673. Vect_close(&In);
  674. if (!have_stop_points)
  675. G_fatal_error(_("No stop points found in vector <%s>"), opt8->answer);
  676. }
  677. /* read raster with start points */
  678. if (opt9->answer) {
  679. int dsize2;
  680. int fd;
  681. RASTER_MAP_TYPE data_type2;
  682. int got_one = 0;
  683. search_mapset = G_find_raster(opt9->answer, "");
  684. if (search_mapset == NULL)
  685. G_fatal_error(_("Raster map <%s> not found"), opt9->answer);
  686. fd = Rast_open_old(opt9->answer, "");
  687. data_type2 = Rast_get_map_type(fd);
  688. dsize2 = Rast_cell_size(data_type2);
  689. cell2 = Rast_allocate_buf(data_type2);
  690. if (!cell2)
  691. G_fatal_error(_("Unable to allocate memory"));
  692. G_message(_("Reading raster map <%s> with start points..."), opt9->answer);
  693. for (row = 0; row < nrows; row++) {
  694. G_percent(row, nrows, 2);
  695. Rast_get_row(fd, cell2, row, data_type2);
  696. ptr2 = cell2;
  697. for (col = 0; col < ncols; col++) {
  698. /* Did I understand that concept of cumulative cost map? - (pmx) 12 april 2000 */
  699. if (!Rast_is_null_value(ptr2, data_type2)) {
  700. double cellval;
  701. Segment_get(&cost_seg, &costs, row, col);
  702. if (start_with_raster_vals == 1) {
  703. cellval = Rast_get_d_value(ptr2, data_type2);
  704. insert(cellval, row, col);
  705. costs.cost_out = cellval;
  706. Segment_put(&cost_seg, &costs, row, col);
  707. }
  708. else {
  709. value = &zero;
  710. insert(zero, row, col);
  711. costs.cost_out = *value;
  712. Segment_put(&cost_seg, &costs, row, col);
  713. }
  714. got_one = 1;
  715. }
  716. ptr2 = G_incr_void_ptr(ptr2, dsize2);
  717. }
  718. }
  719. G_percent(1, 1, 1);
  720. Rast_close(fd);
  721. G_free(cell2);
  722. if (!got_one)
  723. G_fatal_error(_("No start points"));
  724. }
  725. /* If the starting points are given on the command line start a linked
  726. * list of cells ordered by increasing costs
  727. */
  728. if (head_start_pt) {
  729. struct start_pt *top_start_pt = NULL;
  730. top_start_pt = head_start_pt;
  731. while (top_start_pt != NULL) {
  732. value = &zero;
  733. if (top_start_pt->row < 0 || top_start_pt->row >= nrows
  734. || top_start_pt->col < 0 || top_start_pt->col >= ncols)
  735. G_fatal_error(_("Specified starting location outside database window"));
  736. insert(zero, top_start_pt->row, top_start_pt->col);
  737. Segment_get(&cost_seg, &costs, top_start_pt->row,
  738. top_start_pt->col);
  739. costs.cost_out = *value;
  740. Segment_put(&cost_seg, &costs, top_start_pt->row,
  741. top_start_pt->col);
  742. top_start_pt = top_start_pt->next;
  743. }
  744. }
  745. /* Loop through the heap and perform at each cell the following:
  746. * 1) If an adjacent cell has not already been assigned a value compute
  747. * the min cost and assign it.
  748. * 2) Insert the adjacent cell in the heap.
  749. * 3) Free the memory allocated to the present cell.
  750. */
  751. G_debug(1, "total cells: %ld", total_cells);
  752. G_debug(1, "nrows x ncols: %d", nrows * ncols);
  753. G_message(_("Finding cost path..."));
  754. n_processed = 0;
  755. pres_cell = get_lowest();
  756. while (pres_cell != NULL) {
  757. struct cost *ct;
  758. double N_dtm, NE_dtm, E_dtm, SE_dtm, S_dtm, SW_dtm, W_dtm, NW_dtm;
  759. double NNE_dtm, ENE_dtm, ESE_dtm, SSE_dtm, SSW_dtm, WSW_dtm, WNW_dtm,
  760. NNW_dtm;
  761. double N_cost, NE_cost, E_cost, SE_cost, S_cost, SW_cost, W_cost,
  762. NW_cost;
  763. double NNE_cost, ENE_cost, ESE_cost, SSE_cost, SSW_cost, WSW_cost,
  764. WNW_cost, NNW_cost;
  765. N_dtm = NE_dtm = E_dtm = SE_dtm = S_dtm = SW_dtm = W_dtm = NW_dtm = dnullval;
  766. NNE_dtm = ENE_dtm = ESE_dtm = SSE_dtm = SSW_dtm = WSW_dtm = WNW_dtm = NNW_dtm = dnullval;
  767. N_cost = NE_cost = E_cost = SE_cost = S_cost = SW_cost = W_cost = NW_cost = dnullval;
  768. NNE_cost = ENE_cost = ESE_cost = SSE_cost = SSW_cost = WSW_cost = WNW_cost = NNW_cost = dnullval;
  769. /* If we have surpassed the user specified maximum cost, then quit */
  770. if (maxcost && ((double)maxcost < pres_cell->min_cost))
  771. break;
  772. /* If I've already been updated, delete me */
  773. Segment_get(&cost_seg, &costs, pres_cell->row, pres_cell->col);
  774. old_min_cost = costs.cost_out;
  775. if (!Rast_is_d_null_value(&old_min_cost)) {
  776. if (pres_cell->min_cost > old_min_cost) {
  777. delete(pres_cell);
  778. pres_cell = get_lowest();
  779. continue;
  780. }
  781. }
  782. my_dtm = costs.dtm;
  783. if (Rast_is_d_null_value(&my_dtm)) {
  784. delete(pres_cell);
  785. pres_cell = get_lowest();
  786. continue;
  787. }
  788. my_cost = costs.cost_in;
  789. if (Rast_is_d_null_value(&my_cost)) {
  790. delete(pres_cell);
  791. pres_cell = get_lowest();
  792. continue;
  793. }
  794. row = pres_cell->row;
  795. col = pres_cell->col;
  796. G_percent(n_processed++, total_cells, 1);
  797. /* 9 10 Order in which neighbors
  798. * 13 5 3 6 14 are visited (Knight move).
  799. * 1 2
  800. * 16 8 4 7 15
  801. * 12 11
  802. */
  803. /* drainage directions in degrees CCW from East
  804. * drainage directions are set for each neighbor and must be
  805. * read as from neighbor to current cell
  806. *
  807. * X = neighbor:
  808. *
  809. * 112.5 67.5
  810. * 157.5 135 90 45 22.5
  811. * 180 X 360
  812. * 202.5 225 270 315 337.5
  813. * 247.5 292.5
  814. *
  815. * X = present cell, directions for neighbors:
  816. *
  817. * 292.5 247.5
  818. * 337.5 315 270 225 202.5
  819. * 360 X 180
  820. * 22.5 45 90 135 157.5
  821. * 67.5 112.5
  822. */
  823. for (neighbor = 1; neighbor <= total_reviewed; neighbor++) {
  824. switch (neighbor) {
  825. case 1:
  826. col = pres_cell->col - 1;
  827. cur_dir = 360.0;
  828. break;
  829. case 2:
  830. col = pres_cell->col + 1;
  831. cur_dir = 180.0;
  832. break;
  833. case 3:
  834. row = pres_cell->row - 1;
  835. col = pres_cell->col;
  836. cur_dir = 270.0;
  837. break;
  838. case 4:
  839. row = pres_cell->row + 1;
  840. cur_dir = 90.0;
  841. break;
  842. case 5:
  843. row = pres_cell->row - 1;
  844. col = pres_cell->col - 1;
  845. cur_dir = 315.0;
  846. break;
  847. case 6:
  848. col = pres_cell->col + 1;
  849. cur_dir = 225.0;
  850. break;
  851. case 7:
  852. row = pres_cell->row + 1;
  853. cur_dir = 135.0;
  854. break;
  855. case 8:
  856. col = pres_cell->col - 1;
  857. cur_dir = 45.0;
  858. break;
  859. case 9:
  860. row = pres_cell->row - 2;
  861. col = pres_cell->col - 1;
  862. cur_dir = 292.5;
  863. break;
  864. case 10:
  865. col = pres_cell->col + 1;
  866. cur_dir = 247.5;
  867. break;
  868. case 11:
  869. row = pres_cell->row + 2;
  870. cur_dir = 112.5;
  871. break;
  872. case 12:
  873. col = pres_cell->col - 1;
  874. cur_dir = 67.5;
  875. break;
  876. case 13:
  877. row = pres_cell->row - 1;
  878. col = pres_cell->col - 2;
  879. cur_dir = 337.5;
  880. break;
  881. case 14:
  882. col = pres_cell->col + 2;
  883. cur_dir = 202.5;
  884. break;
  885. case 15:
  886. row = pres_cell->row + 1;
  887. cur_dir = 157.5;
  888. break;
  889. case 16:
  890. col = pres_cell->col - 2;
  891. cur_dir = 22.5;
  892. break;
  893. }
  894. if (row < 0 || row >= nrows)
  895. continue;
  896. if (col < 0 || col >= ncols)
  897. continue;
  898. min_cost = dnullval;
  899. Segment_get(&cost_seg, &costs, row, col);
  900. switch (neighbor) {
  901. case 1:
  902. W_dtm = costs.dtm;
  903. W_cost = costs.cost_in;
  904. if (Rast_is_d_null_value(&W_cost))
  905. continue;
  906. check_dtm = (W_dtm - my_dtm) / EW_fac;
  907. if (check_dtm >= 0)
  908. fcost_dtm = (double)(W_dtm - my_dtm) * b;
  909. else if (check_dtm < (slope_factor))
  910. fcost_dtm = (double)(W_dtm - my_dtm) * d;
  911. else
  912. fcost_dtm = (double)(W_dtm - my_dtm) * c;
  913. fcost_cost = (double)(W_cost + my_cost) / 2.0;
  914. min_cost =
  915. pres_cell->min_cost + fcost_dtm + (EW_fac * a) +
  916. lambda * fcost_cost * EW_fac;
  917. break;
  918. case 2:
  919. E_dtm = costs.dtm;
  920. E_cost = costs.cost_in;
  921. if (Rast_is_d_null_value(&E_cost))
  922. continue;
  923. check_dtm = (E_dtm - my_dtm) / EW_fac;
  924. if (check_dtm >= 0)
  925. fcost_dtm = (double)(E_dtm - my_dtm) * b;
  926. else if (check_dtm < (slope_factor))
  927. fcost_dtm = (double)(E_dtm - my_dtm) * d;
  928. else
  929. fcost_dtm = (double)(E_dtm - my_dtm) * c;
  930. fcost_cost = (double)(E_cost + my_cost) / 2.0;
  931. min_cost =
  932. pres_cell->min_cost + fcost_dtm + (EW_fac * a) +
  933. lambda * fcost_cost * EW_fac;
  934. break;
  935. case 3:
  936. N_dtm = costs.dtm;
  937. N_cost = costs.cost_in;
  938. if (Rast_is_d_null_value(&N_cost))
  939. continue;
  940. check_dtm = (N_dtm - my_dtm) / NS_fac;
  941. if (check_dtm >= 0)
  942. fcost_dtm = (double)(N_dtm - my_dtm) * b;
  943. else if (check_dtm < (slope_factor))
  944. fcost_dtm = (double)(N_dtm - my_dtm) * d;
  945. else
  946. fcost_dtm = (double)(N_dtm - my_dtm) * c;
  947. fcost_cost = (double)(N_cost + my_cost) / 2.0;
  948. min_cost =
  949. pres_cell->min_cost + fcost_dtm + (NS_fac * a) +
  950. lambda * fcost_cost * NS_fac;
  951. break;
  952. case 4:
  953. S_dtm = costs.dtm;
  954. S_cost = costs.cost_in;
  955. if (Rast_is_d_null_value(&S_cost))
  956. continue;
  957. check_dtm = (S_dtm - my_dtm) / NS_fac;
  958. if (check_dtm >= 0)
  959. fcost_dtm = (double)(S_dtm - my_dtm) * b;
  960. else if (check_dtm < (slope_factor))
  961. fcost_dtm = (double)(S_dtm - my_dtm) * d;
  962. else
  963. fcost_dtm = (double)(S_dtm - my_dtm) * c;
  964. fcost_cost = (double)(S_cost + my_cost) / 2.0;
  965. min_cost =
  966. pres_cell->min_cost + fcost_dtm + (NS_fac * a) +
  967. lambda * fcost_cost * NS_fac;
  968. break;
  969. case 5:
  970. NW_dtm = costs.dtm;
  971. NW_cost = costs.cost_in;
  972. if (Rast_is_d_null_value(&NW_cost))
  973. continue;
  974. check_dtm = (NW_dtm - my_dtm) / DIAG_fac;
  975. if (check_dtm >= 0)
  976. fcost_dtm = (double)(NW_dtm - my_dtm) * b;
  977. else if (check_dtm < (slope_factor))
  978. fcost_dtm = (double)(NW_dtm - my_dtm) * d;
  979. else
  980. fcost_dtm = (double)(NW_dtm - my_dtm) * c;
  981. fcost_cost = (double)(NW_cost + my_cost) / 2.0;
  982. min_cost =
  983. pres_cell->min_cost + fcost_dtm + (DIAG_fac * a) +
  984. lambda * fcost_cost * DIAG_fac;
  985. break;
  986. case 6:
  987. NE_dtm = costs.dtm;
  988. NE_cost = costs.cost_in;
  989. if (Rast_is_d_null_value(&NE_cost))
  990. continue;
  991. check_dtm = (NE_dtm - my_dtm) / DIAG_fac;
  992. if (check_dtm >= 0)
  993. fcost_dtm = (double)(NE_dtm - my_dtm) * b;
  994. else if (check_dtm < (slope_factor))
  995. fcost_dtm = (double)(NE_dtm - my_dtm) * d;
  996. else
  997. fcost_dtm = (double)(NE_dtm - my_dtm) * c;
  998. fcost_cost = (double)(NE_cost + my_cost) / 2.0;
  999. min_cost =
  1000. pres_cell->min_cost + fcost_dtm + (DIAG_fac * a) +
  1001. lambda * fcost_cost * DIAG_fac;
  1002. break;
  1003. case 7:
  1004. SE_dtm = costs.dtm;
  1005. SE_cost = costs.cost_in;
  1006. if (Rast_is_d_null_value(&SE_cost))
  1007. continue;
  1008. check_dtm = (SE_dtm - my_dtm) / DIAG_fac;
  1009. if (check_dtm >= 0)
  1010. fcost_dtm = (double)(SE_dtm - my_dtm) * b;
  1011. else if (check_dtm < (slope_factor))
  1012. fcost_dtm = (double)(SE_dtm - my_dtm) * d;
  1013. else
  1014. fcost_dtm = (double)(SE_dtm - my_dtm) * c;
  1015. fcost_cost = (double)(SE_cost + my_cost) / 2.0;
  1016. min_cost =
  1017. pres_cell->min_cost + fcost_dtm + (DIAG_fac * a) +
  1018. lambda * fcost_cost * DIAG_fac;
  1019. break;
  1020. case 8:
  1021. SW_dtm = costs.dtm;
  1022. SW_cost = costs.cost_in;
  1023. if (Rast_is_d_null_value(&SW_cost))
  1024. continue;
  1025. check_dtm = (SW_dtm - my_dtm) / DIAG_fac;
  1026. if (check_dtm >= 0)
  1027. fcost_dtm = (double)(SW_dtm - my_dtm) * b;
  1028. else if (check_dtm < (slope_factor))
  1029. fcost_dtm = (double)(SW_dtm - my_dtm) * d;
  1030. else
  1031. fcost_dtm = (double)(SW_dtm - my_dtm) * c;
  1032. fcost_cost = (double)(SW_cost + my_cost) / 2.0;
  1033. min_cost =
  1034. pres_cell->min_cost + fcost_dtm + (DIAG_fac * a) +
  1035. lambda * fcost_cost * DIAG_fac;
  1036. break;
  1037. case 9:
  1038. NNW_dtm = costs.dtm;
  1039. NNW_cost = costs.cost_in;
  1040. if (Rast_is_d_null_value(&NNW_cost))
  1041. continue;
  1042. check_dtm = (NNW_dtm - my_dtm) / V_DIAG_fac;
  1043. if (check_dtm >= 0)
  1044. fcost_dtm = (double)(NNW_dtm - my_dtm) * b;
  1045. else if (check_dtm < (slope_factor))
  1046. fcost_dtm = (double)(NNW_dtm - my_dtm) * d;
  1047. else
  1048. fcost_dtm = (double)(NNW_dtm - my_dtm) * c;
  1049. fcost_cost =
  1050. (double)(N_cost + NW_cost + NNW_cost + my_cost) / 4.0;
  1051. min_cost =
  1052. pres_cell->min_cost + fcost_dtm + (V_DIAG_fac * a) +
  1053. lambda * fcost_cost * V_DIAG_fac;
  1054. break;
  1055. case 10:
  1056. NNE_dtm = costs.dtm;
  1057. NNE_cost = costs.cost_in;
  1058. if (Rast_is_d_null_value(&NNE_cost))
  1059. continue;
  1060. check_dtm = ((NNE_dtm - my_dtm) / V_DIAG_fac);
  1061. if (check_dtm >= 0)
  1062. fcost_dtm = (double)(NNE_dtm - my_dtm) * b;
  1063. else if (check_dtm < (slope_factor))
  1064. fcost_dtm = (double)(NNE_dtm - my_dtm) * d;
  1065. else
  1066. fcost_dtm = (double)(NNE_dtm - my_dtm) * c;
  1067. fcost_cost =
  1068. (double)(N_cost + NE_cost + NNE_cost + my_cost) / 4.0;
  1069. min_cost =
  1070. pres_cell->min_cost + fcost_dtm + (V_DIAG_fac * a) +
  1071. lambda * fcost_cost * V_DIAG_fac;
  1072. break;
  1073. case 11:
  1074. SSE_dtm = costs.dtm;
  1075. SSE_cost = costs.cost_in;
  1076. if (Rast_is_d_null_value(&SSE_cost))
  1077. continue;
  1078. check_dtm = (SSE_dtm - my_dtm) / V_DIAG_fac;
  1079. if (check_dtm >= 0)
  1080. fcost_dtm = (double)(SSE_dtm - my_dtm) * b;
  1081. else if (check_dtm < (slope_factor))
  1082. fcost_dtm = (double)(SSE_dtm - my_dtm) * d;
  1083. else
  1084. fcost_dtm = (double)(SSE_dtm - my_dtm) * c;
  1085. fcost_cost =
  1086. (double)(S_cost + SE_cost + SSE_cost + my_cost) / 4.0;
  1087. min_cost =
  1088. pres_cell->min_cost + fcost_dtm + (V_DIAG_fac * a) +
  1089. lambda * fcost_cost * V_DIAG_fac;
  1090. break;
  1091. case 12:
  1092. SSW_dtm = costs.dtm;
  1093. SSW_cost = costs.cost_in;
  1094. if (Rast_is_d_null_value(&SSW_cost))
  1095. continue;
  1096. check_dtm = (SSW_dtm - my_dtm) / V_DIAG_fac;
  1097. if (check_dtm >= 0)
  1098. fcost_dtm = (double)(SSW_dtm - my_dtm) * b;
  1099. else if (check_dtm < (slope_factor))
  1100. fcost_dtm = (double)(SSW_dtm - my_dtm) * d;
  1101. else
  1102. fcost_dtm = (double)(SSW_dtm - my_dtm) * c;
  1103. fcost_cost =
  1104. (double)(S_cost + SW_cost + SSW_cost + my_cost) / 4.0;
  1105. min_cost =
  1106. pres_cell->min_cost + fcost_dtm + (V_DIAG_fac * a) +
  1107. lambda * fcost_cost * V_DIAG_fac;
  1108. break;
  1109. case 13:
  1110. WNW_dtm = costs.dtm;
  1111. WNW_cost = costs.cost_in;
  1112. if (Rast_is_d_null_value(&WNW_cost))
  1113. continue;
  1114. check_dtm = (WNW_dtm - my_dtm) / H_DIAG_fac;
  1115. if (check_dtm >= 0)
  1116. fcost_dtm = (double)(WNW_dtm - my_dtm) * b;
  1117. else if (check_dtm < (slope_factor))
  1118. fcost_dtm = (double)(WNW_dtm - my_dtm) * d;
  1119. else
  1120. fcost_dtm = (double)(WNW_dtm - my_dtm) * c;
  1121. fcost_cost =
  1122. (double)(W_cost + NW_cost + WNW_cost + my_cost) / 4.0;
  1123. min_cost =
  1124. pres_cell->min_cost + fcost_dtm + (H_DIAG_fac * a) +
  1125. lambda * fcost_cost * H_DIAG_fac;
  1126. break;
  1127. case 14:
  1128. ENE_dtm = costs.dtm;
  1129. ENE_cost = costs.cost_in;
  1130. if (Rast_is_d_null_value(&ENE_cost))
  1131. continue;
  1132. check_dtm = (ENE_dtm - my_dtm) / H_DIAG_fac;
  1133. if (check_dtm >= 0)
  1134. fcost_dtm = (double)(ENE_dtm - my_dtm) * b;
  1135. else if (check_dtm < (slope_factor))
  1136. fcost_dtm = (double)(ENE_dtm - my_dtm) * d;
  1137. else
  1138. fcost_dtm = (double)(ENE_dtm - my_dtm) * c;
  1139. fcost_cost =
  1140. (double)(E_cost + NE_cost + ENE_cost + my_cost) / 4.0;
  1141. min_cost =
  1142. pres_cell->min_cost + fcost_dtm + (H_DIAG_fac * a) +
  1143. lambda * fcost_cost * H_DIAG_fac;
  1144. break;
  1145. case 15:
  1146. ESE_dtm = costs.dtm;
  1147. ESE_cost = costs.cost_in;
  1148. if (Rast_is_d_null_value(&ESE_cost))
  1149. continue;
  1150. check_dtm = (ESE_dtm - my_dtm) / H_DIAG_fac;
  1151. if (check_dtm >= 0)
  1152. fcost_dtm = (double)(ESE_dtm - my_dtm) * b;
  1153. else if (check_dtm < (slope_factor))
  1154. fcost_dtm = (double)(ESE_dtm - my_dtm) * d;
  1155. else
  1156. fcost_dtm = (double)(ESE_dtm - my_dtm) * c;
  1157. fcost_cost =
  1158. (double)(E_cost + SE_cost + ESE_cost + my_cost) / 4.0;
  1159. min_cost =
  1160. pres_cell->min_cost + fcost_dtm + (H_DIAG_fac * a) +
  1161. lambda * fcost_cost * H_DIAG_fac;
  1162. break;
  1163. case 16:
  1164. WSW_dtm = costs.dtm;
  1165. WSW_cost = costs.cost_in;
  1166. if (Rast_is_d_null_value(&WSW_cost))
  1167. continue;
  1168. check_dtm = (WSW_dtm - my_dtm) / H_DIAG_fac;
  1169. if (check_dtm >= 0)
  1170. fcost_dtm = (double)(WSW_dtm - my_dtm) * b;
  1171. else if (check_dtm < (slope_factor))
  1172. fcost_dtm = (double)(WSW_dtm - my_dtm) * d;
  1173. else
  1174. fcost_dtm = (double)(WSW_dtm - my_dtm) * c;
  1175. fcost_cost =
  1176. (double)(W_cost + SW_cost + WSW_cost + my_cost) / 4.0;
  1177. min_cost =
  1178. pres_cell->min_cost + fcost_dtm + (H_DIAG_fac * a) +
  1179. lambda * fcost_cost * H_DIAG_fac;
  1180. break;
  1181. }
  1182. if (Rast_is_d_null_value(&min_cost))
  1183. continue;
  1184. Segment_get(&cost_seg, &costs, row, col);
  1185. old_min_cost = costs.cost_out;
  1186. /* add to list */
  1187. if (Rast_is_d_null_value(&old_min_cost)) {
  1188. costs.cost_out = min_cost;
  1189. Segment_put(&cost_seg, &costs, row, col);
  1190. insert(min_cost, row, col);
  1191. if (dir == 1) {
  1192. Segment_put(&dir_seg, &cur_dir, row, col);
  1193. }
  1194. }
  1195. /* update with lower costs */
  1196. else if (old_min_cost > min_cost) {
  1197. costs.cost_out = min_cost;
  1198. Segment_put(&cost_seg, &costs, row, col);
  1199. insert(min_cost, row, col);
  1200. if (dir == 1) {
  1201. Segment_put(&dir_seg, &cur_dir, row, col);
  1202. }
  1203. }
  1204. }
  1205. if (have_stop_points && time_to_stop(pres_cell->row, pres_cell->col))
  1206. break;
  1207. ct = pres_cell;
  1208. delete(pres_cell);
  1209. pres_cell = get_lowest();
  1210. if (ct == pres_cell)
  1211. G_warning(_("Error, ct == pres_cell"));
  1212. }
  1213. G_percent(1, 1, 1);
  1214. /* free heap */
  1215. free_heap();
  1216. /* Open cumulative cost layer for writing */
  1217. cum_fd = Rast_open_new(cum_cost_layer, cum_data_type);
  1218. cum_cell = Rast_allocate_buf(cum_data_type);
  1219. /* Copy segmented map to output map */
  1220. G_message(_("Writing output raster map <%s>... "), cum_cost_layer);
  1221. cell2 = Rast_allocate_buf(dtm_data_type);
  1222. {
  1223. void *p;
  1224. void *p2;
  1225. int cum_dsize = Rast_cell_size(cum_data_type);
  1226. Rast_set_null_value(cell2, ncols, dtm_data_type);
  1227. for (row = 0; row < nrows; row++) {
  1228. G_percent(row, nrows, 2);
  1229. if (keep_nulls)
  1230. Rast_get_row(dtm_fd, cell2, row, dtm_data_type);
  1231. p = cum_cell;
  1232. p2 = cell2;
  1233. for (col = 0; col < ncols; col++) {
  1234. if (keep_nulls) {
  1235. if (Rast_is_null_value(p2, dtm_data_type)) {
  1236. Rast_set_null_value(p, 1, cum_data_type);
  1237. p = G_incr_void_ptr(p, cum_dsize);
  1238. p2 = G_incr_void_ptr(p2, dtm_dsize);
  1239. continue;
  1240. }
  1241. }
  1242. Segment_get(&cost_seg, &costs, row, col);
  1243. min_cost = costs.cost_out;
  1244. if (Rast_is_d_null_value(&min_cost)) {
  1245. Rast_set_null_value((p), 1, cum_data_type);
  1246. }
  1247. else {
  1248. if (min_cost > peak)
  1249. peak = min_cost;
  1250. switch (cum_data_type) {
  1251. case CELL_TYPE:
  1252. *(CELL *)p = (CELL)(min_cost + .5);
  1253. break;
  1254. case FCELL_TYPE:
  1255. *(FCELL *)p = (FCELL)(min_cost);
  1256. break;
  1257. case DCELL_TYPE:
  1258. *(DCELL *)p = (DCELL)(min_cost);
  1259. break;
  1260. }
  1261. }
  1262. p = G_incr_void_ptr(p, cum_dsize);
  1263. p2 = G_incr_void_ptr(p2, dtm_dsize);
  1264. }
  1265. Rast_put_row(cum_fd, cum_cell, cum_data_type);
  1266. }
  1267. G_percent(1, 1, 1);
  1268. G_free(cum_cell);
  1269. G_free(cell2);
  1270. }
  1271. if (dir == 1) {
  1272. void *p;
  1273. size_t dir_size = Rast_cell_size(dir_data_type);
  1274. dir_fd = Rast_open_new(move_dir_layer, dir_data_type);
  1275. dir_cell = Rast_allocate_buf(dir_data_type);
  1276. G_message(_("Writing output movement direction raster map <%s>..."), move_dir_layer);
  1277. for (row = 0; row < nrows; row++) {
  1278. p = dir_cell;
  1279. for (col = 0; col < ncols; col++) {
  1280. Segment_get(&dir_seg, &cur_dir, row, col);
  1281. *((FCELL *) p) = cur_dir;
  1282. p = G_incr_void_ptr(p, dir_size);
  1283. }
  1284. Rast_put_row(dir_fd, dir_cell, dir_data_type);
  1285. G_percent(row, nrows, 2);
  1286. }
  1287. G_percent(1, 1, 1);
  1288. G_free(dir_cell);
  1289. }
  1290. Segment_close(&cost_seg); /* release memory */
  1291. if (dir == 1)
  1292. Segment_close(&dir_seg);
  1293. Rast_close(dtm_fd);
  1294. Rast_close(cost_fd);
  1295. Rast_close(cum_fd);
  1296. if (dir == 1)
  1297. Rast_close(dir_fd);
  1298. /* writing history file */
  1299. Rast_short_history(cum_cost_layer, "raster", &history);
  1300. Rast_command_history(&history);
  1301. Rast_write_history(cum_cost_layer, &history);
  1302. if (dir == 1) {
  1303. Rast_short_history(move_dir_layer, "raster", &history);
  1304. Rast_command_history(&history);
  1305. Rast_write_history(move_dir_layer, &history);
  1306. }
  1307. /* Create colours for output map */
  1308. /*
  1309. * Rast_read_range (cum_cost_layer, "", &range);
  1310. * Rast_get_range_min_max(&range, &min, &max);
  1311. * G_make_color_wave(&colors,min, max);
  1312. * Rast_write_colors (cum_cost_layer,"",&colors);
  1313. */
  1314. G_done_msg(_("Peak cost value: %g"), peak);
  1315. exit(EXIT_SUCCESS);
  1316. }
  1317. int
  1318. process_answers(char **answers, struct start_pt **points,
  1319. struct start_pt **top_start_pt)
  1320. {
  1321. int col, row;
  1322. double east, north;
  1323. struct start_pt *new_start_pt;
  1324. int got_one = 0;
  1325. *points = NULL;
  1326. if (!answers)
  1327. return (0);
  1328. for (; *answers != NULL; answers += 2) {
  1329. if (!G_scan_easting(*answers, &east, G_projection()))
  1330. G_fatal_error(_("Illegal x coordinate <%s>"), *answers);
  1331. if (!G_scan_northing(*(answers + 1), &north, G_projection()))
  1332. G_fatal_error(_("Illegal y coordinate <%s>"), *(answers + 1));
  1333. if (east < window.west || east > window.east ||
  1334. north < window.south || north > window.north) {
  1335. G_warning(_("Warning, ignoring point outside window: %g, %g"),
  1336. east, north);
  1337. continue;
  1338. }
  1339. else
  1340. got_one = 1;
  1341. row = (window.north - north) / window.ns_res;
  1342. col = (east - window.west) / window.ew_res;
  1343. new_start_pt = (struct start_pt *)(G_malloc(sizeof(struct start_pt)));
  1344. new_start_pt->row = row;
  1345. new_start_pt->col = col;
  1346. new_start_pt->next = NULL;
  1347. if (*points == NULL) {
  1348. *points = new_start_pt;
  1349. *top_start_pt = new_start_pt;
  1350. new_start_pt->next = NULL;
  1351. }
  1352. else {
  1353. (*top_start_pt)->next = new_start_pt;
  1354. *top_start_pt = new_start_pt;
  1355. }
  1356. }
  1357. return (got_one);
  1358. }
  1359. int time_to_stop(int row, int col)
  1360. {
  1361. static int total = 0;
  1362. static int hits = 0;
  1363. struct start_pt *points;
  1364. if (total == 0) {
  1365. for (points = head_end_pt;
  1366. points != NULL; points = points->next, total++) ;
  1367. }
  1368. for (points = head_end_pt; points != NULL; points = points->next)
  1369. if (points->row == row && points->col == col) {
  1370. hits++;
  1371. if (hits == total)
  1372. return (1);
  1373. }
  1374. return (0);
  1375. }