main.c 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276
  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-2015 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, pq_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_raster";
  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 = "memory";
  199. opt10->type = TYPE_INTEGER;
  200. opt10->key_desc = "value";
  201. opt10->required = NO;
  202. opt10->multiple = NO;
  203. opt10->answer = "300";
  204. opt10->description = _("Maximum memory to be used in MB");
  205. flag2 = G_define_flag();
  206. flag2->key = 'k';
  207. flag2->description =
  208. _("Use the 'Knight's move'; slower, but more accurate");
  209. flag3 = G_define_flag();
  210. flag3->key = 'n';
  211. flag3->description = _("Keep null values in output raster map");
  212. flag3->guisection = _("NULL cells");
  213. flag4 = G_define_flag();
  214. flag4->key = 'r';
  215. flag4->description = _("Start with values in raster map");
  216. flag4->guisection = _("Start");
  217. flag5 = G_define_flag();
  218. flag5->key = 'i';
  219. flag5->description = _("Print info about disk space and memory requirements and exit");
  220. /* Parse options */
  221. if (G_parser(argc, argv))
  222. exit(EXIT_FAILURE);
  223. /* If no outdir is specified, set flag to skip all dir */
  224. if (opt11->answer != NULL)
  225. dir = 1;
  226. /* Get database window parameters */
  227. Rast_get_window(&window);
  228. /* Find north-south, east_west and diagonal factors */
  229. EW_fac = 1.0;
  230. NS_fac = window.ns_res / window.ew_res;
  231. DIAG_fac = (double)sqrt((double)(NS_fac * NS_fac + EW_fac * EW_fac));
  232. V_DIAG_fac =
  233. (double)sqrt((double)(4 * NS_fac * NS_fac + EW_fac * EW_fac));
  234. H_DIAG_fac =
  235. (double)sqrt((double)(NS_fac * NS_fac + 4 * EW_fac * EW_fac));
  236. EW_fac /= 2.0;
  237. NS_fac /= 2.0;
  238. DIAG_fac /= 2.0;
  239. V_DIAG_fac /= 4.0;
  240. H_DIAG_fac /= 4.0;
  241. Rast_set_d_null_value(&null_cost, 1);
  242. if (flag2->answer)
  243. total_reviewed = 16;
  244. else
  245. total_reviewed = 8;
  246. keep_nulls = flag3->answer;
  247. start_with_raster_vals = flag4->answer;
  248. {
  249. int count = 0;
  250. if (opt3->answers)
  251. count++;
  252. if (opt7->answers)
  253. count++;
  254. if (opt9->answers)
  255. count++;
  256. if (count != 1)
  257. G_fatal_error(_("Must specify exactly one of start_points, start_rast or coordinate"));
  258. }
  259. if (opt3->answers)
  260. if (!process_answers(opt3->answers, &head_start_pt, &pres_start_pt))
  261. G_fatal_error(_("No start points"));
  262. if (opt4->answers)
  263. have_stop_points =
  264. process_answers(opt4->answers, &head_end_pt, &pres_stop_pt);
  265. if (sscanf(opt5->answer, "%d", &maxcost) != 1 || maxcost < 0)
  266. G_fatal_error(_("Inappropriate maximum cost: %d"), maxcost);
  267. if (sscanf(opt10->answer, "%d", &maxmem) != 1 || maxmem <= 0)
  268. G_fatal_error(_("Inappropriate amount of memory: %d"), maxmem);
  269. if ((opt6->answer == NULL) ||
  270. (sscanf(opt6->answer, "%lf", &null_cost) != 1)) {
  271. G_debug(1, "Null cells excluded from cost evaluation");
  272. Rast_set_d_null_value(&null_cost, 1);
  273. }
  274. else if (keep_nulls)
  275. G_debug(1,"Input null cell will be retained into output map");
  276. if (opt7->answer) {
  277. search_mapset = G_find_vector2(opt7->answer, "");
  278. if (search_mapset == NULL)
  279. G_fatal_error(_("Vector map <%s> not found"), opt7->answer);
  280. }
  281. if (!Rast_is_d_null_value(&null_cost)) {
  282. if (null_cost < 0.0) {
  283. G_warning(_("Assigning negative cost to null cell. Null cells excluded."));
  284. Rast_set_d_null_value(&null_cost, 1);
  285. }
  286. }
  287. else {
  288. keep_nulls = 0; /* handled automagically... */
  289. }
  290. cum_cost_layer = opt1->answer;
  291. cost_layer = opt2->answer;
  292. move_dir_layer = opt11->answer;
  293. nearest_layer = opt12->answer;
  294. /* Find number of rows and columns in window */
  295. nrows = Rast_window_rows();
  296. ncols = Rast_window_cols();
  297. /* Open cost cell layer for reading */
  298. cost_mapset = G_find_raster2(cost_layer, "");
  299. if (cost_mapset == NULL)
  300. G_fatal_error(_("Raster map <%s> not found"), cost_layer);
  301. cost_fd = Rast_open_old(cost_layer, cost_mapset);
  302. data_type = Rast_get_map_type(cost_fd);
  303. /* Parameters for map submatrices */
  304. switch (data_type) {
  305. case (CELL_TYPE):
  306. G_debug(1, "Source map is: Integer cell type");
  307. break;
  308. case (FCELL_TYPE):
  309. G_debug(1, "Source map is: Floating point (float) cell type");
  310. break;
  311. case (DCELL_TYPE):
  312. G_debug(1, "Source map is: Floating point (double) cell type");
  313. break;
  314. }
  315. G_debug(1, " %d rows, %d cols", nrows, ncols);
  316. /* this is most probably the limitation of r.cost for large datasets
  317. * segment size needs to be reduced to avoid unecessary disk IO
  318. * but it doesn't make sense to go down to 1
  319. * so use 64 segment rows and cols for <= 200 million cells
  320. * for larger regions, 32 segment rows and cols
  321. * maybe go down to 16 for > 500 million cells ? */
  322. if ((double) nrows * ncols > 200000000)
  323. srows = scols = SEGCOLSIZE / 2;
  324. else
  325. srows = scols = SEGCOLSIZE;
  326. /* calculate total number of segments */
  327. nseg = ((nrows + srows - 1) / srows) * ((ncols + scols - 1) / scols);
  328. /* calculate disk space and memory requirements */
  329. /* (nrows + ncols) * 8. * 20.0 / 1048576. for Dijkstra search */
  330. pq_mb = ((double)nrows + ncols) * 8. * 20.0 / 1048576.;
  331. G_debug(1, "pq MB: %g", pq_mb);
  332. maxmem -= pq_mb;
  333. if (maxmem < 10)
  334. maxmem = 10;
  335. if (dir == TRUE) {
  336. disk_mb = (double) nrows * ncols * 28. / 1048576.;
  337. segments_in_memory = maxmem /
  338. ((double) srows * scols * (28. / 1048576.));
  339. if (segments_in_memory < 4)
  340. segments_in_memory = 4;
  341. if (segments_in_memory > nseg)
  342. segments_in_memory = nseg;
  343. mem_mb = (double) srows * scols * (28. / 1048576.) * segments_in_memory;
  344. }
  345. else {
  346. disk_mb = (double) nrows * ncols * 24. / 1048576.;
  347. segments_in_memory = maxmem /
  348. ((double) srows * scols * (24. / 1048576.));
  349. if (segments_in_memory < 4)
  350. segments_in_memory = 4;
  351. if (segments_in_memory > nseg)
  352. segments_in_memory = nseg;
  353. mem_mb = (double) srows * scols * (24. / 1048576.) * segments_in_memory;
  354. }
  355. if (flag5->answer) {
  356. fprintf(stdout, _("Will need at least %.2f MB of disk space"), disk_mb);
  357. fprintf(stdout, "\n");
  358. fprintf(stdout, _("Will need at least %.2f MB of memory"), mem_mb);
  359. fprintf(stdout, "\n");
  360. fprintf(stdout, _("%d of %d segments are kept in memory"),
  361. segments_in_memory, nseg);
  362. fprintf(stdout, "\n");
  363. Rast_close(cost_fd);
  364. exit(EXIT_SUCCESS);
  365. }
  366. G_verbose_message("--------------------------------------------");
  367. G_verbose_message(_("Will need at least %.2f MB of disk space"), disk_mb);
  368. G_verbose_message(_("Will need at least %.2f MB of memory"), mem_mb);
  369. G_verbose_message(_("%d of %d segments are kept in memory"),
  370. segments_in_memory, nseg);
  371. G_verbose_message("--------------------------------------------");
  372. /* Create segmented format files for cost layer and output layer */
  373. G_verbose_message(_("Creating some temporary files..."));
  374. if (Segment_open(&cost_seg, G_tempfile(), nrows, ncols, srows, scols,
  375. sizeof(struct cc), segments_in_memory) != 1)
  376. G_fatal_error(_("Can not create temporary file"));
  377. if (dir == TRUE) {
  378. if (Segment_open(&dir_seg, G_tempfile(), nrows, ncols, srows, scols,
  379. sizeof(FCELL), segments_in_memory) != 1)
  380. G_fatal_error(_("Can not create temporary file"));
  381. }
  382. /* Write the cost layer in the segmented file */
  383. G_message(_("Reading raster map <%s>, initializing output..."),
  384. G_fully_qualified_name(cost_layer, cost_mapset));
  385. {
  386. int i, skip_nulls;
  387. double p;
  388. Rast_set_d_null_value(&dnullval, 1);
  389. costs.cost_out = dnullval;
  390. costs.nearest = 0;
  391. total_cells = nrows * ncols;
  392. skip_nulls = Rast_is_d_null_value(&null_cost);
  393. dsize = Rast_cell_size(data_type);
  394. cell = Rast_allocate_buf(data_type);
  395. p = 0.0;
  396. for (row = 0; row < nrows; row++) {
  397. G_percent(row, nrows, 2);
  398. Rast_get_row(cost_fd, cell, row, data_type);
  399. /* INPUT NULL VALUES: ??? */
  400. ptr2 = cell;
  401. for (i = 0; i < ncols; i++) {
  402. if (Rast_is_null_value(ptr2, data_type)) {
  403. p = null_cost;
  404. if (skip_nulls) {
  405. total_cells--;
  406. }
  407. }
  408. else {
  409. switch (data_type) {
  410. case CELL_TYPE:
  411. p = *(CELL *)ptr2;
  412. break;
  413. case FCELL_TYPE:
  414. p = *(FCELL *)ptr2;
  415. break;
  416. case DCELL_TYPE:
  417. p = *(DCELL *)ptr2;
  418. break;
  419. }
  420. }
  421. if (p < 0) {
  422. G_warning(_("Negative cell value found at row %d, col %d. "
  423. "Setting negative value to null_cost value"),
  424. row, i);
  425. p = null_cost;
  426. }
  427. costs.cost_in = p;
  428. Segment_put(&cost_seg, &costs, row, i);
  429. ptr2 = G_incr_void_ptr(ptr2, dsize);
  430. }
  431. }
  432. G_free(cell);
  433. G_percent(1, 1, 1);
  434. }
  435. if (dir == TRUE) {
  436. G_message(_("Initializing directional output..."));
  437. for (row = 0; row < nrows; row++) {
  438. G_percent(row, nrows, 2);
  439. for (col = 0; col < ncols; col++) {
  440. Segment_put(&dir_seg, &dnullval, row, col);
  441. }
  442. }
  443. G_percent(1, 1, 1);
  444. }
  445. /* Scan the start_points layer searching for starting points.
  446. * Create a heap of starting points ordered by increasing costs.
  447. */
  448. init_heap();
  449. /* read vector with start points */
  450. if (opt7->answer) {
  451. struct Map_info In;
  452. struct line_pnts *Points;
  453. struct line_cats *Cats;
  454. struct bound_box box;
  455. struct start_pt *new_start_pt;
  456. int cat, type, npoints = 0;
  457. Points = Vect_new_line_struct();
  458. Cats = Vect_new_cats_struct();
  459. Vect_set_open_level(1); /* topology not required */
  460. if (1 > Vect_open_old(&In, opt7->answer, ""))
  461. G_fatal_error(_("Unable to open vector map <%s>"), opt7->answer);
  462. G_message(_("Reading vector map <%s> with start points..."),
  463. Vect_get_full_name(&In));
  464. Vect_rewind(&In);
  465. Vect_region_box(&window, &box);
  466. while (1) {
  467. /* register line */
  468. type = Vect_read_next_line(&In, Points, Cats);
  469. /* Note: check for dead lines is not needed, because they are skipped by V1_read_next_line_nat() */
  470. if (type == -1) {
  471. G_warning(_("Unable to read vector map"));
  472. continue;
  473. }
  474. else if (type == -2) {
  475. break;
  476. }
  477. if (!Vect_point_in_box(Points->x[0], Points->y[0], 0, &box))
  478. continue;
  479. npoints++;
  480. col = (int)Rast_easting_to_col(Points->x[0], &window);
  481. row = (int)Rast_northing_to_row(Points->y[0], &window);
  482. new_start_pt =
  483. (struct start_pt *)(G_malloc(sizeof(struct start_pt)));
  484. new_start_pt->row = row;
  485. new_start_pt->col = col;
  486. Vect_cat_get(Cats, 1, &cat);
  487. new_start_pt->value = cat;
  488. new_start_pt->next = NULL;
  489. if (head_start_pt == NULL) {
  490. head_start_pt = new_start_pt;
  491. pres_start_pt = new_start_pt;
  492. new_start_pt->next = NULL;
  493. }
  494. else {
  495. pres_start_pt->next = new_start_pt;
  496. pres_start_pt = new_start_pt;
  497. }
  498. }
  499. if (npoints < 1)
  500. G_fatal_error(_("No start points found in vector map <%s>"), Vect_get_full_name(&In));
  501. else
  502. G_verbose_message(n_("%d point found", "%d points found", npoints), npoints);
  503. Vect_close(&In);
  504. }
  505. /* read vector with stop points */
  506. if (opt8->answer) {
  507. struct Map_info In;
  508. struct line_pnts *Points;
  509. struct line_cats *Cats;
  510. struct bound_box box;
  511. struct start_pt *new_start_pt;
  512. int type;
  513. G_message(_("Reading vector map <%s> with stop points..."), opt8->answer);
  514. Points = Vect_new_line_struct();
  515. Cats = Vect_new_cats_struct();
  516. Vect_set_open_level(1); /* topology not required */
  517. if (1 > Vect_open_old(&In, opt8->answer, ""))
  518. G_fatal_error(_("Unable to open vector map <%s>"), opt8->answer);
  519. Vect_rewind(&In);
  520. Vect_region_box(&window, &box);
  521. while (1) {
  522. /* register line */
  523. type = Vect_read_next_line(&In, Points, Cats);
  524. /* Note: check for dead lines is not needed, because they are skipped by V1_read_next_line_nat() */
  525. if (type == -1) {
  526. G_warning(_("Unable to read vector map"));
  527. continue;
  528. }
  529. else if (type == -2) {
  530. break;
  531. }
  532. if (!Vect_point_in_box(Points->x[0], Points->y[0], 0, &box))
  533. continue;
  534. have_stop_points = TRUE;
  535. col = (int)Rast_easting_to_col(Points->x[0], &window);
  536. row = (int)Rast_northing_to_row(Points->y[0], &window);
  537. new_start_pt =
  538. (struct start_pt *)(G_malloc(sizeof(struct start_pt)));
  539. new_start_pt->row = row;
  540. new_start_pt->col = col;
  541. new_start_pt->next = NULL;
  542. if (head_end_pt == NULL) {
  543. head_end_pt = new_start_pt;
  544. pres_stop_pt = new_start_pt;
  545. new_start_pt->next = NULL;
  546. }
  547. else {
  548. pres_stop_pt->next = new_start_pt;
  549. pres_stop_pt = new_start_pt;
  550. }
  551. }
  552. Vect_close(&In);
  553. if (!have_stop_points)
  554. G_fatal_error(_("No stop points found in vector <%s>"), opt8->answer);
  555. }
  556. /* read raster with start points */
  557. if (opt9->answer) {
  558. int dsize2;
  559. int fd;
  560. RASTER_MAP_TYPE data_type2;
  561. int got_one = 0;
  562. search_mapset = G_find_raster(opt9->answer, "");
  563. if (search_mapset == NULL)
  564. G_fatal_error(_("Raster map <%s> not found"), opt9->answer);
  565. fd = Rast_open_old(opt9->answer, search_mapset);
  566. data_type2 = Rast_get_map_type(fd);
  567. nearest_data_type = data_type2;
  568. dsize2 = Rast_cell_size(data_type2);
  569. cell2 = Rast_allocate_buf(data_type2);
  570. if (!cell2)
  571. G_fatal_error(_("Unable to allocate memory"));
  572. G_message(_("Reading raster map <%s> with start points..."), opt9->answer);
  573. for (row = 0; row < nrows; row++) {
  574. G_percent(row, nrows, 2);
  575. Rast_get_row(fd, cell2, row, data_type2);
  576. ptr2 = cell2;
  577. for (col = 0; col < ncols; col++) {
  578. /* Did I understand that concept of cumulative cost map? - (pmx) 12 april 2000 */
  579. if (!Rast_is_null_value(ptr2, data_type2)) {
  580. double cellval;
  581. Segment_get(&cost_seg, &costs, row, col);
  582. cellval = Rast_get_d_value(ptr2, data_type2);
  583. if (start_with_raster_vals == 1) {
  584. insert(cellval, row, col);
  585. costs.cost_out = cellval;
  586. costs.nearest = cellval;
  587. Segment_put(&cost_seg, &costs, row, col);
  588. }
  589. else {
  590. value = &zero;
  591. insert(zero, row, col);
  592. costs.cost_out = *value;
  593. costs.nearest = cellval;
  594. Segment_put(&cost_seg, &costs, row, col);
  595. }
  596. got_one = 1;
  597. }
  598. ptr2 = G_incr_void_ptr(ptr2, dsize2);
  599. }
  600. }
  601. G_percent(1, 1, 1);
  602. Rast_close(fd);
  603. G_free(cell2);
  604. if (!got_one)
  605. G_fatal_error(_("No start points"));
  606. }
  607. /* If the starting points are given on the command line start a linked
  608. * list of cells ordered by increasing costs
  609. */
  610. if (head_start_pt) {
  611. struct start_pt *top_start_pt = NULL;
  612. top_start_pt = head_start_pt;
  613. while (top_start_pt != NULL) {
  614. value = &zero;
  615. if (top_start_pt->row < 0 || top_start_pt->row >= nrows
  616. || top_start_pt->col < 0 || top_start_pt->col >= ncols)
  617. G_fatal_error(_("Specified starting location outside database window"));
  618. insert(zero, top_start_pt->row, top_start_pt->col);
  619. Segment_get(&cost_seg, &costs, top_start_pt->row,
  620. top_start_pt->col);
  621. costs.cost_out = *value;
  622. costs.nearest = top_start_pt->value;
  623. Segment_put(&cost_seg, &costs, top_start_pt->row,
  624. top_start_pt->col);
  625. top_start_pt = top_start_pt->next;
  626. }
  627. }
  628. /* Loop through the heap and perform at each cell the following:
  629. * 1) If an adjacent cell has not already been assigned a value compute
  630. * the min cost and assign it.
  631. * 2) Insert the adjacent cell in the heap.
  632. * 3) Free the memory allocated to the present cell.
  633. */
  634. G_debug(1, "total cells: %ld", total_cells);
  635. G_debug(1, "nrows x ncols: %d", nrows * ncols);
  636. G_message(_("Finding cost path..."));
  637. n_processed = 0;
  638. pres_cell = get_lowest();
  639. while (pres_cell != NULL) {
  640. struct cost *ct;
  641. double N, NE, E, SE, S, SW, W, NW;
  642. double NNE, ENE, ESE, SSE, SSW, WSW, WNW, NNW;
  643. N = NE = E = SE = S = SW = W = NW = dnullval;
  644. NNE = ENE = ESE = SSE = SSW = WSW = WNW = NNW = dnullval;
  645. /* If we have surpassed the user specified maximum cost, then quit */
  646. if (maxcost && ((double)maxcost < pres_cell->min_cost))
  647. break;
  648. /* If I've already been updated, delete me */
  649. Segment_get(&cost_seg, &costs, pres_cell->row, pres_cell->col);
  650. old_min_cost = costs.cost_out;
  651. if (!Rast_is_d_null_value(&old_min_cost)) {
  652. if (pres_cell->min_cost > old_min_cost) {
  653. delete(pres_cell);
  654. pres_cell = get_lowest();
  655. continue;
  656. }
  657. }
  658. my_cost = costs.cost_in;
  659. nearest = costs.nearest;
  660. row = pres_cell->row;
  661. col = pres_cell->col;
  662. G_percent(n_processed++, total_cells, 1);
  663. /* 9 10 Order in which neighbors
  664. * 13 5 3 6 14 are visited (Knight move).
  665. * 1 2
  666. * 16 8 4 7 15
  667. * 12 11
  668. */
  669. /* drainage directions in degrees CCW from East
  670. * drainage directions are set for each neighbor and must be
  671. * read as from neighbor to current cell
  672. *
  673. * X = neighbor:
  674. *
  675. * 112.5 67.5
  676. * 157.5 135 90 45 22.5
  677. * 180 X 360
  678. * 202.5 225 270 315 337.5
  679. * 247.5 292.5
  680. *
  681. * X = present cell, directions for neighbors:
  682. *
  683. * 292.5 247.5
  684. * 337.5 315 270 225 202.5
  685. * 360 X 180
  686. * 22.5 45 90 135 157.5
  687. * 67.5 112.5
  688. */
  689. for (neighbor = 1; neighbor <= total_reviewed; neighbor++) {
  690. switch (neighbor) {
  691. case 1:
  692. col = pres_cell->col - 1;
  693. cur_dir = 360.0;
  694. break;
  695. case 2:
  696. col = pres_cell->col + 1;
  697. cur_dir = 180.0;
  698. break;
  699. case 3:
  700. row = pres_cell->row - 1;
  701. col = pres_cell->col;
  702. cur_dir = 270.0;
  703. break;
  704. case 4:
  705. row = pres_cell->row + 1;
  706. cur_dir = 90.0;
  707. break;
  708. case 5:
  709. row = pres_cell->row - 1;
  710. col = pres_cell->col - 1;
  711. cur_dir = 315.0;
  712. break;
  713. case 6:
  714. col = pres_cell->col + 1;
  715. cur_dir = 225.0;
  716. break;
  717. case 7:
  718. row = pres_cell->row + 1;
  719. cur_dir = 135.0;
  720. break;
  721. case 8:
  722. col = pres_cell->col - 1;
  723. cur_dir = 45.0;
  724. break;
  725. case 9:
  726. row = pres_cell->row - 2;
  727. col = pres_cell->col - 1;
  728. cur_dir = 292.5;
  729. break;
  730. case 10:
  731. col = pres_cell->col + 1;
  732. cur_dir = 247.5;
  733. break;
  734. case 11:
  735. row = pres_cell->row + 2;
  736. cur_dir = 112.5;
  737. break;
  738. case 12:
  739. col = pres_cell->col - 1;
  740. cur_dir = 67.5;
  741. break;
  742. case 13:
  743. row = pres_cell->row - 1;
  744. col = pres_cell->col - 2;
  745. cur_dir = 337.5;
  746. break;
  747. case 14:
  748. col = pres_cell->col + 2;
  749. cur_dir = 202.5;
  750. break;
  751. case 15:
  752. row = pres_cell->row + 1;
  753. cur_dir = 157.5;
  754. break;
  755. case 16:
  756. col = pres_cell->col - 2;
  757. cur_dir = 22.5;
  758. break;
  759. }
  760. if (row < 0 || row >= nrows)
  761. continue;
  762. if (col < 0 || col >= ncols)
  763. continue;
  764. min_cost = dnullval;
  765. Segment_get(&cost_seg, &costs, row, col);
  766. switch (neighbor) {
  767. case 1:
  768. W = costs.cost_in;
  769. fcost = (double)(W + my_cost);
  770. min_cost = pres_cell->min_cost + fcost * EW_fac;
  771. break;
  772. case 2:
  773. E = costs.cost_in;
  774. fcost = (double)(E + my_cost);
  775. min_cost = pres_cell->min_cost + fcost * EW_fac;
  776. break;
  777. case 3:
  778. N = costs.cost_in;
  779. fcost = (double)(N + my_cost);
  780. min_cost = pres_cell->min_cost + fcost * NS_fac;
  781. break;
  782. case 4:
  783. S = costs.cost_in;
  784. fcost = (double)(S + my_cost);
  785. min_cost = pres_cell->min_cost + fcost * NS_fac;
  786. break;
  787. case 5:
  788. NW = costs.cost_in;
  789. fcost = (double)(NW + my_cost);
  790. min_cost = pres_cell->min_cost + fcost * DIAG_fac;
  791. break;
  792. case 6:
  793. NE = costs.cost_in;
  794. fcost = (double)(NE + my_cost);
  795. min_cost = pres_cell->min_cost + fcost * DIAG_fac;
  796. break;
  797. case 7:
  798. SE = costs.cost_in;
  799. fcost = (double)(SE + my_cost);
  800. min_cost = pres_cell->min_cost + fcost * DIAG_fac;
  801. break;
  802. case 8:
  803. SW = costs.cost_in;
  804. fcost = (double)(SW + my_cost);
  805. min_cost = pres_cell->min_cost + fcost * DIAG_fac;
  806. break;
  807. case 9:
  808. NNW = costs.cost_in;
  809. fcost = (double)(N + NW + NNW + my_cost);
  810. min_cost = pres_cell->min_cost + fcost * V_DIAG_fac;
  811. break;
  812. case 10:
  813. NNE = costs.cost_in;
  814. fcost = (double)(N + NE + NNE + my_cost);
  815. min_cost = pres_cell->min_cost + fcost * V_DIAG_fac;
  816. break;
  817. case 11:
  818. SSE = costs.cost_in;
  819. fcost = (double)(S + SE + SSE + my_cost);
  820. min_cost = pres_cell->min_cost + fcost * V_DIAG_fac;
  821. break;
  822. case 12:
  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. WNW = costs.cost_in;
  829. fcost = (double)(W + NW + WNW + my_cost);
  830. min_cost = pres_cell->min_cost + fcost * H_DIAG_fac;
  831. break;
  832. case 14:
  833. ENE = costs.cost_in;
  834. fcost = (double)(E + NE + ENE + my_cost);
  835. min_cost = pres_cell->min_cost + fcost * H_DIAG_fac;
  836. break;
  837. case 15:
  838. ESE = costs.cost_in;
  839. fcost = (double)(E + SE + ESE + my_cost);
  840. min_cost = pres_cell->min_cost + fcost * H_DIAG_fac;
  841. break;
  842. case 16:
  843. WSW = costs.cost_in;
  844. fcost = (double)(W + SW + WSW + my_cost);
  845. min_cost = pres_cell->min_cost + fcost * H_DIAG_fac;
  846. break;
  847. }
  848. /* skip if costs could not be calculated */
  849. if (Rast_is_d_null_value(&min_cost))
  850. continue;
  851. Segment_get(&cost_seg, &costs, row, col);
  852. old_min_cost = costs.cost_out;
  853. /* add to list */
  854. if (Rast_is_d_null_value(&old_min_cost)) {
  855. costs.cost_out = min_cost;
  856. costs.nearest = nearest;
  857. Segment_put(&cost_seg, &costs, row, col);
  858. insert(min_cost, row, col);
  859. if (dir == TRUE) {
  860. Segment_put(&dir_seg, &cur_dir, row, col);
  861. }
  862. }
  863. /* update with lower costs */
  864. else if (old_min_cost > min_cost) {
  865. costs.cost_out = min_cost;
  866. costs.nearest = nearest;
  867. Segment_put(&cost_seg, &costs, row, col);
  868. insert(min_cost, row, col);
  869. if (dir == TRUE) {
  870. Segment_put(&dir_seg, &cur_dir, row, col);
  871. }
  872. }
  873. }
  874. if (have_stop_points && time_to_stop(pres_cell->row, pres_cell->col))
  875. break;
  876. ct = pres_cell;
  877. delete(pres_cell);
  878. pres_cell = get_lowest();
  879. if (ct == pres_cell)
  880. G_warning(_("Error, ct == pres_cell"));
  881. }
  882. G_percent(1, 1, 1);
  883. /* free heap */
  884. free_heap();
  885. /* Open cumulative cost layer for writing */
  886. cum_fd = Rast_open_new(cum_cost_layer, cum_data_type);
  887. cell = Rast_allocate_buf(cum_data_type);
  888. /* Open nearest start point layer */
  889. if (nearest_layer) {
  890. nearest_fd = Rast_open_new(nearest_layer, nearest_data_type);
  891. nearest_cell = Rast_allocate_buf(nearest_data_type);
  892. }
  893. else {
  894. nearest_fd = -1;
  895. nearest_cell = NULL;
  896. }
  897. nearest_size = Rast_cell_size(nearest_data_type);
  898. /* Copy segmented map to output map */
  899. G_message(_("Writing output raster map <%s>..."), cum_cost_layer);
  900. if (nearest_layer) {
  901. G_message(_("Writing raster map with nearest start point <%s>..."), nearest_layer);
  902. }
  903. cell2 = Rast_allocate_buf(data_type);
  904. {
  905. void *p;
  906. void *p2;
  907. void *p3;
  908. int cum_dsize = Rast_cell_size(cum_data_type);
  909. Rast_set_null_value(cell2, ncols, data_type);
  910. for (row = 0; row < nrows; row++) {
  911. G_percent(row, nrows, 2);
  912. if (keep_nulls)
  913. Rast_get_row(cost_fd, cell2, row, data_type);
  914. p = cell;
  915. p2 = cell2;
  916. p3 = nearest_cell;
  917. for (col = 0; col < ncols; col++) {
  918. if (keep_nulls) {
  919. if (Rast_is_null_value(p2, data_type)) {
  920. Rast_set_null_value(p, 1, cum_data_type);
  921. p = G_incr_void_ptr(p, cum_dsize);
  922. p2 = G_incr_void_ptr(p2, dsize);
  923. if (nearest_layer) {
  924. Rast_set_null_value(p3, 1, nearest_data_type);
  925. p3 = G_incr_void_ptr(p3, nearest_size);
  926. }
  927. continue;
  928. }
  929. }
  930. Segment_get(&cost_seg, &costs, row, col);
  931. min_cost = costs.cost_out;
  932. nearest = costs.nearest;
  933. if (Rast_is_d_null_value(&min_cost)) {
  934. Rast_set_null_value(p, 1, cum_data_type);
  935. if (nearest_layer)
  936. Rast_set_null_value(p3, 1, nearest_data_type);
  937. }
  938. else {
  939. if (min_cost > peak)
  940. peak = min_cost;
  941. switch (cum_data_type) {
  942. case CELL_TYPE:
  943. *(CELL *)p = (CELL)(min_cost + .5);
  944. break;
  945. case FCELL_TYPE:
  946. *(FCELL *)p = (FCELL)(min_cost);
  947. break;
  948. case DCELL_TYPE:
  949. *(DCELL *)p = (DCELL)(min_cost);
  950. break;
  951. }
  952. if (nearest_layer) {
  953. switch (nearest_data_type) {
  954. case CELL_TYPE:
  955. *(CELL *)p3 = (CELL)(nearest);
  956. break;
  957. case FCELL_TYPE:
  958. *(FCELL *)p3 = (FCELL)(nearest);
  959. break;
  960. case DCELL_TYPE:
  961. *(DCELL *)p3 = (DCELL)(nearest);
  962. break;
  963. }
  964. }
  965. }
  966. p = G_incr_void_ptr(p, cum_dsize);
  967. p2 = G_incr_void_ptr(p2, dsize);
  968. if (nearest_layer)
  969. p3 = G_incr_void_ptr(p3, nearest_size);
  970. }
  971. Rast_put_row(cum_fd, cell, cum_data_type);
  972. if (nearest_layer)
  973. Rast_put_row(nearest_fd, nearest_cell, nearest_data_type);
  974. }
  975. G_percent(1, 1, 1);
  976. G_free(cell);
  977. G_free(cell2);
  978. if (nearest_layer)
  979. G_free(nearest_cell);
  980. }
  981. if (dir == TRUE) {
  982. void *p;
  983. size_t dir_size = Rast_cell_size(dir_data_type);
  984. dir_fd = Rast_open_new(move_dir_layer, dir_data_type);
  985. dir_cell = Rast_allocate_buf(dir_data_type);
  986. G_message(_("Writing output movement direction raster map <%s>..."), move_dir_layer);
  987. for (row = 0; row < nrows; row++) {
  988. p = dir_cell;
  989. for (col = 0; col < ncols; col++) {
  990. Segment_get(&dir_seg, &cur_dir, row, col);
  991. *((FCELL *) p) = cur_dir;
  992. p = G_incr_void_ptr(p, dir_size);
  993. }
  994. Rast_put_row(dir_fd, dir_cell, dir_data_type);
  995. G_percent(row, nrows, 2);
  996. }
  997. G_percent(1, 1, 1);
  998. G_free(dir_cell);
  999. }
  1000. Segment_close(&cost_seg); /* release memory */
  1001. if (dir == TRUE)
  1002. Segment_close(&dir_seg);
  1003. Rast_close(cost_fd);
  1004. Rast_close(cum_fd);
  1005. if (dir == TRUE)
  1006. Rast_close(dir_fd);
  1007. if (nearest_layer)
  1008. Rast_close(nearest_fd);
  1009. /* writing history file */
  1010. Rast_short_history(cum_cost_layer, "raster", &history);
  1011. Rast_command_history(&history);
  1012. Rast_write_history(cum_cost_layer, &history);
  1013. if (dir == TRUE) {
  1014. Rast_short_history(move_dir_layer, "raster", &history);
  1015. Rast_command_history(&history);
  1016. Rast_write_history(move_dir_layer, &history);
  1017. }
  1018. if (nearest_layer) {
  1019. Rast_short_history(nearest_layer, "raster", &history);
  1020. Rast_command_history(&history);
  1021. Rast_write_history(nearest_layer, &history);
  1022. if (opt9->answer) {
  1023. struct Colors colors;
  1024. Rast_read_colors(opt9->answer, "", &colors);
  1025. Rast_write_colors(nearest_layer, G_mapset(), &colors);
  1026. }
  1027. else {
  1028. struct Colors colors;
  1029. struct Range range;
  1030. CELL min, max;
  1031. Rast_read_range(nearest_layer, G_mapset(), &range);
  1032. Rast_get_range_min_max(&range, &min, &max);
  1033. Rast_make_random_colors(&colors, min, max);
  1034. Rast_write_colors(nearest_layer, G_mapset(), &colors);
  1035. }
  1036. }
  1037. /* Create colours for output map */
  1038. /*
  1039. * Rast_read_range (cum_cost_layer, current_mapset, &range);
  1040. * Rast_get_range_min_max(&range, &min, &max);
  1041. * G_make_color_wave(&colors,min, max);
  1042. * Rast_write_colors (cum_cost_layer,current_mapset,&colors);
  1043. */
  1044. G_done_msg(_("Peak cost value: %g"), peak);
  1045. exit(EXIT_SUCCESS);
  1046. }
  1047. int
  1048. process_answers(char **answers, struct start_pt **points,
  1049. struct start_pt **top_start_pt)
  1050. {
  1051. int col, row;
  1052. double east, north;
  1053. struct start_pt *new_start_pt;
  1054. int got_one = 0;
  1055. int point_no = 0;
  1056. *points = NULL;
  1057. if (!answers)
  1058. return (0);
  1059. for (; *answers != NULL; answers += 2) {
  1060. if (!G_scan_easting(*answers, &east, G_projection()))
  1061. G_fatal_error(_("Illegal x coordinate <%s>"), *answers);
  1062. if (!G_scan_northing(*(answers + 1), &north, G_projection()))
  1063. G_fatal_error(_("Illegal y coordinate <%s>"), *(answers + 1));
  1064. if (east < window.west || east > window.east ||
  1065. north < window.south || north > window.north) {
  1066. G_warning(_("Warning, ignoring point outside window: %g, %g"),
  1067. east, north);
  1068. continue;
  1069. }
  1070. else
  1071. got_one = 1;
  1072. row = (window.north - north) / window.ns_res;
  1073. col = (east - window.west) / window.ew_res;
  1074. new_start_pt = (struct start_pt *)(G_malloc(sizeof(struct start_pt)));
  1075. new_start_pt->row = row;
  1076. new_start_pt->col = col;
  1077. new_start_pt->value = ++point_no;
  1078. new_start_pt->next = NULL;
  1079. if (*points == NULL) {
  1080. *points = new_start_pt;
  1081. *top_start_pt = new_start_pt;
  1082. new_start_pt->next = NULL;
  1083. }
  1084. else {
  1085. (*top_start_pt)->next = new_start_pt;
  1086. *top_start_pt = new_start_pt;
  1087. }
  1088. }
  1089. return (got_one);
  1090. }
  1091. int time_to_stop(int row, int col)
  1092. {
  1093. static int total = 0;
  1094. static int hits = 0;
  1095. struct start_pt *points;
  1096. if (total == 0) {
  1097. for (points = head_end_pt;
  1098. points != NULL; points = points->next, total++) ;
  1099. }
  1100. for (points = head_end_pt; points != NULL; points = points->next)
  1101. if (points->row == row && points->col == col) {
  1102. hits++;
  1103. if (hits == total)
  1104. return (1);
  1105. }
  1106. return (0);
  1107. }