main.c 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285
  1. /****************************************************************************
  2. *
  3. * MODULE: r.cost
  4. *
  5. * AUTHOR(S): Antony Awaida - IESL - M.I.T.
  6. * James Westervelt - CERL
  7. * Pierre de Mouveaux <pmx audiovu com>
  8. * Eric G. Miller <egm2 jps net>
  9. *
  10. * Updated for calculation errors and directional surface generation
  11. * Colin Nielsen <colin.nielsen gmail com>
  12. * Use min heap instead of btree (faster, less memory)
  13. * Markus Metz
  14. *
  15. * PURPOSE: Outputs a raster map layer showing the cumulative cost
  16. * of moving between different geographic locations on an
  17. * input raster map layer whose cell category values
  18. * represent cost.
  19. *
  20. * COPYRIGHT: (C) 2006-2009 by the GRASS Development Team
  21. *
  22. * This program is free software under the GNU General Public
  23. * License (>=v2). Read the file COPYING that comes with GRASS
  24. * for details.
  25. *
  26. ***************************************************************************/
  27. /*********************************************************************
  28. *
  29. * This is the main program for the minimum path cost analysis.
  30. * It generates a cumulative cost map (output) from an elevation
  31. * or cost map (input) with respect to starting locations (coor).
  32. *
  33. * It takes as input the following:
  34. * 1) Cost of traversing each grid cell as given by a cost map
  35. * cell (input).
  36. * 2) If starting points are not specified on the command line
  37. * then the output map must exist and contain the starting locations
  38. *
  39. * Otherwise the output map need not exist and the coor points
  40. * from the command line are used.
  41. *
  42. *********************************************************************/
  43. /* BUG 2005: r.cost probably hangs with negative costs.
  44. * Positive costs could be a condition for Dijkstra search? MM
  45. *
  46. * 08 april 2000 - Pierre de Mouveaux. pmx@audiovu.com
  47. * Updated to use the Grass 5.0 floating point raster cell format.
  48. *
  49. * 12 dec 2001 - Eric G. Miller <egm2@jps.net>
  50. * Try to fix some file searching bugs, and give better error
  51. * if "output" doesn't exist, but is expected (this is bad design).
  52. */
  53. /* TODO
  54. * use Vect_*() functions
  55. * use search tree for stop points
  56. * re-organize and clean up code for better readability
  57. * compartmentalize code, start with putting Dijkstra search into a separate function
  58. */
  59. #include <stdlib.h>
  60. #include <unistd.h>
  61. #include <string.h>
  62. #include <math.h>
  63. #include <sys/types.h>
  64. #include <sys/stat.h>
  65. #include <fcntl.h>
  66. #include <grass/gis.h>
  67. #include <grass/raster.h>
  68. #include <grass/vector.h>
  69. #include <grass/segment.h>
  70. #include <grass/glocale.h>
  71. #include "cost.h"
  72. #include "stash.h"
  73. #define SEGCOLSIZE 64
  74. struct Cell_head window;
  75. struct start_pt *head_start_pt = NULL;
  76. struct start_pt *head_end_pt = NULL;
  77. int main(int argc, char *argv[])
  78. {
  79. const char *cum_cost_layer, *move_dir_layer, *nearest_layer;
  80. const char *cost_layer;
  81. const char *cost_mapset, *search_mapset;
  82. void *cell, *cell2, *dir_cell, *nearest_cell;
  83. SEGMENT cost_seg, dir_seg;
  84. double *value;
  85. extern struct Cell_head window;
  86. double NS_fac, EW_fac, DIAG_fac, H_DIAG_fac, V_DIAG_fac;
  87. double fcost;
  88. double min_cost, old_min_cost;
  89. FCELL cur_dir;
  90. double zero = 0.0;
  91. int col, row, nrows, ncols;
  92. int maxcost;
  93. int nseg;
  94. int maxmem;
  95. int segments_in_memory;
  96. int cost_fd, cum_fd, dir_fd, nearest_fd;
  97. int have_stop_points = FALSE, dir = FALSE;
  98. double my_cost, nearest;
  99. double null_cost, dnullval;
  100. int srows, scols;
  101. int total_reviewed;
  102. int keep_nulls = 1;
  103. int start_with_raster_vals = 1;
  104. int neighbor;
  105. long n_processed = 0;
  106. long total_cells;
  107. struct GModule *module;
  108. struct Flag *flag2, *flag3, *flag4, *flag5;
  109. struct Option *opt1, *opt2, *opt3, *opt4, *opt5, *opt6, *opt7, *opt8;
  110. struct Option *opt9, *opt10, *opt11, *opt12;
  111. struct cost *pres_cell;
  112. struct start_pt *pres_start_pt = NULL;
  113. struct start_pt *pres_stop_pt = NULL;
  114. struct cc {
  115. double cost_in, cost_out, nearest;
  116. } costs;
  117. void *ptr2;
  118. RASTER_MAP_TYPE data_type, /* input cost type */
  119. cum_data_type = DCELL_TYPE, /* output cumulative cost type */
  120. dir_data_type = FCELL_TYPE, /* output direction type */
  121. nearest_data_type = CELL_TYPE; /* output nearest type */
  122. struct History history;
  123. double peak = 0.0;
  124. int dsize, nearest_size;
  125. double disk_mb, mem_mb;
  126. G_gisinit(argv[0]);
  127. module = G_define_module();
  128. G_add_keyword(_("raster"));
  129. G_add_keyword(_("cost surface"));
  130. G_add_keyword(_("cumulative costs"));
  131. G_add_keyword(_("cost allocation"));
  132. module->description =
  133. _("Creates a raster map showing the "
  134. "cumulative cost of moving between different "
  135. "geographic locations on an input raster map "
  136. "whose cell category values represent cost.");
  137. opt2 = G_define_standard_option(G_OPT_R_INPUT);
  138. opt2->description =
  139. _("Name of input raster map containing grid cell cost information");
  140. opt1 = G_define_standard_option(G_OPT_R_OUTPUT);
  141. opt12 = G_define_standard_option(G_OPT_R_OUTPUT);
  142. opt12->key = "nearest";
  143. opt12->required = NO;
  144. opt12->description =
  145. _("Name for output raster map with nearest start point");
  146. opt12->guisection = _("Optional outputs");
  147. opt11 = G_define_standard_option(G_OPT_R_OUTPUT);
  148. opt11->key = "outdir";
  149. opt11->required = NO;
  150. opt11->description =
  151. _("Name for output raster map to contain movement directions");
  152. opt11->guisection = _("Optional outputs");
  153. opt7 = G_define_standard_option(G_OPT_V_INPUT);
  154. opt7->key = "start_points";
  155. opt7->required = NO;
  156. opt7->label = _("Name of starting vector points map");
  157. opt7->guisection = _("Start");
  158. opt8 = G_define_standard_option(G_OPT_V_INPUT);
  159. opt8->key = "stop_points";
  160. opt8->required = NO;
  161. opt8->label = _("Name of stopping vector points map");
  162. opt8->guisection = _("Stop");
  163. opt9 = G_define_standard_option(G_OPT_R_INPUT);
  164. opt9->key = "start_rast";
  165. opt9->required = NO;
  166. opt9->description = _("Name of starting raster points map");
  167. opt9->guisection = _("Start");
  168. opt3 = G_define_standard_option(G_OPT_M_COORDS);
  169. opt3->key = "start_coordinates";
  170. opt3->multiple = YES;
  171. opt3->description =
  172. _("Coordinates of starting point(s) (E,N)");
  173. opt3->guisection = _("Start");
  174. opt4 = G_define_standard_option(G_OPT_M_COORDS);
  175. opt4->key = "stop_coordinates";
  176. opt4->multiple = YES;
  177. opt4->description =
  178. _("Coordinates of stopping point(s) (E,N)");
  179. opt4->guisection = _("Stop");
  180. opt5 = G_define_option();
  181. opt5->key = "max_cost";
  182. opt5->type = TYPE_INTEGER;
  183. opt5->key_desc = "value";
  184. opt5->required = NO;
  185. opt5->multiple = NO;
  186. opt5->answer = "0";
  187. opt5->description = _("Maximum cumulative cost");
  188. opt6 = G_define_option();
  189. opt6->key = "null_cost";
  190. opt6->type = TYPE_DOUBLE;
  191. opt6->key_desc = "value";
  192. opt6->required = NO;
  193. opt6->multiple = NO;
  194. opt6->description =
  195. _("Cost assigned to null cells. By default, null cells are excluded");
  196. opt6->guisection = _("NULL cells");
  197. opt10 = G_define_option();
  198. opt10->key = "percent_memory";
  199. opt10->type = TYPE_INTEGER;
  200. opt10->key_desc = "value";
  201. opt10->required = NO;
  202. opt10->multiple = NO;
  203. opt10->answer = "40";
  204. opt10->options = "0-100";
  205. opt10->description = _("Percent of map to keep in memory");
  206. flag2 = G_define_flag();
  207. flag2->key = 'k';
  208. flag2->description =
  209. _("Use the 'Knight's move'; slower, but more accurate");
  210. flag3 = G_define_flag();
  211. flag3->key = 'n';
  212. flag3->description = _("Keep null values in output raster map");
  213. flag3->guisection = _("NULL cells");
  214. flag4 = G_define_flag();
  215. flag4->key = 'r';
  216. flag4->description = _("Start with values in raster map");
  217. flag4->guisection = _("Start");
  218. flag5 = G_define_flag();
  219. flag5->key = 'i';
  220. flag5->description = _("Print info about disk space and memory requirements and exit");
  221. /* Parse options */
  222. if (G_parser(argc, argv))
  223. exit(EXIT_FAILURE);
  224. /* If no outdir is specified, set flag to skip all dir */
  225. if (opt11->answer != NULL)
  226. dir = 1;
  227. /* Get database window parameters */
  228. Rast_get_window(&window);
  229. /* Find north-south, east_west and diagonal factors */
  230. EW_fac = 1.0;
  231. NS_fac = window.ns_res / window.ew_res;
  232. DIAG_fac = (double)sqrt((double)(NS_fac * NS_fac + EW_fac * EW_fac));
  233. V_DIAG_fac =
  234. (double)sqrt((double)(4 * NS_fac * NS_fac + EW_fac * EW_fac));
  235. H_DIAG_fac =
  236. (double)sqrt((double)(NS_fac * NS_fac + 4 * EW_fac * EW_fac));
  237. EW_fac /= 2.0;
  238. NS_fac /= 2.0;
  239. DIAG_fac /= 2.0;
  240. V_DIAG_fac /= 4.0;
  241. H_DIAG_fac /= 4.0;
  242. Rast_set_d_null_value(&null_cost, 1);
  243. if (flag2->answer)
  244. total_reviewed = 16;
  245. else
  246. total_reviewed = 8;
  247. keep_nulls = flag3->answer;
  248. start_with_raster_vals = flag4->answer;
  249. {
  250. int count = 0;
  251. if (opt3->answers)
  252. count++;
  253. if (opt7->answers)
  254. count++;
  255. if (opt9->answers)
  256. count++;
  257. if (count != 1)
  258. G_fatal_error(_("Must specify exactly one of start_points, start_rast or coordinate"));
  259. }
  260. if (opt3->answers)
  261. if (!process_answers(opt3->answers, &head_start_pt, &pres_start_pt))
  262. G_fatal_error(_("No start points"));
  263. if (opt4->answers)
  264. have_stop_points =
  265. process_answers(opt4->answers, &head_end_pt, &pres_stop_pt);
  266. if (sscanf(opt5->answer, "%d", &maxcost) != 1 || maxcost < 0)
  267. G_fatal_error(_("Inappropriate maximum cost: %d"), maxcost);
  268. if (sscanf(opt10->answer, "%d", &maxmem) != 1 || maxmem < 0 ||
  269. maxmem > 100)
  270. G_fatal_error(_("Inappropriate percent memory: %d"), maxmem);
  271. if ((opt6->answer == NULL) ||
  272. (sscanf(opt6->answer, "%lf", &null_cost) != 1)) {
  273. G_debug(1, "Null cells excluded from cost evaluation");
  274. Rast_set_d_null_value(&null_cost, 1);
  275. }
  276. else if (keep_nulls)
  277. G_debug(1, "Null cell will be retained into output map");
  278. if (opt7->answer) {
  279. search_mapset = G_find_vector2(opt7->answer, "");
  280. if (search_mapset == NULL)
  281. G_fatal_error(_("Vector map <%s> not found"), opt7->answer);
  282. }
  283. if (!Rast_is_d_null_value(&null_cost)) {
  284. if (null_cost < 0.0) {
  285. G_warning(_("Assigning negative cost to null cell. Null cells excluded."));
  286. Rast_set_d_null_value(&null_cost, 1);
  287. }
  288. }
  289. else {
  290. keep_nulls = 0; /* handled automagically... */
  291. }
  292. cum_cost_layer = opt1->answer;
  293. cost_layer = opt2->answer;
  294. move_dir_layer = opt11->answer;
  295. nearest_layer = opt12->answer;
  296. /* Find number of rows and columns in window */
  297. nrows = Rast_window_rows();
  298. ncols = Rast_window_cols();
  299. /* Open cost cell layer for reading */
  300. cost_mapset = G_find_raster2(cost_layer, "");
  301. if (cost_mapset == NULL)
  302. G_fatal_error(_("Raster map <%s> not found"), cost_layer);
  303. cost_fd = Rast_open_old(cost_layer, cost_mapset);
  304. data_type = Rast_get_map_type(cost_fd);
  305. /* Parameters for map submatrices */
  306. switch (data_type) {
  307. case (CELL_TYPE):
  308. G_debug(1, "Source map is: Integer cell type");
  309. break;
  310. case (FCELL_TYPE):
  311. G_debug(1, "Source map is: Floating point (float) cell type");
  312. break;
  313. case (DCELL_TYPE):
  314. G_debug(1, "Source map is: Floating point (double) cell type");
  315. break;
  316. }
  317. G_debug(1, " %d rows, %d cols", nrows, ncols);
  318. /* this is most probably the limitation of r.cost for large datasets
  319. * segment size needs to be reduced to avoid unecessary disk IO
  320. * but it doesn't make sense to go down to 1
  321. * so use 64 segment rows and cols for <= 200 million cells
  322. * for larger regions, 32 segment rows and cols
  323. * maybe go down to 16 for > 500 million cells ? */
  324. if ((double) nrows * ncols > 200000000)
  325. srows = scols = SEGCOLSIZE / 2;
  326. else
  327. srows = scols = SEGCOLSIZE;
  328. if (maxmem == 100) {
  329. srows = scols = 256;
  330. }
  331. /* calculate total number of segments */
  332. nseg = ((nrows + srows - 1) / srows) * ((ncols + scols - 1) / scols);
  333. if (maxmem > 0)
  334. segments_in_memory = (maxmem * nseg) / 100;
  335. /* maxmem = 0 */
  336. else
  337. segments_in_memory = 4 * (nrows / srows + ncols / scols + 2);
  338. if (segments_in_memory == 0)
  339. segments_in_memory = 1;
  340. /* report disk space and memory requirements */
  341. if (dir == TRUE) {
  342. disk_mb = (double) nrows * ncols * 28. / 1048576.;
  343. mem_mb = (double) srows * scols * 28. / 1048576. * segments_in_memory;
  344. mem_mb += nrows * ncols * 0.05 * 20. / 1048576.; /* for Dijkstra search */
  345. }
  346. else {
  347. disk_mb = (double) nrows * ncols * 24. / 1048576.;
  348. mem_mb = (double) srows * scols * 24. / 1048576. * segments_in_memory;
  349. mem_mb += nrows * ncols * 0.05 * 20. / 1048576.; /* for Dijkstra search */
  350. }
  351. if (flag5->answer) {
  352. fprintf(stdout, _("Will need at least %.2f MB of disk space"), disk_mb);
  353. fprintf(stdout, "\n");
  354. fprintf(stdout, _("Will need at least %.2f MB of memory"), mem_mb);
  355. fprintf(stdout, "\n");
  356. Rast_close(cost_fd);
  357. exit(EXIT_SUCCESS);
  358. }
  359. G_verbose_message("--------------------------------------------");
  360. G_verbose_message(_("Will need at least %.2f MB of disk space"), disk_mb);
  361. G_verbose_message(_("Will need at least %.2f MB of memory"), mem_mb);
  362. G_verbose_message("--------------------------------------------");
  363. /* Create segmented format files for cost layer and output layer */
  364. G_verbose_message(_("Creating some temporary files..."));
  365. if (segment_open(&cost_seg, G_tempfile(), nrows, ncols, srows, scols,
  366. sizeof(struct cc), segments_in_memory) != 1)
  367. G_fatal_error(_("Can not create temporary file"));
  368. if (dir == TRUE) {
  369. if (segment_open(&dir_seg, G_tempfile(), nrows, ncols, srows, scols,
  370. sizeof(FCELL), segments_in_memory) != 1)
  371. G_fatal_error(_("Can not create temporary file"));
  372. }
  373. /* Write the cost layer in the segmented file */
  374. G_message(_("Reading raster map <%s>, initializing output..."),
  375. G_fully_qualified_name(cost_layer, cost_mapset));
  376. {
  377. int i, skip_nulls;
  378. double p;
  379. Rast_set_d_null_value(&dnullval, 1);
  380. costs.cost_out = dnullval;
  381. costs.nearest = 0;
  382. total_cells = nrows * ncols;
  383. skip_nulls = Rast_is_d_null_value(&null_cost);
  384. dsize = Rast_cell_size(data_type);
  385. cell = Rast_allocate_buf(data_type);
  386. p = 0.0;
  387. for (row = 0; row < nrows; row++) {
  388. G_percent(row, nrows, 2);
  389. Rast_get_row(cost_fd, cell, row, data_type);
  390. /* INPUT NULL VALUES: ??? */
  391. ptr2 = cell;
  392. for (i = 0; i < ncols; i++) {
  393. if (Rast_is_null_value(ptr2, data_type)) {
  394. p = null_cost;
  395. if (skip_nulls) {
  396. total_cells--;
  397. }
  398. }
  399. else {
  400. switch (data_type) {
  401. case CELL_TYPE:
  402. p = *(CELL *)ptr2;
  403. break;
  404. case FCELL_TYPE:
  405. p = *(FCELL *)ptr2;
  406. break;
  407. case DCELL_TYPE:
  408. p = *(DCELL *)ptr2;
  409. break;
  410. }
  411. }
  412. if (p < 0) {
  413. G_warning(_("Negative cell value found at row %d, col %d. "
  414. "Setting negative value to null_cost value"),
  415. row, i);
  416. p = null_cost;
  417. }
  418. costs.cost_in = p;
  419. segment_put(&cost_seg, &costs, row, i);
  420. ptr2 = G_incr_void_ptr(ptr2, dsize);
  421. }
  422. }
  423. G_free(cell);
  424. G_percent(1, 1, 1);
  425. }
  426. if (dir == TRUE) {
  427. int i;
  428. G_message(_("Initializing directional output..."));
  429. for (row = 0; row < nrows; row++) {
  430. G_percent(row, nrows, 2);
  431. for (i = 0; i < ncols; i++) {
  432. segment_put(&dir_seg, &dnullval, row, i);
  433. }
  434. }
  435. G_percent(1, 1, 1);
  436. }
  437. /* Scan the start_points layer searching for starting points.
  438. * Create a heap of starting points ordered by increasing costs.
  439. */
  440. init_heap();
  441. /* read vector with start points */
  442. if (opt7->answer) {
  443. struct Map_info In;
  444. struct line_pnts *Points;
  445. struct line_cats *Cats;
  446. struct bound_box box;
  447. struct start_pt *new_start_pt;
  448. int cat, type, npoints = 0;
  449. Points = Vect_new_line_struct();
  450. Cats = Vect_new_cats_struct();
  451. Vect_set_open_level(1); /* topology not required */
  452. if (1 > Vect_open_old(&In, opt7->answer, ""))
  453. G_fatal_error(_("Unable to open vector map <%s>"), opt7->answer);
  454. G_message(_("Reading vector map <%s> with start points..."),
  455. Vect_get_full_name(&In));
  456. Vect_rewind(&In);
  457. Vect_region_box(&window, &box);
  458. while (1) {
  459. /* register line */
  460. type = Vect_read_next_line(&In, Points, Cats);
  461. /* Note: check for dead lines is not needed, because they are skipped by V1_read_next_line_nat() */
  462. if (type == -1) {
  463. G_warning(_("Unable to read vector map"));
  464. continue;
  465. }
  466. else if (type == -2) {
  467. break;
  468. }
  469. if (!Vect_point_in_box(Points->x[0], Points->y[0], 0, &box))
  470. continue;
  471. npoints++;
  472. col = (int)Rast_easting_to_col(Points->x[0], &window);
  473. row = (int)Rast_northing_to_row(Points->y[0], &window);
  474. new_start_pt =
  475. (struct start_pt *)(G_malloc(sizeof(struct start_pt)));
  476. new_start_pt->row = row;
  477. new_start_pt->col = col;
  478. Vect_cat_get(Cats, 1, &cat);
  479. new_start_pt->value = cat;
  480. new_start_pt->next = NULL;
  481. if (head_start_pt == NULL) {
  482. head_start_pt = new_start_pt;
  483. pres_start_pt = new_start_pt;
  484. new_start_pt->next = NULL;
  485. }
  486. else {
  487. pres_start_pt->next = new_start_pt;
  488. pres_start_pt = new_start_pt;
  489. }
  490. }
  491. if (npoints < 1)
  492. G_fatal_error(_("No start points found in vector map <%s>"), Vect_get_full_name(&In));
  493. else
  494. G_verbose_message(_("%d points found"), npoints);
  495. Vect_close(&In);
  496. }
  497. /* read vector with stop points */
  498. if (opt8->answer) {
  499. struct Map_info In;
  500. struct line_pnts *Points;
  501. struct line_cats *Cats;
  502. struct bound_box box;
  503. struct start_pt *new_start_pt;
  504. int type;
  505. G_message(_("Reading vector map <%s> with stop points..."), opt8->answer);
  506. Points = Vect_new_line_struct();
  507. Cats = Vect_new_cats_struct();
  508. Vect_set_open_level(1); /* topology not required */
  509. if (1 > Vect_open_old(&In, opt8->answer, ""))
  510. G_fatal_error(_("Unable to open vector map <%s>"), opt8->answer);
  511. Vect_rewind(&In);
  512. Vect_region_box(&window, &box);
  513. while (1) {
  514. /* register line */
  515. type = Vect_read_next_line(&In, Points, Cats);
  516. /* Note: check for dead lines is not needed, because they are skipped by V1_read_next_line_nat() */
  517. if (type == -1) {
  518. G_warning(_("Unable to read vector map"));
  519. continue;
  520. }
  521. else if (type == -2) {
  522. break;
  523. }
  524. if (!Vect_point_in_box(Points->x[0], Points->y[0], 0, &box))
  525. continue;
  526. have_stop_points = TRUE;
  527. col = (int)Rast_easting_to_col(Points->x[0], &window);
  528. row = (int)Rast_northing_to_row(Points->y[0], &window);
  529. new_start_pt =
  530. (struct start_pt *)(G_malloc(sizeof(struct start_pt)));
  531. new_start_pt->row = row;
  532. new_start_pt->col = col;
  533. new_start_pt->next = NULL;
  534. if (head_end_pt == NULL) {
  535. head_end_pt = new_start_pt;
  536. pres_stop_pt = new_start_pt;
  537. new_start_pt->next = NULL;
  538. }
  539. else {
  540. pres_stop_pt->next = new_start_pt;
  541. pres_stop_pt = new_start_pt;
  542. }
  543. }
  544. Vect_close(&In);
  545. if (!have_stop_points)
  546. G_warning(_("No stop points found in vector <%s>"), opt8->answer);
  547. }
  548. /* read raster with start points */
  549. if (opt9->answer) {
  550. int dsize2;
  551. int fd;
  552. RASTER_MAP_TYPE data_type2;
  553. int got_one = 0;
  554. search_mapset = G_find_raster(opt9->answer, "");
  555. if (search_mapset == NULL)
  556. G_fatal_error(_("Raster map <%s> not found"), opt9->answer);
  557. fd = Rast_open_old(opt9->answer, search_mapset);
  558. data_type2 = Rast_get_map_type(fd);
  559. nearest_data_type = data_type2;
  560. dsize2 = Rast_cell_size(data_type2);
  561. cell2 = Rast_allocate_buf(data_type2);
  562. if (!cell2)
  563. G_fatal_error(_("Unable to allocate memory"));
  564. G_message(_("Reading raster map <%s> with start points..."), opt9->answer);
  565. for (row = 0; row < nrows; row++) {
  566. G_percent(row, nrows, 2);
  567. Rast_get_row(fd, cell2, row, data_type2);
  568. ptr2 = cell2;
  569. for (col = 0; col < ncols; col++) {
  570. /* Did I understand that concept of cummulative cost map? - (pmx) 12 april 2000 */
  571. if (!Rast_is_null_value(ptr2, data_type2)) {
  572. double cellval;
  573. segment_get(&cost_seg, &costs, row, col);
  574. cellval = Rast_get_d_value(ptr2, data_type2);
  575. if (start_with_raster_vals == 1) {
  576. insert(cellval, row, col);
  577. costs.cost_out = cellval;
  578. costs.nearest = cellval;
  579. segment_put(&cost_seg, &costs, row, col);
  580. }
  581. else {
  582. value = &zero;
  583. insert(zero, row, col);
  584. costs.cost_out = *value;
  585. costs.nearest = cellval;
  586. segment_put(&cost_seg, &costs, row, col);
  587. }
  588. got_one = 1;
  589. }
  590. ptr2 = G_incr_void_ptr(ptr2, dsize2);
  591. }
  592. }
  593. G_percent(1, 1, 1);
  594. Rast_close(fd);
  595. G_free(cell2);
  596. if (!got_one)
  597. G_fatal_error(_("No start points"));
  598. }
  599. /* If the starting points are given on the command line start a linked
  600. * list of cells ordered by increasing costs
  601. */
  602. if (head_start_pt) {
  603. struct start_pt *top_start_pt = NULL;
  604. top_start_pt = head_start_pt;
  605. while (top_start_pt != NULL) {
  606. value = &zero;
  607. if (top_start_pt->row < 0 || top_start_pt->row >= nrows
  608. || top_start_pt->col < 0 || top_start_pt->col >= ncols)
  609. G_fatal_error(_("Specified starting location outside database window"));
  610. insert(zero, top_start_pt->row, top_start_pt->col);
  611. segment_get(&cost_seg, &costs, top_start_pt->row,
  612. top_start_pt->col);
  613. costs.cost_out = *value;
  614. costs.nearest = top_start_pt->value;
  615. segment_put(&cost_seg, &costs, top_start_pt->row,
  616. top_start_pt->col);
  617. top_start_pt = top_start_pt->next;
  618. }
  619. }
  620. /* Loop through the heap and perform at each cell the following:
  621. * 1) If an adjacent cell has not already been assigned a value compute
  622. * the min cost and assign it.
  623. * 2) Insert the adjacent cell in the heap.
  624. * 3) Free the memory allocated to the present cell.
  625. */
  626. G_message(_("Finding cost path..."));
  627. n_processed = 0;
  628. pres_cell = get_lowest();
  629. while (pres_cell != NULL) {
  630. struct cost *ct;
  631. double N, NE, E, SE, S, SW, W, NW;
  632. double NNE, ENE, ESE, SSE, SSW, WSW, WNW, NNW;
  633. N = NE = E = SE = S = SW = W = NW = dnullval;
  634. NNE = ENE = ESE = SSE = SSW = WSW = WNW = NNW = dnullval;
  635. /* If we have surpassed the user specified maximum cost, then quit */
  636. if (maxcost && ((double)maxcost < pres_cell->min_cost))
  637. break;
  638. /* If I've already been updated, delete me */
  639. segment_get(&cost_seg, &costs, pres_cell->row, pres_cell->col);
  640. old_min_cost = costs.cost_out;
  641. if (!Rast_is_d_null_value(&old_min_cost)) {
  642. if (pres_cell->min_cost > old_min_cost) {
  643. delete(pres_cell);
  644. pres_cell = get_lowest();
  645. continue;
  646. }
  647. }
  648. row = pres_cell->row;
  649. col = pres_cell->col;
  650. my_cost = costs.cost_in;
  651. nearest = costs.nearest;
  652. G_percent(n_processed++, total_cells, 1);
  653. /* 9 10 Order in which neighbors
  654. * 13 5 3 6 14 are visited (Knight move).
  655. * 1 2
  656. * 16 8 4 7 15
  657. * 12 11
  658. */
  659. /* drainage directions in degrees CCW from East
  660. * drainage directions are set for each neighbor and must be
  661. * read as from neighbor to current cell
  662. *
  663. * X = neighbor:
  664. *
  665. * 112.5 67.5
  666. * 157.5 135 90 45 22.5
  667. * 180 X 360
  668. * 202.5 225 270 315 337.5
  669. * 247.5 292.5
  670. *
  671. * X = present cell, directions for neighbors:
  672. *
  673. * 292.5 247.5
  674. * 337.5 315 270 225 202.5
  675. * 360 X 180
  676. * 22.5 45 90 135 157.5
  677. * 67.5 112.5
  678. */
  679. for (neighbor = 1; neighbor <= total_reviewed; neighbor++) {
  680. switch (neighbor) {
  681. case 1:
  682. col = pres_cell->col - 1;
  683. cur_dir = 360.0;
  684. break;
  685. case 2:
  686. col = pres_cell->col + 1;
  687. cur_dir = 180.0;
  688. break;
  689. case 3:
  690. row = pres_cell->row - 1;
  691. col = pres_cell->col;
  692. cur_dir = 270.0;
  693. break;
  694. case 4:
  695. row = pres_cell->row + 1;
  696. cur_dir = 90.0;
  697. break;
  698. case 5:
  699. row = pres_cell->row - 1;
  700. col = pres_cell->col - 1;
  701. cur_dir = 315.0;
  702. break;
  703. case 6:
  704. col = pres_cell->col + 1;
  705. cur_dir = 225.0;
  706. break;
  707. case 7:
  708. row = pres_cell->row + 1;
  709. cur_dir = 135.0;
  710. break;
  711. case 8:
  712. col = pres_cell->col - 1;
  713. cur_dir = 45.0;
  714. break;
  715. case 9:
  716. row = pres_cell->row - 2;
  717. col = pres_cell->col - 1;
  718. cur_dir = 292.5;
  719. break;
  720. case 10:
  721. col = pres_cell->col + 1;
  722. cur_dir = 247.5;
  723. break;
  724. case 11:
  725. row = pres_cell->row + 2;
  726. cur_dir = 112.5;
  727. break;
  728. case 12:
  729. col = pres_cell->col - 1;
  730. cur_dir = 67.5;
  731. break;
  732. case 13:
  733. row = pres_cell->row - 1;
  734. col = pres_cell->col - 2;
  735. cur_dir = 337.5;
  736. break;
  737. case 14:
  738. col = pres_cell->col + 2;
  739. cur_dir = 202.5;
  740. break;
  741. case 15:
  742. row = pres_cell->row + 1;
  743. cur_dir = 157.5;
  744. break;
  745. case 16:
  746. col = pres_cell->col - 2;
  747. cur_dir = 22.5;
  748. break;
  749. }
  750. if (row < 0 || row >= nrows)
  751. continue;
  752. if (col < 0 || col >= ncols)
  753. continue;
  754. switch (neighbor) {
  755. case 1:
  756. segment_get(&cost_seg, &costs, row, col);
  757. W = costs.cost_in;
  758. fcost = (double)(W + my_cost);
  759. min_cost = pres_cell->min_cost + fcost * EW_fac;
  760. break;
  761. case 2:
  762. segment_get(&cost_seg, &costs, row, col);
  763. E = costs.cost_in;
  764. fcost = (double)(E + my_cost);
  765. min_cost = pres_cell->min_cost + fcost * EW_fac;
  766. break;
  767. case 3:
  768. segment_get(&cost_seg, &costs, row, col);
  769. N = costs.cost_in;
  770. fcost = (double)(N + my_cost);
  771. min_cost = pres_cell->min_cost + fcost * NS_fac;
  772. break;
  773. case 4:
  774. segment_get(&cost_seg, &costs, row, col);
  775. S = costs.cost_in;
  776. fcost = (double)(S + my_cost);
  777. min_cost = pres_cell->min_cost + fcost * NS_fac;
  778. break;
  779. case 5:
  780. segment_get(&cost_seg, &costs, row, col);
  781. NW = costs.cost_in;
  782. fcost = (double)(NW + my_cost);
  783. min_cost = pres_cell->min_cost + fcost * DIAG_fac;
  784. break;
  785. case 6:
  786. segment_get(&cost_seg, &costs, row, col);
  787. NE = costs.cost_in;
  788. fcost = (double)(NE + my_cost);
  789. min_cost = pres_cell->min_cost + fcost * DIAG_fac;
  790. break;
  791. case 7:
  792. segment_get(&cost_seg, &costs, row, col);
  793. SE = costs.cost_in;
  794. fcost = (double)(SE + my_cost);
  795. min_cost = pres_cell->min_cost + fcost * DIAG_fac;
  796. break;
  797. case 8:
  798. segment_get(&cost_seg, &costs, row, col);
  799. SW = costs.cost_in;
  800. fcost = (double)(SW + my_cost);
  801. min_cost = pres_cell->min_cost + fcost * DIAG_fac;
  802. break;
  803. case 9:
  804. segment_get(&cost_seg, &costs, row, col);
  805. NNW = costs.cost_in;
  806. fcost = (double)(N + NW + NNW + my_cost);
  807. min_cost = pres_cell->min_cost + fcost * V_DIAG_fac;
  808. break;
  809. case 10:
  810. segment_get(&cost_seg, &costs, row, col);
  811. NNE = costs.cost_in;
  812. fcost = (double)(N + NE + NNE + my_cost);
  813. min_cost = pres_cell->min_cost + fcost * V_DIAG_fac;
  814. break;
  815. case 11:
  816. segment_get(&cost_seg, &costs, row, col);
  817. SSE = costs.cost_in;
  818. fcost = (double)(S + SE + SSE + my_cost);
  819. min_cost = pres_cell->min_cost + fcost * V_DIAG_fac;
  820. break;
  821. case 12:
  822. segment_get(&cost_seg, &costs, row, col);
  823. SSW = costs.cost_in;
  824. fcost = (double)(S + SW + SSW + my_cost);
  825. min_cost = pres_cell->min_cost + fcost * V_DIAG_fac;
  826. break;
  827. case 13:
  828. segment_get(&cost_seg, &costs, row, col);
  829. WNW = costs.cost_in;
  830. fcost = (double)(W + NW + WNW + my_cost);
  831. min_cost = pres_cell->min_cost + fcost * H_DIAG_fac;
  832. break;
  833. case 14:
  834. segment_get(&cost_seg, &costs, row, col);
  835. ENE = costs.cost_in;
  836. fcost = (double)(E + NE + ENE + my_cost);
  837. min_cost = pres_cell->min_cost + fcost * H_DIAG_fac;
  838. break;
  839. case 15:
  840. segment_get(&cost_seg, &costs, row, col);
  841. ESE = costs.cost_in;
  842. fcost = (double)(E + SE + ESE + my_cost);
  843. min_cost = pres_cell->min_cost + fcost * H_DIAG_fac;
  844. break;
  845. case 16:
  846. segment_get(&cost_seg, &costs, row, col);
  847. WSW = costs.cost_in;
  848. fcost = (double)(W + SW + WSW + my_cost);
  849. min_cost = pres_cell->min_cost + fcost * H_DIAG_fac;
  850. break;
  851. }
  852. /* skip if costs could not be calculated */
  853. if (Rast_is_d_null_value(&min_cost))
  854. continue;
  855. old_min_cost = costs.cost_out;
  856. /* add to list */
  857. if (Rast_is_d_null_value(&old_min_cost)) {
  858. costs.cost_out = min_cost;
  859. costs.nearest = nearest;
  860. segment_put(&cost_seg, &costs, row, col);
  861. insert(min_cost, row, col);
  862. if (dir == TRUE) {
  863. segment_put(&dir_seg, &cur_dir, row, col);
  864. }
  865. }
  866. /* update with lower costs */
  867. else if (old_min_cost > min_cost) {
  868. costs.cost_out = min_cost;
  869. costs.nearest = nearest;
  870. segment_put(&cost_seg, &costs, row, col);
  871. insert(min_cost, row, col);
  872. if (dir == TRUE) {
  873. segment_put(&dir_seg, &cur_dir, row, col);
  874. }
  875. }
  876. }
  877. if (have_stop_points && time_to_stop(pres_cell->row, pres_cell->col))
  878. break;
  879. ct = pres_cell;
  880. delete(pres_cell);
  881. pres_cell = get_lowest();
  882. if (ct == pres_cell) {
  883. G_warning(_("Error, ct == pres_cell"));
  884. }
  885. }
  886. G_percent(1, 1, 1);
  887. /* free heap */
  888. free_heap();
  889. /* Open cumulative cost layer for writing */
  890. cum_fd = Rast_open_new(cum_cost_layer, cum_data_type);
  891. cell = Rast_allocate_buf(cum_data_type);
  892. /* Open nearest start point layer */
  893. if (nearest_layer) {
  894. nearest_fd = Rast_open_new(nearest_layer, nearest_data_type);
  895. nearest_cell = Rast_allocate_buf(nearest_data_type);
  896. }
  897. else {
  898. nearest_fd = -1;
  899. nearest_cell = NULL;
  900. }
  901. nearest_size = Rast_cell_size(nearest_data_type);
  902. /* Copy segmented map to output map */
  903. G_message(_("Writing output raster map <%s>..."), cum_cost_layer);
  904. if (nearest_layer) {
  905. G_message(_("Writing raster map with nearest start point <%s>..."), nearest_layer);
  906. }
  907. cell2 = Rast_allocate_buf(data_type);
  908. {
  909. void *p;
  910. void *p2;
  911. void *p3;
  912. int cum_dsize = Rast_cell_size(cum_data_type);
  913. Rast_set_null_value(cell2, ncols, data_type);
  914. for (row = 0; row < nrows; row++) {
  915. G_percent(row, nrows, 2);
  916. if (keep_nulls)
  917. Rast_get_row(cost_fd, cell2, row, data_type);
  918. p = cell;
  919. p2 = cell2;
  920. p3 = nearest_cell;
  921. for (col = 0; col < ncols; col++) {
  922. if (keep_nulls) {
  923. if (Rast_is_null_value(p2, data_type)) {
  924. Rast_set_null_value(p, 1, cum_data_type);
  925. p = G_incr_void_ptr(p, cum_dsize);
  926. p2 = G_incr_void_ptr(p2, dsize);
  927. if (nearest_layer) {
  928. Rast_set_null_value(p3, 1, nearest_data_type);
  929. p3 = G_incr_void_ptr(p3, nearest_size);
  930. }
  931. continue;
  932. }
  933. }
  934. segment_get(&cost_seg, &costs, row, col);
  935. min_cost = costs.cost_out;
  936. nearest = costs.nearest;
  937. if (Rast_is_d_null_value(&min_cost)) {
  938. Rast_set_null_value(p, 1, cum_data_type);
  939. if (nearest_layer)
  940. Rast_set_null_value(p3, 1, nearest_data_type);
  941. }
  942. else {
  943. if (min_cost > peak)
  944. peak = min_cost;
  945. switch (cum_data_type) {
  946. case CELL_TYPE:
  947. *(CELL *)p = (CELL)(min_cost + .5);
  948. break;
  949. case FCELL_TYPE:
  950. *(FCELL *)p = (FCELL)(min_cost);
  951. break;
  952. case DCELL_TYPE:
  953. *(DCELL *)p = (DCELL)(min_cost);
  954. break;
  955. }
  956. if (nearest_layer) {
  957. switch (nearest_data_type) {
  958. case CELL_TYPE:
  959. *(CELL *)p3 = (CELL)(nearest);
  960. break;
  961. case FCELL_TYPE:
  962. *(FCELL *)p3 = (FCELL)(nearest);
  963. break;
  964. case DCELL_TYPE:
  965. *(DCELL *)p3 = (DCELL)(nearest);
  966. break;
  967. }
  968. }
  969. }
  970. p = G_incr_void_ptr(p, cum_dsize);
  971. p2 = G_incr_void_ptr(p2, dsize);
  972. if (nearest_layer)
  973. p3 = G_incr_void_ptr(p3, nearest_size);
  974. }
  975. Rast_put_row(cum_fd, cell, cum_data_type);
  976. if (nearest_layer)
  977. Rast_put_row(nearest_fd, nearest_cell, nearest_data_type);
  978. }
  979. G_percent(1, 1, 1);
  980. G_free(cell);
  981. G_free(cell2);
  982. if (nearest_layer)
  983. G_free(nearest_cell);
  984. }
  985. if (dir == TRUE) {
  986. void *p;
  987. size_t dir_size = Rast_cell_size(dir_data_type);
  988. dir_fd = Rast_open_new(move_dir_layer, dir_data_type);
  989. dir_cell = Rast_allocate_buf(dir_data_type);
  990. G_message(_("Writing output movement direction raster map <%s>..."), move_dir_layer);
  991. for (row = 0; row < nrows; row++) {
  992. p = dir_cell;
  993. for (col = 0; col < ncols; col++) {
  994. segment_get(&dir_seg, &cur_dir, row, col);
  995. *((FCELL *) p) = cur_dir;
  996. p = G_incr_void_ptr(p, dir_size);
  997. }
  998. Rast_put_row(dir_fd, dir_cell, dir_data_type);
  999. G_percent(row, nrows, 2);
  1000. }
  1001. G_percent(1, 1, 1);
  1002. G_free(dir_cell);
  1003. }
  1004. segment_close(&cost_seg); /* release memory */
  1005. if (dir == TRUE)
  1006. segment_close(&dir_seg);
  1007. Rast_close(cost_fd);
  1008. Rast_close(cum_fd);
  1009. if (dir == TRUE)
  1010. Rast_close(dir_fd);
  1011. if (nearest_layer)
  1012. Rast_close(nearest_fd);
  1013. /* writing history file */
  1014. Rast_short_history(cum_cost_layer, "raster", &history);
  1015. Rast_command_history(&history);
  1016. Rast_write_history(cum_cost_layer, &history);
  1017. if (dir == TRUE) {
  1018. Rast_short_history(move_dir_layer, "raster", &history);
  1019. Rast_command_history(&history);
  1020. Rast_write_history(move_dir_layer, &history);
  1021. }
  1022. if (nearest_layer) {
  1023. Rast_short_history(nearest_layer, "raster", &history);
  1024. Rast_command_history(&history);
  1025. Rast_write_history(nearest_layer, &history);
  1026. if (opt9->answer) {
  1027. struct Colors colors;
  1028. Rast_read_colors(opt9->answer, "", &colors);
  1029. Rast_write_colors(nearest_layer, G_mapset(), &colors);
  1030. }
  1031. else {
  1032. struct Colors colors;
  1033. struct Range range;
  1034. CELL min, max;
  1035. Rast_read_range(nearest_layer, G_mapset(), &range);
  1036. Rast_get_range_min_max(&range, &min, &max);
  1037. Rast_make_random_colors(&colors, min, max);
  1038. Rast_write_colors(nearest_layer, G_mapset(), &colors);
  1039. }
  1040. }
  1041. /* Create colours for output map */
  1042. /*
  1043. * Rast_read_range (cum_cost_layer, current_mapset, &range);
  1044. * Rast_get_range_min_max(&range, &min, &max);
  1045. * G_make_color_wave(&colors,min, max);
  1046. * Rast_write_colors (cum_cost_layer,current_mapset,&colors);
  1047. */
  1048. G_done_msg(_("Peak cost value: %f."), peak);
  1049. exit(EXIT_SUCCESS);
  1050. }
  1051. int
  1052. process_answers(char **answers, struct start_pt **points,
  1053. struct start_pt **top_start_pt)
  1054. {
  1055. int col, row;
  1056. double east, north;
  1057. struct start_pt *new_start_pt;
  1058. int got_one = 0;
  1059. int point_no = 0;
  1060. *points = NULL;
  1061. if (!answers)
  1062. return (0);
  1063. for (; *answers != NULL; answers += 2) {
  1064. if (!G_scan_easting(*answers, &east, G_projection()))
  1065. G_fatal_error(_("Illegal x coordinate <%s>"), *answers);
  1066. if (!G_scan_northing(*(answers + 1), &north, G_projection()))
  1067. G_fatal_error(_("Illegal y coordinate <%s>"), *(answers + 1));
  1068. if (east < window.west || east > window.east ||
  1069. north < window.south || north > window.north) {
  1070. G_warning(_("Warning, ignoring point outside window: %.4f,%.4f"),
  1071. east, north);
  1072. continue;
  1073. }
  1074. else
  1075. got_one = 1;
  1076. row = (window.north - north) / window.ns_res;
  1077. col = (east - window.west) / window.ew_res;
  1078. new_start_pt = (struct start_pt *)(G_malloc(sizeof(struct start_pt)));
  1079. new_start_pt->row = row;
  1080. new_start_pt->col = col;
  1081. new_start_pt->value = ++point_no;
  1082. new_start_pt->next = NULL;
  1083. if (*points == NULL) {
  1084. *points = new_start_pt;
  1085. *top_start_pt = new_start_pt;
  1086. new_start_pt->next = NULL;
  1087. }
  1088. else {
  1089. (*top_start_pt)->next = new_start_pt;
  1090. *top_start_pt = new_start_pt;
  1091. }
  1092. }
  1093. return (got_one);
  1094. }
  1095. int time_to_stop(int row, int col)
  1096. {
  1097. static int total = 0;
  1098. static int hits = 0;
  1099. struct start_pt *points;
  1100. if (total == 0) {
  1101. for (points = head_end_pt;
  1102. points != NULL; points = points->next, total++) ;
  1103. }
  1104. for (points = head_end_pt; points != NULL; points = points->next)
  1105. if (points->row == row && points->col == col) {
  1106. hits++;
  1107. if (hits == total)
  1108. return (1);
  1109. }
  1110. return (0);
  1111. }