main.c 56 KB

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