gs_norms.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /*!
  2. \file lib/ogsf/gs_norms.c
  3. \brief OGSF library - calculation normals (lower level functions)
  4. GRASS OpenGL gsurf OGSF Library
  5. (C) 1999-2008 by the GRASS Development Team
  6. This program is free software under the
  7. GNU General Public License (>=v2).
  8. Read the file COPYING that comes with GRASS
  9. for details.
  10. \author Bill Brown USACERL
  11. \author Doxygenized by Martin Landa <landa.martin gmail.com> (May 2008)
  12. */
  13. #include <math.h>
  14. #include <grass/gis.h>
  15. #include <grass/ogsf.h>
  16. #include "gsget.h"
  17. #include "rowcol.h"
  18. #define NTOP 0x00001000
  19. #define NBOT 0x00000100
  20. #define NLFT 0x00000010
  21. #define NRGT 0x00000001
  22. #define NALL 0x00001111
  23. #define NTL 0x00001010
  24. #define NTR 0x00001001
  25. #define NBL 0x00000110
  26. #define NBR 0x00000101
  27. /*!
  28. \brief This macro is only used in the function calc_norm()
  29. */
  30. #define SET_NORM(i) \
  31. dz1 = z1 - z2; \
  32. dz2 = z3 - z4; \
  33. temp[0] = (float) -dz1 * y_res_z2; \
  34. temp[1] = (float) dz2 * x_res_z2; \
  35. temp[2] = c_z2; \
  36. normalizer = sqrt(temp[0] * temp[0] + temp[1] * temp[1] + c_z2_sq); \
  37. if (!normalizer) normalizer= 1.0; \
  38. temp[X] /= normalizer; \
  39. temp[Y] /= normalizer; \
  40. temp[Z] /= normalizer; \
  41. PNORM(i,temp);
  42. static long slice;
  43. static float x_res_z2, y_res_z2;
  44. static float c_z2, c_z2_sq;
  45. static typbuff *elbuf;
  46. static unsigned long *norm;
  47. /*
  48. #define USE_GL_NORMALIZE
  49. */
  50. /*!
  51. \brief Init variables
  52. for optimization
  53. \param gs surface (geosurf)
  54. */
  55. void init_vars(geosurf * gs)
  56. {
  57. /* optimized - these are static - global to this file */
  58. norm = gs->norms;
  59. elbuf = gs_get_att_typbuff(gs, ATT_TOPO, 0);
  60. #ifdef USE_GL_NORMALIZE
  61. c_z2 =
  62. 2.0 * gs->xres * gs->yres * gs->x_mod * gs->y_mod / GS_global_exag();
  63. c_z2_sq = c_z2 * c_z2;
  64. x_res_z2 = 2.0 * gs->xres * gs->z_exag * gs->x_mod;
  65. y_res_z2 = 2.0 * gs->yres * gs->z_exag * gs->y_mod;
  66. #else
  67. {
  68. float sx, sy, sz;
  69. GS_get_scale(&sx, &sy, &sz, 1);
  70. c_z2 = 2.0 * gs->xres * gs->yres * gs->x_mod * gs->y_mod;
  71. c_z2_sq = c_z2 * c_z2;
  72. x_res_z2 = 2.0 * gs->xres * gs->z_exag * gs->x_mod;
  73. y_res_z2 = 2.0 * gs->yres * gs->z_exag * gs->y_mod;
  74. }
  75. #endif
  76. slice = gs->y_mod * gs->cols;
  77. return;
  78. }
  79. /*!
  80. \brief Calculate normals
  81. OPTIMIZED for constant dy & dx
  82. The norm array is always the same size, but diff resolutions
  83. force resampled data points to have their normals recalculated,
  84. then only those norms are passed to n3f during drawing.
  85. Norms are converted to a packed unsigned int for storage,
  86. must be converted back at time of use.
  87. \todo fix to correctly calculate norms when mapped to sphere!
  88. Uses the previous and next cells (when available) for normal
  89. calculations to produce smoother normals
  90. \param gs surface (geosurf)
  91. \return 1 on success
  92. \return 0 on failure
  93. */
  94. int gs_calc_normals(geosurf * gs)
  95. {
  96. int row, col;
  97. int xcnt, ycnt;
  98. int xmod, ymod;
  99. if (!gs->norm_needupdate || !gs->norms) {
  100. return (0);
  101. }
  102. gs->norm_needupdate = 0;
  103. gs_update_curmask(gs);
  104. xmod = gs->x_mod;
  105. ymod = gs->y_mod;
  106. xcnt = VCOLS(gs);
  107. ycnt = VROWS(gs);
  108. init_vars(gs);
  109. G_debug(5, "gs_calc_normals(): id=%d", gs->gsurf_id);
  110. /* first row - just use single cell */
  111. /* first col - use bottom & right neighbors */
  112. calc_norm(gs, 0, 0, NBR);
  113. for (col = 1; col < xcnt; col++) {
  114. /* turn off top neighbor for first row */
  115. calc_norm(gs, 0, col * xmod, ~NTOP);
  116. }
  117. /* use bottom & left neighbors for last col */
  118. calc_norm(gs, 0, col * xmod, NBL);
  119. /* now use four neighboring points for rows 1 - (n-1) */
  120. for (row = 1; row < ycnt; row++) {
  121. if (!(row % 100))
  122. G_debug(5, "gs_calc_normals(): row=%d", row);
  123. /* turn off left neighbor for first col */
  124. calc_norm(gs, row * ymod, 0, ~NLFT);
  125. /* use all 4 neighbors until last col */
  126. for (col = 1; col < xcnt; col++) {
  127. calc_norm(gs, row * ymod, col * xmod, NALL);
  128. }
  129. /* turn off right neighbor for last col */
  130. calc_norm(gs, row * ymod, col * xmod, ~NRGT);
  131. }
  132. /* last row */
  133. /* use top & right neighbors for first col */
  134. calc_norm(gs, row * ymod, 0, NTR);
  135. for (col = 1; col < xcnt; col++) {
  136. /* turn off bottom neighbor for last row */
  137. calc_norm(gs, row * ymod, col * xmod, ~NBOT);
  138. }
  139. /* use top & left neighbors for last column */
  140. calc_norm(gs, row * ymod, col * xmod, NTL);
  141. return (1);
  142. }
  143. /*!
  144. \brief Calculate normals
  145. Need either four neighbors or two non-linear neighbors
  146. passed initial state of neighbors known from array position
  147. and data row & col
  148. \param gs surface (geosurf)
  149. \param drow data row
  150. \param dcol data col
  151. \param neighbors neighbors id
  152. \return 0 no normals
  153. \return 1 on success
  154. */
  155. int calc_norm(geosurf * gs, int drow, int dcol, unsigned int neighbors)
  156. {
  157. long noffset;
  158. float temp[3], normalizer, dz1, dz2, z0, z1, z2, z3, z4;
  159. if (gs->curmask) {
  160. /* need to check masked neighbors */
  161. /* NOTE: this should automatically eliminate nullvals */
  162. if (neighbors & NTOP) {
  163. if (BM_get(gs->curmask, dcol, drow - gs->y_mod)) {
  164. /* masked */
  165. neighbors &= ~NTOP;
  166. }
  167. }
  168. if (neighbors & NBOT) {
  169. if (BM_get(gs->curmask, dcol, drow + gs->y_mod)) {
  170. /* masked */
  171. neighbors &= ~NBOT;
  172. }
  173. }
  174. if (neighbors & NLFT) {
  175. if (BM_get(gs->curmask, dcol - gs->x_mod, drow)) {
  176. /* masked */
  177. neighbors &= ~NLFT;
  178. }
  179. }
  180. if (neighbors & NRGT) {
  181. if (BM_get(gs->curmask, dcol + gs->x_mod, drow)) {
  182. /* masked */
  183. neighbors &= ~NRGT;
  184. }
  185. }
  186. }
  187. if (!neighbors) {
  188. /* none */
  189. return (0);
  190. }
  191. noffset = DRC2OFF(gs, drow, dcol);
  192. if (!GET_MAPATT(elbuf, noffset, z0)) {
  193. return (0);
  194. }
  195. z1 = z2 = z3 = z4 = z0;
  196. /* we know these aren't null now, maybe use faster GET_MAPATT? */
  197. if (neighbors & NRGT) {
  198. GET_MAPATT(elbuf, noffset + gs->x_mod, z1);
  199. if (!(neighbors & NLFT)) {
  200. z2 = z0 + (z0 - z1);
  201. }
  202. }
  203. if (neighbors & NLFT) {
  204. GET_MAPATT(elbuf, noffset - gs->x_mod, z2);
  205. if (!(neighbors & NRGT)) {
  206. z1 = z0 + (z0 - z2);
  207. }
  208. }
  209. if (neighbors & NTOP) {
  210. GET_MAPATT(elbuf, noffset - slice, z4);
  211. if (!(neighbors & NBOT)) {
  212. z3 = z0 + (z0 - z4);
  213. }
  214. }
  215. if (neighbors & NBOT) {
  216. GET_MAPATT(elbuf, noffset + slice, z3);
  217. if (!(neighbors & NTOP)) {
  218. z4 = z0 + (z0 - z3);
  219. }
  220. }
  221. SET_NORM(norm[noffset]);
  222. return (1);
  223. }