do_astar.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. #include <stdlib.h>
  2. #include <math.h>
  3. #include <grass/raster.h>
  4. #include <grass/glocale.h>
  5. #include "local_proto.h"
  6. #define GET_PARENT(c) ((((GW_LARGE_INT)(c) - 2) >> 3) + 1)
  7. #define GET_CHILD(p) (((GW_LARGE_INT)(p) << 3) - 6)
  8. HEAP_PNT heap_drop(void);
  9. static double get_slope(CELL, CELL, double);
  10. int do_astar(void)
  11. {
  12. int r, c, r_nbr, c_nbr, ct_dir;
  13. GW_LARGE_INT first_cum, count;
  14. int nextdr[8] = { 1, -1, 0, 0, -1, 1, 1, -1 };
  15. int nextdc[8] = { 0, 0, -1, 1, 1, -1, 1, -1 };
  16. CELL ele_val, ele_up, ele_nbr[8];
  17. WAT_ALT wa;
  18. ASP_FLAG af;
  19. char is_in_list, is_worked;
  20. HEAP_PNT heap_p;
  21. /* sides
  22. * |7|1|4|
  23. * |2| |3|
  24. * |5|0|6|
  25. */
  26. int nbr_ew[8] = { 0, 1, 2, 3, 1, 0, 0, 1 };
  27. int nbr_ns[8] = { 0, 1, 2, 3, 3, 2, 3, 2 };
  28. double dx, dy, dist_to_nbr[8], ew_res, ns_res;
  29. double slope[8];
  30. struct Cell_head window;
  31. int skip_diag;
  32. count = 0;
  33. first_cum = n_points;
  34. G_message(_("A* Search..."));
  35. Rast_get_window(&window);
  36. for (ct_dir = 0; ct_dir < sides; ct_dir++) {
  37. /* get r, c (r_nbr, c_nbr) for neighbours */
  38. r_nbr = nextdr[ct_dir];
  39. c_nbr = nextdc[ct_dir];
  40. /* account for rare cases when ns_res != ew_res */
  41. dy = abs(r_nbr) * window.ns_res;
  42. dx = abs(c_nbr) * window.ew_res;
  43. if (ct_dir < 4)
  44. dist_to_nbr[ct_dir] = dx + dy;
  45. else
  46. dist_to_nbr[ct_dir] = sqrt(dx * dx + dy * dy);
  47. }
  48. ew_res = window.ew_res;
  49. ns_res = window.ns_res;
  50. while (heap_size > 0) {
  51. G_percent(count++, n_points, 1);
  52. if (count > n_points)
  53. G_fatal_error(_("%lld surplus points"),
  54. heap_size);
  55. if (heap_size > n_points)
  56. G_fatal_error
  57. (_("Too many points in heap %lld, should be %lld"),
  58. heap_size, n_points);
  59. heap_p = heap_drop();
  60. r = heap_p.pnt.r;
  61. c = heap_p.pnt.c;
  62. ele_val = heap_p.ele;
  63. for (ct_dir = 0; ct_dir < sides; ct_dir++) {
  64. /* get r, c (r_nbr, c_nbr) for neighbours */
  65. r_nbr = r + nextdr[ct_dir];
  66. c_nbr = c + nextdc[ct_dir];
  67. slope[ct_dir] = -1;
  68. ele_nbr[ct_dir] = 0;
  69. skip_diag = 0;
  70. /* check that neighbour is within region */
  71. if (r_nbr < 0 || r_nbr >= nrows || c_nbr < 0 || c_nbr >= ncols)
  72. continue;
  73. seg_get(&aspflag, (char *)&af, r_nbr, c_nbr);
  74. is_in_list = FLAG_GET(af.flag, INLISTFLAG);
  75. is_worked = FLAG_GET(af.flag, WORKEDFLAG);
  76. if (!is_worked) {
  77. seg_get(&watalt, (char *)&wa, r_nbr, c_nbr);
  78. ele_nbr[ct_dir] = wa.ele;
  79. slope[ct_dir] = get_slope(ele_val, ele_nbr[ct_dir],
  80. dist_to_nbr[ct_dir]);
  81. }
  82. /* avoid diagonal flow direction bias */
  83. if (!is_in_list || (!is_worked && af.asp < 0)) {
  84. if (ct_dir > 3 && slope[ct_dir] > 0) {
  85. if (slope[nbr_ew[ct_dir]] >= 0) {
  86. /* slope to ew nbr > slope to center */
  87. if (slope[ct_dir] <
  88. get_slope(ele_nbr[nbr_ew[ct_dir]],
  89. ele_nbr[ct_dir], ew_res))
  90. skip_diag = 1;
  91. }
  92. if (!skip_diag && slope[nbr_ns[ct_dir]] >= 0) {
  93. /* slope to ns nbr > slope to center */
  94. if (slope[ct_dir] <
  95. get_slope(ele_nbr[nbr_ns[ct_dir]],
  96. ele_nbr[ct_dir], ns_res))
  97. skip_diag = 1;
  98. }
  99. }
  100. }
  101. if (!skip_diag) {
  102. if (!is_in_list) {
  103. ele_up = ele_nbr[ct_dir];
  104. af.asp = drain[r_nbr - r + 1][c_nbr - c + 1];
  105. heap_add(r_nbr, c_nbr, ele_up);
  106. FLAG_SET(af.flag, INLISTFLAG);
  107. seg_put(&aspflag, (char *)&af, r_nbr, c_nbr);
  108. }
  109. else if (!is_worked) {
  110. if (FLAG_GET(af.flag, EDGEFLAG)) {
  111. /* neighbour is edge in list, not yet worked */
  112. if (af.asp < 0 && slope[ct_dir] > 0) {
  113. /* adjust flow direction for edge cell */
  114. af.asp = drain[r_nbr - r + 1][c_nbr - c + 1];
  115. seg_put(&aspflag, (char *)&af, r_nbr, c_nbr);
  116. }
  117. }
  118. else if (FLAG_GET(af.flag, DEPRFLAG)) {
  119. G_debug(3, "real depression");
  120. /* neighbour is inside real depression, not yet worked */
  121. if (af.asp == 0 && ele_val <= ele_nbr[ct_dir]) {
  122. af.asp = drain[r_nbr - r + 1][c_nbr - c + 1];
  123. FLAG_UNSET(af.flag, DEPRFLAG);
  124. seg_put(&aspflag, (char *)&af, r_nbr, c_nbr);
  125. }
  126. }
  127. }
  128. }
  129. } /* end neighbours */
  130. /* add astar points to sorted list for flow accumulation and stream extraction */
  131. first_cum--;
  132. seg_put(&astar_pts, (char *)&heap_p.pnt, 0, first_cum);
  133. seg_get(&aspflag, (char *)&af, r, c);
  134. FLAG_SET(af.flag, WORKEDFLAG);
  135. seg_put(&aspflag, (char *)&af, r, c);
  136. } /* end A* search */
  137. G_percent(n_points, n_points, 1); /* finish it */
  138. return 1;
  139. }
  140. /*
  141. * compare function for heap
  142. * returns 1 if point1 < point2 else 0
  143. */
  144. static int heap_cmp(HEAP_PNT *a, HEAP_PNT *b)
  145. {
  146. if (a->ele < b->ele)
  147. return 1;
  148. else if (a->ele == b->ele) {
  149. if (a->added < b->added)
  150. return 1;
  151. }
  152. return 0;
  153. }
  154. static int sift_up(GW_LARGE_INT start, HEAP_PNT child_p)
  155. {
  156. GW_LARGE_INT parent, child;
  157. HEAP_PNT heap_p;
  158. child = start;
  159. while (child > 1) {
  160. parent = GET_PARENT(child);
  161. seg_get(&search_heap, (char *)&heap_p, 0, parent);
  162. /* push parent point down if child is smaller */
  163. if (heap_cmp(&child_p, &heap_p)) {
  164. seg_put(&search_heap, (char *)&heap_p, 0, child);
  165. child = parent;
  166. }
  167. else
  168. /* no more sifting up, found slot for child */
  169. break;
  170. }
  171. /* add child to heap */
  172. seg_put(&search_heap, (char *)&child_p, 0, child);
  173. return 0;
  174. }
  175. /*
  176. * add item to heap
  177. * returns heap_size
  178. */
  179. GW_LARGE_INT heap_add(int r, int c, CELL ele)
  180. {
  181. HEAP_PNT heap_p;
  182. /* add point to next free position */
  183. heap_size++;
  184. heap_p.added = nxt_avail_pt;
  185. heap_p.ele = ele;
  186. heap_p.pnt.r = r;
  187. heap_p.pnt.c = c;
  188. nxt_avail_pt++;
  189. /* sift up: move new point towards top of heap */
  190. sift_up(heap_size, heap_p);
  191. return heap_size;
  192. }
  193. /*
  194. * drop item from heap
  195. * returns heap size
  196. */
  197. HEAP_PNT heap_drop(void)
  198. {
  199. GW_LARGE_INT child, childr, parent;
  200. GW_LARGE_INT i;
  201. HEAP_PNT child_p, childr_p, last_p, root_p;
  202. seg_get(&search_heap, (char *)&last_p, 0, heap_size);
  203. seg_get(&search_heap, (char *)&root_p, 0, 1);
  204. if (heap_size == 1) {
  205. heap_size = 0;
  206. return root_p;
  207. }
  208. parent = 1;
  209. while ((child = GET_CHILD(parent)) < heap_size) {
  210. seg_get(&search_heap, (char *)&child_p, 0, child);
  211. if (child < heap_size) {
  212. childr = child + 1;
  213. i = child + 8;
  214. while (childr < heap_size && childr < i) {
  215. seg_get(&search_heap, (char *)&childr_p, 0, childr);
  216. if (heap_cmp(&childr_p, &child_p)) {
  217. child = childr;
  218. child_p = childr_p;
  219. }
  220. childr++;
  221. }
  222. }
  223. if (heap_cmp(&last_p, &child_p)) {
  224. break;
  225. }
  226. /* move hole down */
  227. seg_put(&search_heap, (char *)&child_p, 0, parent);
  228. parent = child;
  229. }
  230. /* fill hole */
  231. if (parent < heap_size) {
  232. seg_put(&search_heap, (char *)&last_p, 0, parent);
  233. }
  234. /* the actual drop */
  235. heap_size--;
  236. return root_p;
  237. }
  238. static double get_slope(CELL ele, CELL up_ele, double dist)
  239. {
  240. if (ele >= up_ele)
  241. return 0.0;
  242. else
  243. return (double)(up_ele - ele) / dist;
  244. }