GRASS GIS 7 Programmer's Manual  7.7.svn(2018)-r73380
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) normalizer= 1.0; \
50  temp[X] /= normalizer; \
51  temp[Y] /= normalizer; \
52  temp[Z] /= normalizer; \
53  PNORM(i,temp);
54
55 static long slice;
56 static float x_res_z2, y_res_z2;
57 static float c_z2, c_z2_sq;
58 static typbuff *elbuf;
59 static unsigned long *norm;
60
61 /*
62  #define USE_GL_NORMALIZE
63  */
64
65 /*!
66  \brief Init variables
67
68  for optimization
69
70  \param gs surface (geosurf)
71  */
72 void init_vars(geosurf * gs)
73 {
74  /* optimized - these are static - global to this file */
75  norm = gs->norms;
76  elbuf = gs_get_att_typbuff(gs, ATT_TOPO, 0);
77
78 #ifdef USE_GL_NORMALIZE
79  c_z2 =
80  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;
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
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)) {
217  neighbors &= ~NTOP;
218  }
219  }
220
221  if (neighbors & NBOT) {
222  if (BM_get(gs->curmask, dcol, drow + gs->y_mod)) {
224  neighbors &= ~NBOT;
225  }
226  }
227
228  if (neighbors & NLFT) {
229  if (BM_get(gs->curmask, dcol - gs->x_mod, drow)) {
231  neighbors &= ~NLFT;
232  }
233  }
234
235  if (neighbors & NRGT) {
236  if (BM_get(gs->curmask, dcol + gs->x_mod, drow)) {
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 *map, int x, int y)
Gets &#39;val&#39; from the bitmap.
Definition: bitmap.c:220
#define NALL
Definition: gs_norms.c:32
#define DRC2OFF(gs, drow, dcol)
Definition: rowcol.h:17
void GS_get_scale(float *sx, float *sy, float *sz, int doexag)
Get axis scale.
Definition: gs2.c:3240
#define SET_NORM(i)
This macro is only used in the function calc_norm()
Definition: gs_norms.c:42
unsigned long * norms
Definition: ogsf.h:274
#define VROWS(gs)
Definition: rowcol.h:13
#define VCOLS(gs)
Definition: rowcol.h:14
#define ATT_TOPO
Definition: ogsf.h:73
int gs_calc_normals(geosurf *gs)
Calculate normals.
Definition: gs_norms.c:124
void init_vars(geosurf *gs)
Init variables.
Definition: gs_norms.c:72
#define NTR
Definition: gs_norms.c:35
float z_exag
Definition: ogsf.h:266
int cols
Definition: ogsf.h:260
double yres
Definition: ogsf.h:265
typbuff * gs_get_att_typbuff(geosurf *gs, int desc, int to_write)
Get attribute data buffer.
Definition: gs.c:681
int x_mod
Definition: ogsf.h:271
#define NTOP
Definition: gs_norms.c:27
int norm_needupdate
Definition: ogsf.h:273
int G_debug(int level, const char *msg,...)
Print debugging message.
Definition: debug.c:65
int y_mod
Definition: ogsf.h:271
#define NBR
Definition: gs_norms.c:37
Definition: ogsf.h:275
#define NRGT
Definition: gs_norms.c:30
#define NBL
Definition: gs_norms.c:36
#define NTL
Definition: gs_norms.c:34
#define NLFT
Definition: gs_norms.c:29
float GS_global_exag(void)
Get global z-exag value.
Definition: gs2.c:1999
int gsurf_id
Definition: ogsf.h:259
Definition: ogsf.h:204
#define NBOT
Definition: gs_norms.c:28
int calc_norm(geosurf *gs, int drow, int dcol, unsigned int neighbors)
Calculate normals.
Definition: gs_norms.c:206
double xres
Definition: ogsf.h:265
Definition: ogsf.h:257