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