spread.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. /***********************************************************************
  2. *
  3. * spread.c in ../r.spread
  4. *
  5. * This is a raster version of Dijkstra's shortest path algorithm
  6. * that is suited for simulating elliptical spread phenomena. It
  7. * 1) starts from each spread origin (stored in
  8. * a linked list of type costHa) - spread();
  9. * 2) selects appropriate cells as links for the current
  10. * spread cell and stored in a linked list of type
  11. * cell_ptrHa - select() ;
  12. * A) caculates the cumulative cost (time) of the
  13. * end cell of each link - calculate();
  14. * B) compares this new cumulative cost (time) with
  15. * the previously computed cumulative time/cost,
  16. * if there is any, of the same cell - update();
  17. * C) puts this cell into a min-heap and puts the
  18. * new cumulative cost (time) together with UTM
  19. * coordinates in the cumulative cost (time)
  20. * map, x (East) map and y (North) map if
  21. * there is no previous cumulative cost (time);
  22. * otherwise, if the new cumulative cost (time)
  23. * is less, replaces with it both in the heap
  24. * and the output maps - update().
  25. * 3) gets the first cell in the min-heap, which is the
  26. * cell with the least cumulative cost (time), and
  27. * repeats Step 2 until the heap is empty or desired
  28. * simulated cumulative cost (time) is reached - spread().
  29. *
  30. ***********************************************************************/
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <math.h>
  34. #include <grass/gis.h>
  35. #include <grass/raster.h>
  36. #include "cmd_line.h"
  37. #include "costHa.h"
  38. #include "cell_ptrHa.h"
  39. #include "local_proto.h"
  40. #ifndef PI
  41. #define PI M_PI
  42. #endif
  43. #define DATA(map, r, c) (map)[(r) * ncols + (c)]
  44. /*#define DEBUG */
  45. extern CELL *map_max, *map_base, *map_dir, *map_visit;
  46. extern CELL *map_x_out, *map_y_out;
  47. extern float *map_out;
  48. extern int BARRIER;
  49. extern int nrows, ncols;
  50. /* extern float PI; */
  51. extern long heap_len;
  52. extern struct costHa *heap;
  53. extern struct Cell_head window;
  54. struct cell_ptrHa *front_cell = NULL, *rear_cell = NULL;
  55. void spread(void)
  56. {
  57. float min_cost;
  58. int ros_max, ros_base, dir;
  59. int row, col;
  60. int cell_count = 0, ncells = 0;
  61. struct cell_ptrHa *to_cell, *old_to_cell;
  62. struct costHa *pres_cell;
  63. ncells = nrows * ncols;
  64. G_message
  65. ("Finding spread time - number of cells visited in percentage ... %3d%%",
  66. 0);
  67. pres_cell = (struct costHa *)G_malloc(sizeof(struct costHa));
  68. get_minHa(heap, pres_cell, heap_len);
  69. G_debug(2, "begin spread: cost(%d,%d)=%f", pres_cell->row, pres_cell->col,
  70. pres_cell->min_cost);
  71. G_debug(2,
  72. " heap_len=%ld pres_cell->min_cost=%f time_lag=%d",
  73. heap_len, pres_cell->min_cost, time_lag);
  74. while (heap_len-- > 0 && pres_cell->min_cost < init_time + time_lag + 1.0) {
  75. ros_max = DATA(map_max, pres_cell->row, pres_cell->col);
  76. ros_base = DATA(map_base, pres_cell->row, pres_cell->col);
  77. dir = DATA(map_dir, pres_cell->row, pres_cell->col);
  78. /*Select end cells of links of the present cell */
  79. select_linksB(pres_cell, least / 2, comp_dens);
  80. #ifdef DEBUG
  81. to_cell = front_cell;
  82. while (to_cell != NULL) {
  83. printf("(%d,%d) ", to_cell->row, to_cell->col);
  84. to_cell = to_cell->next;
  85. }
  86. #endif
  87. /*Get a cell in the list each time, and compute culmulative costs
  88. *via the current spread cell*/
  89. to_cell = front_cell;
  90. while (to_cell != NULL) {
  91. /*calculate cumulative costs,
  92. *function returns -1 if detected a barrier */
  93. if (cumulative
  94. (pres_cell, to_cell, ros_max, ros_base, dir,
  95. &min_cost) == -1) {
  96. old_to_cell = to_cell;
  97. to_cell = to_cell->next;
  98. front_cell = to_cell;
  99. G_free(old_to_cell);
  100. continue;
  101. }
  102. G_debug(2, " finish a link: cost(%d,%d)->(%d,%d)=%f",
  103. pres_cell->row, pres_cell->col, to_cell->row,
  104. to_cell->col, min_cost);
  105. /*update the cumulative time/cost */
  106. update(pres_cell, to_cell->row, to_cell->col, to_cell->angle,
  107. min_cost);
  108. old_to_cell = to_cell;
  109. to_cell = to_cell->next;
  110. front_cell = to_cell;
  111. G_free(old_to_cell);
  112. }
  113. /*compute spotting fires */
  114. if (spotting)
  115. spot(pres_cell, dir);
  116. /*mark a visited cell */
  117. DATA(map_visit, pres_cell->row, pres_cell->col) = YES;
  118. #if 0
  119. if (display)
  120. draw_a_cell(pres_cell->row, pres_cell->col,
  121. (int)pres_cell->min_cost);
  122. #endif
  123. cell_count++;
  124. if ((100 * cell_count / ncells) % 2 == 0 &&
  125. (100 * (cell_count + (int)(0.009 * ncells)) / ncells) % 2 == 0) {
  126. G_percent(cell_count, ncells, 2);
  127. }
  128. get_minHa(heap, pres_cell, heap_len);
  129. G_debug(2,
  130. "in while: heap_len=%ld pres_cell->min_cost=%f time_lag=%d",
  131. heap_len, pres_cell->min_cost, time_lag);
  132. } /*end 'while (heap_len-- >0)' */
  133. G_free(pres_cell);
  134. /*Assign min_cost values to un-reached area */
  135. for (row = 0; row < nrows; row++) {
  136. for (col = 0; col < ncols; col++) {
  137. if (!DATA(map_visit, row, col)) {
  138. DATA(map_out, row, col) = (float)BARRIER;
  139. if (x_out)
  140. DATA(map_x_out, row, col) = 0;
  141. if (y_out)
  142. DATA(map_y_out, row, col) = 0;
  143. }
  144. }
  145. }
  146. G_debug(2, "end spread");
  147. } /*end spread () */
  148. /******* function computing cumulative spread time/cost, ***************
  149. ******* good for both adjacent cell links and non-adjacent cell links */
  150. int
  151. cumulative(struct costHa *pres_cell, struct cell_ptrHa *to_cell,
  152. int ros_max, int ros_base, int dir, float *min_cost)
  153. {
  154. float ros, xros, cost;
  155. float xstep_len;
  156. float cos_angle, sin_angle;
  157. int xrow, xcol, xsteps, count;
  158. /*most of the actions below calculate the cumulative time/cost,
  159. *from the current spread cell, of the end cell of one link*/
  160. sin_angle = sin(to_cell->angle);
  161. cos_angle = cos(to_cell->angle);
  162. if (abs(pres_cell->row - to_cell->row) >
  163. abs(pres_cell->col - to_cell->col)) {
  164. xsteps = abs(pres_cell->row - to_cell->row);
  165. xstep_len = 1 / cos_angle;
  166. if (xstep_len < 0.0)
  167. xstep_len = -xstep_len;
  168. }
  169. else {
  170. xsteps = abs(pres_cell->col - to_cell->col);
  171. xstep_len = 1 / sin_angle;
  172. if (xstep_len < 0.0)
  173. xstep_len = -xstep_len;
  174. }
  175. /*ROS value based on a 'from_cell', (elliptical cases) */
  176. ros =
  177. ros_base / (1 -
  178. (1 - ros_base / (float)ros_max) * cos(to_cell->angle -
  179. dir % 360 * PI /
  180. 180));
  181. /*the next cell */
  182. xrow = pres_cell->row - xstep_len * cos_angle + 0.5;
  183. xcol = pres_cell->col + xstep_len * sin_angle + 0.5;
  184. cost = 0.0;
  185. count = 1;
  186. while (count <= xsteps) {
  187. /*Can't go through a barrer in a path */
  188. if (DATA(map_base, xrow, xcol) <= 0)
  189. return -1;
  190. /*ROS value based on current 'to_cell', (elliptical cases) */
  191. xros =
  192. DATA(map_base, xrow,
  193. xcol) / (1 - (1 -
  194. DATA(map_base, xrow,
  195. xcol) / (float)DATA(map_max, xrow,
  196. xcol)) *
  197. cos(to_cell->angle -
  198. DATA(map_dir, xrow, xcol) % 360 * PI / 180));
  199. /*Calculate cost to this cell */
  200. cost =
  201. cost + 0.5 * (xstep_len * window.ns_res / ros +
  202. xstep_len * window.ns_res / xros);
  203. /*Update temp cell along the path, and counter */
  204. ros = xros;
  205. xrow = pres_cell->row - count * xstep_len * cos_angle + 0.5;
  206. xcol = pres_cell->col + count * xstep_len * sin_angle + 0.5;
  207. count++;
  208. } /*end'while (count<= ..)' */
  209. G_debug(2, " in cumulatvie() cost=%.2f pre min_cost=%.2f",
  210. cost, *min_cost);
  211. /*from the origin, cumulative time/cost of the end cell of one link */
  212. *min_cost = pres_cell->min_cost + cost;
  213. G_debug(2, " in cumulatvie() post min_cost=%.2f",
  214. *min_cost);
  215. return 0;
  216. }
  217. /****** function for updating the cumulative cost/time, possibaly ********
  218. ****** back path x,y coordinates, both in the output(s) and the heap ********/
  219. void
  220. update(struct costHa *pres_cell, int row, int col, double angle,
  221. float min_cost)
  222. {
  223. if (DATA(map_out, row, col) < -1.0) {
  224. G_debug(2, " insert: out(%d,%d)=%f min_cost=%f", row, col,
  225. DATA(map_out, row, col), min_cost);
  226. DATA(map_out, row, col) = min_cost;
  227. if (x_out)
  228. DATA(map_x_out, row, col) = pres_cell->col;
  229. if (y_out)
  230. DATA(map_y_out, row, col) = pres_cell->row;
  231. insertHa(min_cost, angle, row, col, heap, &heap_len);
  232. #if 0
  233. if (display && min_cost < init_time + time_lag + 1.0)
  234. draw_a_burning_cell(row, col);
  235. #endif
  236. }
  237. else {
  238. if (DATA(map_out, row, col) > min_cost + 0.001) {
  239. G_debug(2, " replace: out(%d,%d)=%f min_cost=%f", row, col,
  240. DATA(map_out, row, col), min_cost);
  241. DATA(map_out, row, col) = min_cost;
  242. if (x_out)
  243. DATA(map_x_out, row, col) = pres_cell->col;
  244. if (y_out)
  245. DATA(map_y_out, row, col) = pres_cell->row;
  246. replaceHa(min_cost, angle, row, col, heap, &heap_len);
  247. #if 0
  248. if (display && min_cost < init_time + time_lag + 1.0)
  249. draw_a_burning_cell(row, col);
  250. #endif
  251. }
  252. }
  253. }