GRASS GIS 8 Programmer's Manual 8.3.2(2024)-exported
Loading...
Searching...
No Matches
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
56static long slice;
57static float x_res_z2, y_res_z2;
58static float c_z2, c_z2_sq;
59static typbuff *elbuf;
60static 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 */
73void 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 */
124int gs_calc_normals(geosurf *gs)
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 */
206int 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 *map, int x, int y)
Gets 'val' from the bitmap.
Definition bitmap.c:217
int G_debug(int level, const char *msg,...)
Print debugging message.
Definition debug.c:66
void GS_get_scale(float *sx, float *sy, float *sz, int doexag)
Get axis scale.
Definition gs2.c:3236
float GS_global_exag(void)
Get global z-exag value.
Definition gs2.c:1997
typbuff * gs_get_att_typbuff(geosurf *gs, int desc, int to_write)
Get attribute data buffer.
Definition gs.c:681
int gs_update_curmask(geosurf *surf)
Update current maps.
Definition gs_bm.c:231
#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 VCOLS(gs)
Definition rowcol.h:14
#define VROWS(gs)
Definition rowcol.h:13
#define DRC2OFF(gs, drow, dcol)
Definition rowcol.h:17