main.c 46 KB

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