main.c 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269
  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_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 = "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,"Input 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. G_message(_("Initializing directional output..."));
  428. for (row = 0; row < nrows; row++) {
  429. G_percent(row, nrows, 2);
  430. for (col = 0; col < ncols; col++) {
  431. Segment_put(&dir_seg, &dnullval, row, col);
  432. }
  433. }
  434. G_percent(1, 1, 1);
  435. }
  436. /* Scan the start_points layer searching for starting points.
  437. * Create a heap of starting points ordered by increasing costs.
  438. */
  439. init_heap();
  440. /* read vector with start points */
  441. if (opt7->answer) {
  442. struct Map_info In;
  443. struct line_pnts *Points;
  444. struct line_cats *Cats;
  445. struct bound_box box;
  446. struct start_pt *new_start_pt;
  447. int cat, type, npoints = 0;
  448. Points = Vect_new_line_struct();
  449. Cats = Vect_new_cats_struct();
  450. Vect_set_open_level(1); /* topology not required */
  451. if (1 > Vect_open_old(&In, opt7->answer, ""))
  452. G_fatal_error(_("Unable to open vector map <%s>"), opt7->answer);
  453. G_message(_("Reading vector map <%s> with start points..."),
  454. Vect_get_full_name(&In));
  455. Vect_rewind(&In);
  456. Vect_region_box(&window, &box);
  457. while (1) {
  458. /* register line */
  459. type = Vect_read_next_line(&In, Points, Cats);
  460. /* Note: check for dead lines is not needed, because they are skipped by V1_read_next_line_nat() */
  461. if (type == -1) {
  462. G_warning(_("Unable to read vector map"));
  463. continue;
  464. }
  465. else if (type == -2) {
  466. break;
  467. }
  468. if (!Vect_point_in_box(Points->x[0], Points->y[0], 0, &box))
  469. continue;
  470. npoints++;
  471. col = (int)Rast_easting_to_col(Points->x[0], &window);
  472. row = (int)Rast_northing_to_row(Points->y[0], &window);
  473. new_start_pt =
  474. (struct start_pt *)(G_malloc(sizeof(struct start_pt)));
  475. new_start_pt->row = row;
  476. new_start_pt->col = col;
  477. Vect_cat_get(Cats, 1, &cat);
  478. new_start_pt->value = cat;
  479. new_start_pt->next = NULL;
  480. if (head_start_pt == NULL) {
  481. head_start_pt = new_start_pt;
  482. pres_start_pt = new_start_pt;
  483. new_start_pt->next = NULL;
  484. }
  485. else {
  486. pres_start_pt->next = new_start_pt;
  487. pres_start_pt = new_start_pt;
  488. }
  489. }
  490. if (npoints < 1)
  491. G_fatal_error(_("No start points found in vector map <%s>"), Vect_get_full_name(&In));
  492. else
  493. G_verbose_message(_n("%d point found", "%d points found", npoints), npoints);
  494. Vect_close(&In);
  495. }
  496. /* read vector with stop points */
  497. if (opt8->answer) {
  498. struct Map_info In;
  499. struct line_pnts *Points;
  500. struct line_cats *Cats;
  501. struct bound_box box;
  502. struct start_pt *new_start_pt;
  503. int type;
  504. G_message(_("Reading vector map <%s> with stop points..."), opt8->answer);
  505. Points = Vect_new_line_struct();
  506. Cats = Vect_new_cats_struct();
  507. Vect_set_open_level(1); /* topology not required */
  508. if (1 > Vect_open_old(&In, opt8->answer, ""))
  509. G_fatal_error(_("Unable to open vector map <%s>"), opt8->answer);
  510. Vect_rewind(&In);
  511. Vect_region_box(&window, &box);
  512. while (1) {
  513. /* register line */
  514. type = Vect_read_next_line(&In, Points, Cats);
  515. /* Note: check for dead lines is not needed, because they are skipped by V1_read_next_line_nat() */
  516. if (type == -1) {
  517. G_warning(_("Unable to read vector map"));
  518. continue;
  519. }
  520. else if (type == -2) {
  521. break;
  522. }
  523. if (!Vect_point_in_box(Points->x[0], Points->y[0], 0, &box))
  524. continue;
  525. have_stop_points = TRUE;
  526. col = (int)Rast_easting_to_col(Points->x[0], &window);
  527. row = (int)Rast_northing_to_row(Points->y[0], &window);
  528. new_start_pt =
  529. (struct start_pt *)(G_malloc(sizeof(struct start_pt)));
  530. new_start_pt->row = row;
  531. new_start_pt->col = col;
  532. new_start_pt->next = NULL;
  533. if (head_end_pt == NULL) {
  534. head_end_pt = new_start_pt;
  535. pres_stop_pt = new_start_pt;
  536. new_start_pt->next = NULL;
  537. }
  538. else {
  539. pres_stop_pt->next = new_start_pt;
  540. pres_stop_pt = new_start_pt;
  541. }
  542. }
  543. Vect_close(&In);
  544. if (!have_stop_points)
  545. G_fatal_error(_("No stop points found in vector <%s>"), opt8->answer);
  546. }
  547. /* read raster with start points */
  548. if (opt9->answer) {
  549. int dsize2;
  550. int fd;
  551. RASTER_MAP_TYPE data_type2;
  552. int got_one = 0;
  553. search_mapset = G_find_raster(opt9->answer, "");
  554. if (search_mapset == NULL)
  555. G_fatal_error(_("Raster map <%s> not found"), opt9->answer);
  556. fd = Rast_open_old(opt9->answer, search_mapset);
  557. data_type2 = Rast_get_map_type(fd);
  558. nearest_data_type = data_type2;
  559. dsize2 = Rast_cell_size(data_type2);
  560. cell2 = Rast_allocate_buf(data_type2);
  561. if (!cell2)
  562. G_fatal_error(_("Unable to allocate memory"));
  563. G_message(_("Reading raster map <%s> with start points..."), opt9->answer);
  564. for (row = 0; row < nrows; row++) {
  565. G_percent(row, nrows, 2);
  566. Rast_get_row(fd, cell2, row, data_type2);
  567. ptr2 = cell2;
  568. for (col = 0; col < ncols; col++) {
  569. /* Did I understand that concept of cummulative cost map? - (pmx) 12 april 2000 */
  570. if (!Rast_is_null_value(ptr2, data_type2)) {
  571. double cellval;
  572. Segment_get(&cost_seg, &costs, row, col);
  573. cellval = Rast_get_d_value(ptr2, data_type2);
  574. if (start_with_raster_vals == 1) {
  575. insert(cellval, row, col);
  576. costs.cost_out = cellval;
  577. costs.nearest = cellval;
  578. Segment_put(&cost_seg, &costs, row, col);
  579. }
  580. else {
  581. value = &zero;
  582. insert(zero, row, col);
  583. costs.cost_out = *value;
  584. costs.nearest = cellval;
  585. Segment_put(&cost_seg, &costs, row, col);
  586. }
  587. got_one = 1;
  588. }
  589. ptr2 = G_incr_void_ptr(ptr2, dsize2);
  590. }
  591. }
  592. G_percent(1, 1, 1);
  593. Rast_close(fd);
  594. G_free(cell2);
  595. if (!got_one)
  596. G_fatal_error(_("No start points"));
  597. }
  598. /* If the starting points are given on the command line start a linked
  599. * list of cells ordered by increasing costs
  600. */
  601. if (head_start_pt) {
  602. struct start_pt *top_start_pt = NULL;
  603. top_start_pt = head_start_pt;
  604. while (top_start_pt != NULL) {
  605. value = &zero;
  606. if (top_start_pt->row < 0 || top_start_pt->row >= nrows
  607. || top_start_pt->col < 0 || top_start_pt->col >= ncols)
  608. G_fatal_error(_("Specified starting location outside database window"));
  609. insert(zero, top_start_pt->row, top_start_pt->col);
  610. Segment_get(&cost_seg, &costs, top_start_pt->row,
  611. top_start_pt->col);
  612. costs.cost_out = *value;
  613. costs.nearest = top_start_pt->value;
  614. Segment_put(&cost_seg, &costs, top_start_pt->row,
  615. top_start_pt->col);
  616. top_start_pt = top_start_pt->next;
  617. }
  618. }
  619. /* Loop through the heap and perform at each cell the following:
  620. * 1) If an adjacent cell has not already been assigned a value compute
  621. * the min cost and assign it.
  622. * 2) Insert the adjacent cell in the heap.
  623. * 3) Free the memory allocated to the present cell.
  624. */
  625. G_debug(1, "total cells: %ld", total_cells);
  626. G_debug(1, "nrows x ncols: %d", nrows * ncols);
  627. G_message(_("Finding cost path..."));
  628. n_processed = 0;
  629. pres_cell = get_lowest();
  630. while (pres_cell != NULL) {
  631. struct cost *ct;
  632. double N, NE, E, SE, S, SW, W, NW;
  633. double NNE, ENE, ESE, SSE, SSW, WSW, WNW, NNW;
  634. N = NE = E = SE = S = SW = W = NW = dnullval;
  635. NNE = ENE = ESE = SSE = SSW = WSW = WNW = NNW = dnullval;
  636. /* If we have surpassed the user specified maximum cost, then quit */
  637. if (maxcost && ((double)maxcost < pres_cell->min_cost))
  638. break;
  639. /* If I've already been updated, delete me */
  640. Segment_get(&cost_seg, &costs, pres_cell->row, pres_cell->col);
  641. old_min_cost = costs.cost_out;
  642. if (!Rast_is_d_null_value(&old_min_cost)) {
  643. if (pres_cell->min_cost > old_min_cost) {
  644. delete(pres_cell);
  645. pres_cell = get_lowest();
  646. continue;
  647. }
  648. }
  649. my_cost = costs.cost_in;
  650. nearest = costs.nearest;
  651. row = pres_cell->row;
  652. col = pres_cell->col;
  653. G_percent(n_processed++, total_cells, 1);
  654. /* 9 10 Order in which neighbors
  655. * 13 5 3 6 14 are visited (Knight move).
  656. * 1 2
  657. * 16 8 4 7 15
  658. * 12 11
  659. */
  660. /* drainage directions in degrees CCW from East
  661. * drainage directions are set for each neighbor and must be
  662. * read as from neighbor to current cell
  663. *
  664. * X = neighbor:
  665. *
  666. * 112.5 67.5
  667. * 157.5 135 90 45 22.5
  668. * 180 X 360
  669. * 202.5 225 270 315 337.5
  670. * 247.5 292.5
  671. *
  672. * X = present cell, directions for neighbors:
  673. *
  674. * 292.5 247.5
  675. * 337.5 315 270 225 202.5
  676. * 360 X 180
  677. * 22.5 45 90 135 157.5
  678. * 67.5 112.5
  679. */
  680. for (neighbor = 1; neighbor <= total_reviewed; neighbor++) {
  681. switch (neighbor) {
  682. case 1:
  683. col = pres_cell->col - 1;
  684. cur_dir = 360.0;
  685. break;
  686. case 2:
  687. col = pres_cell->col + 1;
  688. cur_dir = 180.0;
  689. break;
  690. case 3:
  691. row = pres_cell->row - 1;
  692. col = pres_cell->col;
  693. cur_dir = 270.0;
  694. break;
  695. case 4:
  696. row = pres_cell->row + 1;
  697. cur_dir = 90.0;
  698. break;
  699. case 5:
  700. row = pres_cell->row - 1;
  701. col = pres_cell->col - 1;
  702. cur_dir = 315.0;
  703. break;
  704. case 6:
  705. col = pres_cell->col + 1;
  706. cur_dir = 225.0;
  707. break;
  708. case 7:
  709. row = pres_cell->row + 1;
  710. cur_dir = 135.0;
  711. break;
  712. case 8:
  713. col = pres_cell->col - 1;
  714. cur_dir = 45.0;
  715. break;
  716. case 9:
  717. row = pres_cell->row - 2;
  718. col = pres_cell->col - 1;
  719. cur_dir = 292.5;
  720. break;
  721. case 10:
  722. col = pres_cell->col + 1;
  723. cur_dir = 247.5;
  724. break;
  725. case 11:
  726. row = pres_cell->row + 2;
  727. cur_dir = 112.5;
  728. break;
  729. case 12:
  730. col = pres_cell->col - 1;
  731. cur_dir = 67.5;
  732. break;
  733. case 13:
  734. row = pres_cell->row - 1;
  735. col = pres_cell->col - 2;
  736. cur_dir = 337.5;
  737. break;
  738. case 14:
  739. col = pres_cell->col + 2;
  740. cur_dir = 202.5;
  741. break;
  742. case 15:
  743. row = pres_cell->row + 1;
  744. cur_dir = 157.5;
  745. break;
  746. case 16:
  747. col = pres_cell->col - 2;
  748. cur_dir = 22.5;
  749. break;
  750. }
  751. if (row < 0 || row >= nrows)
  752. continue;
  753. if (col < 0 || col >= ncols)
  754. continue;
  755. min_cost = dnullval;
  756. Segment_get(&cost_seg, &costs, row, col);
  757. switch (neighbor) {
  758. case 1:
  759. W = costs.cost_in;
  760. fcost = (double)(W + my_cost);
  761. min_cost = pres_cell->min_cost + fcost * EW_fac;
  762. break;
  763. case 2:
  764. E = costs.cost_in;
  765. fcost = (double)(E + my_cost);
  766. min_cost = pres_cell->min_cost + fcost * EW_fac;
  767. break;
  768. case 3:
  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. S = costs.cost_in;
  775. fcost = (double)(S + my_cost);
  776. min_cost = pres_cell->min_cost + fcost * NS_fac;
  777. break;
  778. case 5:
  779. NW = costs.cost_in;
  780. fcost = (double)(NW + my_cost);
  781. min_cost = pres_cell->min_cost + fcost * DIAG_fac;
  782. break;
  783. case 6:
  784. NE = costs.cost_in;
  785. fcost = (double)(NE + my_cost);
  786. min_cost = pres_cell->min_cost + fcost * DIAG_fac;
  787. break;
  788. case 7:
  789. SE = costs.cost_in;
  790. fcost = (double)(SE + my_cost);
  791. min_cost = pres_cell->min_cost + fcost * DIAG_fac;
  792. break;
  793. case 8:
  794. SW = costs.cost_in;
  795. fcost = (double)(SW + my_cost);
  796. min_cost = pres_cell->min_cost + fcost * DIAG_fac;
  797. break;
  798. case 9:
  799. NNW = costs.cost_in;
  800. fcost = (double)(N + NW + NNW + my_cost);
  801. min_cost = pres_cell->min_cost + fcost * V_DIAG_fac;
  802. break;
  803. case 10:
  804. NNE = costs.cost_in;
  805. fcost = (double)(N + NE + NNE + my_cost);
  806. min_cost = pres_cell->min_cost + fcost * V_DIAG_fac;
  807. break;
  808. case 11:
  809. SSE = costs.cost_in;
  810. fcost = (double)(S + SE + SSE + my_cost);
  811. min_cost = pres_cell->min_cost + fcost * V_DIAG_fac;
  812. break;
  813. case 12:
  814. SSW = costs.cost_in;
  815. fcost = (double)(S + SW + SSW + my_cost);
  816. min_cost = pres_cell->min_cost + fcost * V_DIAG_fac;
  817. break;
  818. case 13:
  819. WNW = costs.cost_in;
  820. fcost = (double)(W + NW + WNW + my_cost);
  821. min_cost = pres_cell->min_cost + fcost * H_DIAG_fac;
  822. break;
  823. case 14:
  824. ENE = costs.cost_in;
  825. fcost = (double)(E + NE + ENE + my_cost);
  826. min_cost = pres_cell->min_cost + fcost * H_DIAG_fac;
  827. break;
  828. case 15:
  829. ESE = costs.cost_in;
  830. fcost = (double)(E + SE + ESE + my_cost);
  831. min_cost = pres_cell->min_cost + fcost * H_DIAG_fac;
  832. break;
  833. case 16:
  834. WSW = costs.cost_in;
  835. fcost = (double)(W + SW + WSW + my_cost);
  836. min_cost = pres_cell->min_cost + fcost * H_DIAG_fac;
  837. break;
  838. }
  839. /* skip if costs could not be calculated */
  840. if (Rast_is_d_null_value(&min_cost))
  841. continue;
  842. Segment_get(&cost_seg, &costs, row, col);
  843. old_min_cost = costs.cost_out;
  844. /* add to list */
  845. if (Rast_is_d_null_value(&old_min_cost)) {
  846. costs.cost_out = min_cost;
  847. costs.nearest = nearest;
  848. Segment_put(&cost_seg, &costs, row, col);
  849. insert(min_cost, row, col);
  850. if (dir == TRUE) {
  851. Segment_put(&dir_seg, &cur_dir, row, col);
  852. }
  853. }
  854. /* update with lower costs */
  855. else if (old_min_cost > min_cost) {
  856. costs.cost_out = min_cost;
  857. costs.nearest = nearest;
  858. Segment_put(&cost_seg, &costs, row, col);
  859. insert(min_cost, row, col);
  860. if (dir == TRUE) {
  861. Segment_put(&dir_seg, &cur_dir, row, col);
  862. }
  863. }
  864. }
  865. if (have_stop_points && time_to_stop(pres_cell->row, pres_cell->col))
  866. break;
  867. ct = pres_cell;
  868. delete(pres_cell);
  869. pres_cell = get_lowest();
  870. if (ct == pres_cell)
  871. G_warning(_("Error, ct == pres_cell"));
  872. }
  873. G_percent(1, 1, 1);
  874. /* free heap */
  875. free_heap();
  876. /* Open cumulative cost layer for writing */
  877. cum_fd = Rast_open_new(cum_cost_layer, cum_data_type);
  878. cell = Rast_allocate_buf(cum_data_type);
  879. /* Open nearest start point layer */
  880. if (nearest_layer) {
  881. nearest_fd = Rast_open_new(nearest_layer, nearest_data_type);
  882. nearest_cell = Rast_allocate_buf(nearest_data_type);
  883. }
  884. else {
  885. nearest_fd = -1;
  886. nearest_cell = NULL;
  887. }
  888. nearest_size = Rast_cell_size(nearest_data_type);
  889. /* Copy segmented map to output map */
  890. G_message(_("Writing output raster map <%s>..."), cum_cost_layer);
  891. if (nearest_layer) {
  892. G_message(_("Writing raster map with nearest start point <%s>..."), nearest_layer);
  893. }
  894. cell2 = Rast_allocate_buf(data_type);
  895. {
  896. void *p;
  897. void *p2;
  898. void *p3;
  899. int cum_dsize = Rast_cell_size(cum_data_type);
  900. Rast_set_null_value(cell2, ncols, data_type);
  901. for (row = 0; row < nrows; row++) {
  902. G_percent(row, nrows, 2);
  903. if (keep_nulls)
  904. Rast_get_row(cost_fd, cell2, row, data_type);
  905. p = cell;
  906. p2 = cell2;
  907. p3 = nearest_cell;
  908. for (col = 0; col < ncols; col++) {
  909. if (keep_nulls) {
  910. if (Rast_is_null_value(p2, data_type)) {
  911. Rast_set_null_value(p, 1, cum_data_type);
  912. p = G_incr_void_ptr(p, cum_dsize);
  913. p2 = G_incr_void_ptr(p2, dsize);
  914. if (nearest_layer) {
  915. Rast_set_null_value(p3, 1, nearest_data_type);
  916. p3 = G_incr_void_ptr(p3, nearest_size);
  917. }
  918. continue;
  919. }
  920. }
  921. Segment_get(&cost_seg, &costs, row, col);
  922. min_cost = costs.cost_out;
  923. nearest = costs.nearest;
  924. if (Rast_is_d_null_value(&min_cost)) {
  925. Rast_set_null_value(p, 1, cum_data_type);
  926. if (nearest_layer)
  927. Rast_set_null_value(p3, 1, nearest_data_type);
  928. }
  929. else {
  930. if (min_cost > peak)
  931. peak = min_cost;
  932. switch (cum_data_type) {
  933. case CELL_TYPE:
  934. *(CELL *)p = (CELL)(min_cost + .5);
  935. break;
  936. case FCELL_TYPE:
  937. *(FCELL *)p = (FCELL)(min_cost);
  938. break;
  939. case DCELL_TYPE:
  940. *(DCELL *)p = (DCELL)(min_cost);
  941. break;
  942. }
  943. if (nearest_layer) {
  944. switch (nearest_data_type) {
  945. case CELL_TYPE:
  946. *(CELL *)p3 = (CELL)(nearest);
  947. break;
  948. case FCELL_TYPE:
  949. *(FCELL *)p3 = (FCELL)(nearest);
  950. break;
  951. case DCELL_TYPE:
  952. *(DCELL *)p3 = (DCELL)(nearest);
  953. break;
  954. }
  955. }
  956. }
  957. p = G_incr_void_ptr(p, cum_dsize);
  958. p2 = G_incr_void_ptr(p2, dsize);
  959. if (nearest_layer)
  960. p3 = G_incr_void_ptr(p3, nearest_size);
  961. }
  962. Rast_put_row(cum_fd, cell, cum_data_type);
  963. if (nearest_layer)
  964. Rast_put_row(nearest_fd, nearest_cell, nearest_data_type);
  965. }
  966. G_percent(1, 1, 1);
  967. G_free(cell);
  968. G_free(cell2);
  969. if (nearest_layer)
  970. G_free(nearest_cell);
  971. }
  972. if (dir == TRUE) {
  973. void *p;
  974. size_t dir_size = Rast_cell_size(dir_data_type);
  975. dir_fd = Rast_open_new(move_dir_layer, dir_data_type);
  976. dir_cell = Rast_allocate_buf(dir_data_type);
  977. G_message(_("Writing output movement direction raster map <%s>..."), move_dir_layer);
  978. for (row = 0; row < nrows; row++) {
  979. p = dir_cell;
  980. for (col = 0; col < ncols; col++) {
  981. Segment_get(&dir_seg, &cur_dir, row, col);
  982. *((FCELL *) p) = cur_dir;
  983. p = G_incr_void_ptr(p, dir_size);
  984. }
  985. Rast_put_row(dir_fd, dir_cell, dir_data_type);
  986. G_percent(row, nrows, 2);
  987. }
  988. G_percent(1, 1, 1);
  989. G_free(dir_cell);
  990. }
  991. Segment_close(&cost_seg); /* release memory */
  992. if (dir == TRUE)
  993. Segment_close(&dir_seg);
  994. Rast_close(cost_fd);
  995. Rast_close(cum_fd);
  996. if (dir == TRUE)
  997. Rast_close(dir_fd);
  998. if (nearest_layer)
  999. Rast_close(nearest_fd);
  1000. /* writing history file */
  1001. Rast_short_history(cum_cost_layer, "raster", &history);
  1002. Rast_command_history(&history);
  1003. Rast_write_history(cum_cost_layer, &history);
  1004. if (dir == TRUE) {
  1005. Rast_short_history(move_dir_layer, "raster", &history);
  1006. Rast_command_history(&history);
  1007. Rast_write_history(move_dir_layer, &history);
  1008. }
  1009. if (nearest_layer) {
  1010. Rast_short_history(nearest_layer, "raster", &history);
  1011. Rast_command_history(&history);
  1012. Rast_write_history(nearest_layer, &history);
  1013. if (opt9->answer) {
  1014. struct Colors colors;
  1015. Rast_read_colors(opt9->answer, "", &colors);
  1016. Rast_write_colors(nearest_layer, G_mapset(), &colors);
  1017. }
  1018. else {
  1019. struct Colors colors;
  1020. struct Range range;
  1021. CELL min, max;
  1022. Rast_read_range(nearest_layer, G_mapset(), &range);
  1023. Rast_get_range_min_max(&range, &min, &max);
  1024. Rast_make_random_colors(&colors, min, max);
  1025. Rast_write_colors(nearest_layer, G_mapset(), &colors);
  1026. }
  1027. }
  1028. /* Create colours for output map */
  1029. /*
  1030. * Rast_read_range (cum_cost_layer, current_mapset, &range);
  1031. * Rast_get_range_min_max(&range, &min, &max);
  1032. * G_make_color_wave(&colors,min, max);
  1033. * Rast_write_colors (cum_cost_layer,current_mapset,&colors);
  1034. */
  1035. G_done_msg(_("Peak cost value: %g"), peak);
  1036. exit(EXIT_SUCCESS);
  1037. }
  1038. int
  1039. process_answers(char **answers, struct start_pt **points,
  1040. struct start_pt **top_start_pt)
  1041. {
  1042. int col, row;
  1043. double east, north;
  1044. struct start_pt *new_start_pt;
  1045. int got_one = 0;
  1046. int point_no = 0;
  1047. *points = NULL;
  1048. if (!answers)
  1049. return (0);
  1050. for (; *answers != NULL; answers += 2) {
  1051. if (!G_scan_easting(*answers, &east, G_projection()))
  1052. G_fatal_error(_("Illegal x coordinate <%s>"), *answers);
  1053. if (!G_scan_northing(*(answers + 1), &north, G_projection()))
  1054. G_fatal_error(_("Illegal y coordinate <%s>"), *(answers + 1));
  1055. if (east < window.west || east > window.east ||
  1056. north < window.south || north > window.north) {
  1057. G_warning(_("Warning, ignoring point outside window: %g, %g"),
  1058. east, north);
  1059. continue;
  1060. }
  1061. else
  1062. got_one = 1;
  1063. row = (window.north - north) / window.ns_res;
  1064. col = (east - window.west) / window.ew_res;
  1065. new_start_pt = (struct start_pt *)(G_malloc(sizeof(struct start_pt)));
  1066. new_start_pt->row = row;
  1067. new_start_pt->col = col;
  1068. new_start_pt->value = ++point_no;
  1069. new_start_pt->next = NULL;
  1070. if (*points == NULL) {
  1071. *points = new_start_pt;
  1072. *top_start_pt = new_start_pt;
  1073. new_start_pt->next = NULL;
  1074. }
  1075. else {
  1076. (*top_start_pt)->next = new_start_pt;
  1077. *top_start_pt = new_start_pt;
  1078. }
  1079. }
  1080. return (got_one);
  1081. }
  1082. int time_to_stop(int row, int col)
  1083. {
  1084. static int total = 0;
  1085. static int hits = 0;
  1086. struct start_pt *points;
  1087. if (total == 0) {
  1088. for (points = head_end_pt;
  1089. points != NULL; points = points->next, total++) ;
  1090. }
  1091. for (points = head_end_pt; points != NULL; points = points->next)
  1092. if (points->row == row && points->col == col) {
  1093. hits++;
  1094. if (hits == total)
  1095. return (1);
  1096. }
  1097. return (0);
  1098. }