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