spread.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  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. /* initialize using arbitrary value, this value is never used except for debug */
  64. min_cost = 0;
  65. ncells = nrows * ncols;
  66. G_message
  67. ("Finding spread time - number of cells visited in percentage ... %3d%%",
  68. 0);
  69. pres_cell = (struct costHa *)G_malloc(sizeof(struct costHa));
  70. get_minHa(heap, pres_cell, heap_len);
  71. G_debug(2, "begin spread: cost(%d,%d)=%f", pres_cell->row, pres_cell->col,
  72. pres_cell->min_cost);
  73. G_debug(2,
  74. " heap_len=%ld pres_cell->min_cost=%f time_lag=%d",
  75. heap_len, pres_cell->min_cost, time_lag);
  76. while (heap_len-- > 0 && pres_cell->min_cost < init_time + time_lag + 1.0) {
  77. ros_max = DATA(map_max, pres_cell->row, pres_cell->col);
  78. ros_base = DATA(map_base, pres_cell->row, pres_cell->col);
  79. dir = DATA(map_dir, pres_cell->row, pres_cell->col);
  80. /*Select end cells of links of the present cell */
  81. select_linksB(pres_cell, least / 2, comp_dens);
  82. #ifdef DEBUG
  83. to_cell = front_cell;
  84. while (to_cell != NULL) {
  85. printf("(%d,%d) ", to_cell->row, to_cell->col);
  86. to_cell = to_cell->next;
  87. }
  88. #endif
  89. /*Get a cell in the list each time, and compute culmulative costs
  90. *via the current spread cell*/
  91. to_cell = front_cell;
  92. while (to_cell != NULL) {
  93. /*calculate cumulative costs,
  94. *function returns -1 if detected a barrier */
  95. if (cumulative
  96. (pres_cell, to_cell, ros_max, ros_base, dir,
  97. &min_cost) == -1) {
  98. old_to_cell = to_cell;
  99. to_cell = to_cell->next;
  100. front_cell = to_cell;
  101. G_free(old_to_cell);
  102. continue;
  103. }
  104. G_debug(2, " finish a link: cost(%d,%d)->(%d,%d)=%f",
  105. pres_cell->row, pres_cell->col, to_cell->row,
  106. to_cell->col, min_cost);
  107. /*update the cumulative time/cost */
  108. update(pres_cell, to_cell->row, to_cell->col, to_cell->angle,
  109. min_cost);
  110. old_to_cell = to_cell;
  111. to_cell = to_cell->next;
  112. front_cell = to_cell;
  113. G_free(old_to_cell);
  114. }
  115. /*compute spotting fires */
  116. if (spotting)
  117. spot(pres_cell, dir);
  118. /*mark a visited cell */
  119. DATA(map_visit, pres_cell->row, pres_cell->col) = YES;
  120. #if 0
  121. if (display)
  122. draw_a_cell(pres_cell->row, pres_cell->col,
  123. (int)pres_cell->min_cost);
  124. #endif
  125. cell_count++;
  126. if ((100 * cell_count / ncells) % 2 == 0 &&
  127. (100 * (cell_count + (int)(0.009 * ncells)) / ncells) % 2 == 0) {
  128. G_percent(cell_count, ncells, 2);
  129. }
  130. get_minHa(heap, pres_cell, heap_len);
  131. G_debug(2,
  132. "in while: heap_len=%ld pres_cell->min_cost=%f time_lag=%d",
  133. heap_len, pres_cell->min_cost, time_lag);
  134. } /*end 'while (heap_len-- >0)' */
  135. G_free(pres_cell);
  136. /*Assign min_cost values to un-reached area */
  137. for (row = 0; row < nrows; row++) {
  138. for (col = 0; col < ncols; col++) {
  139. if (!DATA(map_visit, row, col)) {
  140. DATA(map_out, row, col) = (float)BARRIER;
  141. if (x_out)
  142. DATA(map_x_out, row, col) = 0;
  143. if (y_out)
  144. DATA(map_y_out, row, col) = 0;
  145. }
  146. }
  147. }
  148. G_debug(2, "end spread");
  149. } /*end spread () */
  150. /******* function computing cumulative spread time/cost, ***************
  151. ******* good for both adjacent cell links and non-adjacent cell links */
  152. int
  153. cumulative(struct costHa *pres_cell, struct cell_ptrHa *to_cell,
  154. int ros_max, int ros_base, int dir, float *min_cost)
  155. {
  156. float ros, xros, cost;
  157. float xstep_len;
  158. float cos_angle, sin_angle;
  159. int xrow, xcol, xsteps, count;
  160. /*most of the actions below calculate the cumulative time/cost,
  161. *from the current spread cell, of the end cell of one link*/
  162. sin_angle = sin(to_cell->angle);
  163. cos_angle = cos(to_cell->angle);
  164. if (abs(pres_cell->row - to_cell->row) >
  165. abs(pres_cell->col - to_cell->col)) {
  166. xsteps = abs(pres_cell->row - to_cell->row);
  167. xstep_len = 1 / cos_angle;
  168. if (xstep_len < 0.0)
  169. xstep_len = -xstep_len;
  170. }
  171. else {
  172. xsteps = abs(pres_cell->col - to_cell->col);
  173. xstep_len = 1 / sin_angle;
  174. if (xstep_len < 0.0)
  175. xstep_len = -xstep_len;
  176. }
  177. /*ROS value based on a 'from_cell', (elliptical cases) */
  178. ros =
  179. ros_base / (1 -
  180. (1 - ros_base / (float)ros_max) * cos(to_cell->angle -
  181. dir % 360 * PI /
  182. 180));
  183. /*the next cell */
  184. xrow = pres_cell->row - xstep_len * cos_angle + 0.5;
  185. xcol = pres_cell->col + xstep_len * sin_angle + 0.5;
  186. cost = 0.0;
  187. count = 1;
  188. while (count <= xsteps) {
  189. /*Can't go through a barrer in a path */
  190. if (DATA(map_base, xrow, xcol) <= 0)
  191. return -1;
  192. /*ROS value based on current 'to_cell', (elliptical cases) */
  193. xros =
  194. DATA(map_base, xrow,
  195. xcol) / (1 - (1 -
  196. DATA(map_base, xrow,
  197. xcol) / (float)DATA(map_max, xrow,
  198. xcol)) *
  199. cos(to_cell->angle -
  200. DATA(map_dir, xrow, xcol) % 360 * PI / 180));
  201. /*Calculate cost to this cell */
  202. cost =
  203. cost + 0.5 * (xstep_len * window.ns_res / ros +
  204. xstep_len * window.ns_res / xros);
  205. /*Update temp cell along the path, and counter */
  206. ros = xros;
  207. xrow = pres_cell->row - count * xstep_len * cos_angle + 0.5;
  208. xcol = pres_cell->col + count * xstep_len * sin_angle + 0.5;
  209. count++;
  210. } /*end'while (count<= ..)' */
  211. G_debug(2, " in cumulatvie() cost=%.2f pre min_cost=%.2f",
  212. cost, *min_cost);
  213. /*from the origin, cumulative time/cost of the end cell of one link */
  214. *min_cost = pres_cell->min_cost + cost;
  215. G_debug(2, " in cumulatvie() post min_cost=%.2f",
  216. *min_cost);
  217. return 0;
  218. }
  219. /****** function for updating the cumulative cost/time, possibaly ********
  220. ****** back path x,y coordinates, both in the output(s) and the heap ********/
  221. void
  222. update(struct costHa *pres_cell, int row, int col, double angle,
  223. float min_cost)
  224. {
  225. if (DATA(map_out, row, col) < -1.0) {
  226. G_debug(2, " insert: out(%d,%d)=%f min_cost=%f", row, col,
  227. DATA(map_out, row, col), min_cost);
  228. DATA(map_out, row, col) = min_cost;
  229. if (x_out)
  230. DATA(map_x_out, row, col) = pres_cell->col;
  231. if (y_out)
  232. DATA(map_y_out, row, col) = pres_cell->row;
  233. insertHa(min_cost, angle, row, col, heap, &heap_len);
  234. #if 0
  235. if (display && min_cost < init_time + time_lag + 1.0)
  236. draw_a_burning_cell(row, col);
  237. #endif
  238. }
  239. else {
  240. if (DATA(map_out, row, col) > min_cost + 0.001) {
  241. G_debug(2, " replace: out(%d,%d)=%f min_cost=%f", row, col,
  242. DATA(map_out, row, col), min_cost);
  243. DATA(map_out, row, col) = min_cost;
  244. if (x_out)
  245. DATA(map_x_out, row, col) = pres_cell->col;
  246. if (y_out)
  247. DATA(map_y_out, row, col) = pres_cell->row;
  248. replaceHa(min_cost, angle, row, col, heap, &heap_len);
  249. #if 0
  250. if (display && min_cost < init_time + time_lag + 1.0)
  251. draw_a_burning_cell(row, col);
  252. #endif
  253. }
  254. }
  255. }