statusstructure.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. /****************************************************************************
  2. *
  3. * MODULE: r.viewshed
  4. *
  5. * AUTHOR(S): Laura Toma, Bowdoin College - ltoma@bowdoin.edu
  6. * Yi Zhuang - yzhuang@bowdoin.edu
  7. * Ported to GRASS by William Richard -
  8. * wkrichar@bowdoin.edu or willster3021@gmail.com
  9. * Markus Metz: surface interpolation
  10. *
  11. * Date: april 2011
  12. *
  13. * PURPOSE: To calculate the viewshed (the visible cells in the
  14. * raster) for the given viewpoint (observer) location. The
  15. * visibility model is the following: Two points in the raster are
  16. * considered visible to each other if the cells where they belong are
  17. * visible to each other. Two cells are visible to each other if the
  18. * line-of-sight that connects their centers does not intersect the
  19. * terrain. The terrain is NOT viewed as a tesselation of flat cells,
  20. * i.e. if the line-of-sight does not pass through the cell center,
  21. * elevation is determined using bilinear interpolation.
  22. * The viewshed algorithm is efficient both in
  23. * terms of CPU operations and I/O operations. It has worst-case
  24. * complexity O(n lg n) in the RAM model and O(sort(n)) in the
  25. * I/O-model. For the algorithm and all the other details see the
  26. * paper: "Computing Visibility on * Terrains in External Memory" by
  27. * Herman Haverkort, Laura Toma and Yi Zhuang.
  28. *
  29. * COPYRIGHT: (C) 2008 by the GRASS Development Team
  30. *
  31. * This program is free software under the GNU General Public License
  32. * (>=v2). Read the file COPYING that comes with GRASS for details.
  33. *
  34. *****************************************************************************/
  35. #include <math.h>
  36. #include <stdio.h>
  37. #include <stdlib.h>
  38. #include <assert.h>
  39. extern "C"
  40. {
  41. #include <grass/gis.h>
  42. #include <grass/glocale.h>
  43. }
  44. #include "grass.h"
  45. #include "statusstructure.h"
  46. /*SMALLEST_GRADIENT is defined in rbbst.h */
  47. /* ------------------------------------------------------------ */
  48. /*find the vertical angle in degrees between the viewpoint and the
  49. point represented by the StatusNode. Assumes all values (except
  50. gradient) in sn have been filled. The value returned is in [0,
  51. 180]. A value of 0 is directly below the specified viewing position,
  52. 90 is due horizontal, and 180 is directly above the observer.
  53. If doCurv is set we need to consider the curvature of the
  54. earth */
  55. float get_vertical_angle(Viewpoint vp, StatusNode sn, surface_type elev, int doCurv)
  56. {
  57. /*determine the difference in elevation, based on the curvature */
  58. double diffElev;
  59. diffElev = vp.elev - elev;
  60. /*calculate and return the angle in degrees */
  61. assert(fabs(sn.dist2vp) > 0.001);
  62. /* 0 above, 180 below */
  63. if (diffElev >= 0.0)
  64. return (atan(sqrt(sn.dist2vp) / diffElev) * (180 / M_PI));
  65. else
  66. return (atan(fabs(diffElev) / sqrt(sn.dist2vp)) * (180 / M_PI) + 90);
  67. /* 180 above, 0 below */
  68. if (diffElev >= 0.0)
  69. return (atan(diffElev / sqrt(sn.dist2vp)) * (180 / M_PI) + 90);
  70. else
  71. return (atan(sqrt(sn.dist2vp) / fabs(diffElev)) * (180 / M_PI));
  72. }
  73. /* ------------------------------------------------------------ */
  74. /*return an estimate of the size of active structure */
  75. long long get_active_str_size_bytes(GridHeader * hd)
  76. {
  77. long long sizeBytes;
  78. G_verbose_message(_("Estimated size active structure:"));
  79. G_verbose_message(_(" (key=%d, ptr=%d, total node=%d B)"),
  80. (int)sizeof(TreeValue),
  81. (int)sizeof(TreeNode *), (int)sizeof(TreeNode));
  82. sizeBytes = sizeof(TreeNode) * std::max(hd->ncols, hd->nrows);
  83. G_verbose_message(_(" Total= %lld B"), sizeBytes);
  84. return sizeBytes;
  85. }
  86. /* ------------------------------------------------------------ */
  87. /*given a StatusNode, fill in its dist2vp and gradient */
  88. void calculate_dist_n_gradient(StatusNode * sn, double elev,
  89. Viewpoint * vp, GridHeader hd)
  90. {
  91. assert(sn && vp);
  92. /*sqrt is expensive
  93. //sn->dist2vp = sqrt((float) ( pow(sn->row - vp->row,2.0) +
  94. // pow(sn->col - vp->col,2.0)));
  95. //sn->gradient = (sn->elev - vp->elev)/(sn->dist2vp); */
  96. double diffElev = elev - vp->elev;
  97. if (G_projection() == PROJECTION_LL) {
  98. double dist = G_distance(Rast_col_to_easting(sn->col + 0.5, &(hd.window)),
  99. Rast_row_to_northing(sn->row + 0.5, &(hd.window)),
  100. Rast_col_to_easting(vp->col + 0.5, &(hd.window)),
  101. Rast_row_to_northing(vp->row + 0.5, &(hd.window)));
  102. sn->dist2vp = dist * dist;
  103. }
  104. else {
  105. double dx = ((double)sn->col - vp->col) * hd.ew_res;
  106. double dy = ((double)sn->row - vp->row) * hd.ns_res;
  107. sn->dist2vp = (dx * dx) + (dy * dy);
  108. }
  109. if (diffElev == 0) {
  110. sn->gradient[1] = 0;
  111. return;
  112. }
  113. /* PI / 2 above, - PI / 2 below, like r.los */
  114. sn->gradient[1] = atan(diffElev / sqrt(sn->dist2vp));
  115. return;
  116. /* PI above, 0 below. slower than r.los - like */
  117. if (diffElev >= 0.0)
  118. sn->gradient[1] = (atan(diffElev / sqrt(sn->dist2vp)) + M_PI / 2);
  119. else
  120. sn->gradient[1] = (atan(sqrt(sn->dist2vp) / fabs(diffElev)));
  121. return;
  122. /* a little bit faster but not accurate enough */
  123. sn->gradient[1] = (diffElev * diffElev) / (sn->dist2vp);
  124. /*maintain sign */
  125. if (elev < vp->elev)
  126. sn->gradient[1] = -sn->gradient[1];
  127. return;
  128. }
  129. /* ------------------------------------------------------------ */
  130. /* calculate gradient for ENTERING or EXITING event */
  131. void calculate_event_gradient(StatusNode * sn, int e_idx,
  132. double row, double col, double elev,
  133. Viewpoint * vp, GridHeader hd)
  134. {
  135. assert(sn && vp);
  136. /*sqrt is expensive
  137. //sn->dist2vp = sqrt((float) ( pow(sn->row - vp->row,2.0) +
  138. // pow(sn->col - vp->col,2.0)));
  139. //sn->gradient = (sn->elev - vp->elev)/(sn->dist2vp); */
  140. double diffElev = elev - vp->elev;
  141. double dist2vp;
  142. if (G_projection() == PROJECTION_LL) {
  143. double dist = G_distance(Rast_col_to_easting(col + 0.5, &(hd.window)),
  144. Rast_row_to_northing(row + 0.5, &(hd.window)),
  145. Rast_col_to_easting(vp->col + 0.5, &(hd.window)),
  146. Rast_row_to_northing(vp->row + 0.5, &(hd.window)));
  147. dist2vp = dist * dist;
  148. }
  149. else {
  150. double dx = (col - vp->col) * hd.ew_res;
  151. double dy = (row - vp->row) * hd.ns_res;
  152. dist2vp = (dx * dx) + (dy * dy);
  153. }
  154. /* PI / 2 above, - PI / 2 below */
  155. sn->gradient[e_idx] = atan(diffElev / sqrt(dist2vp));
  156. return;
  157. /* PI above, 0 below. slower than r.los - like */
  158. if (diffElev >= 0.0)
  159. sn->gradient[e_idx] = (atan(diffElev / sqrt(dist2vp)) + M_PI / 2);
  160. else
  161. sn->gradient[e_idx] = (atan(sqrt(dist2vp) / fabs(diffElev)));
  162. return;
  163. /* faster but not accurate enough */
  164. sn->gradient[e_idx] = (diffElev * diffElev) / (dist2vp);
  165. /*maintain sign */
  166. if (elev < vp->elev)
  167. sn->gradient[e_idx] = -sn->gradient[e_idx];
  168. return;
  169. }
  170. /* ------------------------------------------------------------ */
  171. /*create an empty status list */
  172. StatusList *create_status_struct()
  173. {
  174. StatusList *sl;
  175. sl = (StatusList *) G_malloc(sizeof(StatusList));
  176. assert(sl);
  177. TreeValue tv;
  178. tv.gradient[0] = SMALLEST_GRADIENT;
  179. tv.gradient[1] = SMALLEST_GRADIENT;
  180. tv.gradient[2] = SMALLEST_GRADIENT;
  181. tv.angle[0] = 0;
  182. tv.angle[1] = 0;
  183. tv.angle[2] = 0;
  184. tv.key = 0;
  185. tv.maxGradient = SMALLEST_GRADIENT;
  186. sl->rbt = create_tree(tv);
  187. return sl;
  188. }
  189. /* ------------------------------------------------------------ */
  190. /*delete a status structure */
  191. void delete_status_structure(StatusList * sl)
  192. {
  193. assert(sl);
  194. delete_tree(sl->rbt);
  195. G_free(sl);
  196. return;
  197. }
  198. /* ------------------------------------------------------------ */
  199. /*delete the statusNode with the given key */
  200. void delete_from_status_struct(StatusList * sl, double dist2vp)
  201. {
  202. assert(sl);
  203. delete_from(sl->rbt, dist2vp);
  204. return;
  205. }
  206. /* ------------------------------------------------------------ */
  207. /*insert the element into the status structure */
  208. void insert_into_status_struct(StatusNode sn, StatusList * sl)
  209. {
  210. assert(sl);
  211. TreeValue tv;
  212. tv.key = sn.dist2vp;
  213. tv.gradient[0] = sn.gradient[0];
  214. tv.gradient[1] = sn.gradient[1];
  215. tv.gradient[2] = sn.gradient[2];
  216. tv.angle[0] = sn.angle[0];
  217. tv.angle[1] = sn.angle[1];
  218. tv.angle[2] = sn.angle[2];
  219. tv.maxGradient = SMALLEST_GRADIENT;
  220. insert_into(sl->rbt, tv);
  221. return;
  222. }
  223. /* ------------------------------------------------------------ */
  224. /*find the node with max Gradient within the distance (from viewpoint)
  225. //given */
  226. double find_max_gradient_in_status_struct(StatusList * sl, double dist, double angle, double gradient)
  227. {
  228. assert(sl);
  229. /*note: if there is nothing in the status struccture, it means this
  230. cell is VISIBLE */
  231. if (is_empty(sl))
  232. return SMALLEST_GRADIENT;
  233. /*it is also possible that the status structure is not empty, but
  234. there are no events with key < dist ---in this case it returns
  235. SMALLEST_GRADIENT; */
  236. return find_max_gradient_within_key(sl->rbt, dist, angle, gradient);
  237. }
  238. /*returns true if it is empty */
  239. int is_empty(StatusList * sl)
  240. {
  241. assert(sl);
  242. return (is_empty(sl->rbt) ||
  243. sl->rbt->root->value.maxGradient == SMALLEST_GRADIENT);
  244. }