ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/warp3d.c
Revision: 3.12
Committed: Thu Feb 22 17:45:27 2024 UTC (2 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 3.11: +25 -25 lines
Log Message:
style: got rid of register keywords

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: warp3d.c,v 3.11 2019/12/28 18:05:14 greg Exp $";
3 #endif
4 /*
5 * 3D warping routines.
6 */
7
8 #include <stdlib.h>
9 #include <math.h>
10
11 #include "rterror.h"
12 #include "rtio.h"
13 #include "fvect.h"
14 #include "warp3d.h"
15
16 #define MIND 1e-5 /* minimum distance between input points */
17
18 typedef struct {
19 GNDX n; /* index must be first */
20 W3VEC v;
21 } KEYDP; /* key/data allocation pair */
22
23 #define fgetvec(p,v) (fgetval(p,'f',v) > 0 && fgetval(p,'f',v+1) > 0 \
24 && fgetval(p,'f',v+2) > 0)
25
26 #define AHUNK 24 /* number of points to allocate at a time */
27
28
29 double wpdist2(W3VEC p1, W3VEC p2);
30 static int gridpoint(GNDX ndx, W3VEC rem, W3VEC ipt, struct grid3d *gp);
31 static int get3dgpt(W3VEC ov, GNDX ndx, WARP3D *wp);
32 static int get3dgin(W3VEC ov, GNDX ndx, W3VEC rem, WARP3D *wp);
33 static void l3interp(W3VEC vo, W3VEC *cl, W3VEC dv, int n);
34 static int warp3dex(W3VEC ov, W3VEC pi, WARP3D *wp);
35 static lut_hashf_t gridhash;
36 static int new3dgrid(WARP3D *wp);
37 static void done3dgrid(struct grid3d *gp);
38
39
40 double
41 wpdist2( /* compute square of distance between points */
42 W3VEC p1,
43 W3VEC p2
44 )
45 {
46 double d, d2;
47
48 d = p1[0] - p2[0]; d2 = d*d;
49 d = p1[1] - p2[1]; d2 += d*d;
50 d = p1[2] - p2[2]; d2 += d*d;
51 return(d2);
52 }
53
54
55 int
56 warp3d( /* warp 3D point according to the given map */
57 W3VEC po,
58 W3VEC pi,
59 WARP3D *wp
60 )
61 {
62 int rval = W3OK;
63 GNDX gi;
64 W3VEC gd, ov;
65
66 if (wp->grid.gn[0] == 0 && (rval = new3dgrid(wp)) != W3OK)
67 return(rval);
68 rval |= gridpoint(gi, gd, pi, &wp->grid);
69 if (wp->grid.flags & W3EXACT)
70 rval |= warp3dex(ov, pi, wp);
71 else if (wp->grid.flags & W3FAST)
72 rval |= get3dgpt(ov, gi, wp);
73 else
74 rval |= get3dgin(ov, gi, gd, wp);
75 po[0] = pi[0] + ov[0];
76 po[1] = pi[1] + ov[1];
77 po[2] = pi[2] + ov[2];
78 return(rval);
79 }
80
81
82 static int
83 gridpoint( /* compute grid position for ipt */
84 GNDX ndx,
85 W3VEC rem,
86 W3VEC ipt,
87 struct grid3d *gp
88 )
89 {
90 int rval = W3OK;
91 int i;
92
93 for (i = 0; i < 3; i++) {
94 rem[i] = (ipt[i] - gp->gmin[i])/gp->gstep[i];
95 if (rem[i] < 0.) {
96 ndx[i] = 0;
97 rval = W3GAMUT;
98 } else if ((int)rem[i] >= gp->gn[i]) {
99 ndx[i] = gp->gn[i] - 1;
100 rval = W3GAMUT;
101 } else
102 ndx[i] = (int)rem[i];
103 rem[i] -= (double)ndx[i];
104 }
105 return(rval);
106 }
107
108
109 static int
110 get3dgpt( /* get value for voxel */
111 W3VEC ov,
112 GNDX ndx,
113 WARP3D *wp
114 )
115 {
116 W3VEC gpt;
117 LUENT *le;
118 KEYDP *kd;
119 int rval = W3OK;
120 int i;
121
122 le = lu_find(&wp->grid.gtab, ndx);
123 if (le == NULL)
124 return(W3ERROR);
125 if (le->data == NULL) {
126 if (le->key != NULL)
127 kd = (KEYDP *)le->key;
128 else if ((kd = (KEYDP *)malloc(sizeof(KEYDP))) == NULL)
129 return(W3ERROR);
130 for (i = 0; i < 3; i++) {
131 kd->n[i] = ndx[i];
132 gpt[i] = wp->grid.gmin[i] + ndx[i]*wp->grid.gstep[i];
133 if (wp->grid.flags & W3FAST) /* on centers */
134 gpt[i] += .5*wp->grid.gstep[i];
135 }
136 rval = warp3dex(kd->v, gpt, wp);
137 le->key = (char *)kd->n;
138 le->data = (char *)kd->v;
139 }
140 W3VCPY(ov, (float *)le->data);
141 return(rval);
142 }
143
144
145 static int
146 get3dgin( /* interpolate from warp grid */
147 W3VEC ov,
148 GNDX ndx,
149 W3VEC rem,
150 WARP3D *wp
151 )
152 {
153 W3VEC cv[8];
154 GNDX gi;
155 int rval = W3OK;
156 int i;
157 /* get corner values */
158 for (i = 0; i < 8; i++) {
159 gi[0] = ndx[0] + (i & 1);
160 gi[1] = ndx[1] + (i>>1 & 1);
161 gi[2] = ndx[2] + (i>>2);
162 rval |= get3dgpt(cv[i], gi, wp);
163 }
164 if (rval & W3ERROR)
165 return(rval);
166 l3interp(ov, cv, rem, 3); /* perform trilinear interpolation */
167 return(rval);
168 }
169
170
171 static void
172 l3interp( /* trilinear interpolation (recursive) */
173 W3VEC vo,
174 W3VEC *cl,
175 W3VEC dv,
176 int n
177 )
178 {
179 W3VEC v0, v1;
180 int i;
181
182 if (--n) {
183 l3interp(v0, cl, dv, n);
184 l3interp(v1, cl+(1<<n), dv, n);
185 } else {
186 W3VCPY(v0, cl[0]);
187 W3VCPY(v1, cl[1]);
188 }
189 for (i = 0; i < 3; i++)
190 vo[i] = (1.-dv[n])*v0[i] + dv[n]*v1[i];
191 }
192
193
194 static int
195 warp3dex( /* compute warp using 1/r^2 weighted avg. */
196 W3VEC ov,
197 W3VEC pi,
198 WARP3D *wp
199 )
200 {
201 double d2, w, wsum;
202 W3VEC vt;
203 int i;
204
205 vt[0] = vt[1] = vt[2] = 0.;
206 wsum = 0.;
207 for (i = wp->npts; i--; ) {
208 d2 = wpdist2(pi, wp->ip[i]);
209 if (d2 <= MIND*MIND) w = 1./(MIND*MIND);
210 else w = 1./d2;
211 vt[0] += w*wp->ov[i][0];
212 vt[1] += w*wp->ov[i][1];
213 vt[2] += w*wp->ov[i][2];
214 wsum += w;
215 }
216 if (wsum > 0.) {
217 ov[0] = vt[0]/wsum;
218 ov[1] = vt[1]/wsum;
219 ov[2] = vt[2]/wsum;
220 }
221 return(W3OK);
222 }
223
224
225 WARP3D *
226 new3dw( /* allocate and initialize WARP3D struct */
227 int flgs
228 )
229 {
230 WARP3D *wp;
231
232 if ((flgs & (W3EXACT|W3FAST)) == (W3EXACT|W3FAST)) {
233 eputs("new3dw: only one of W3EXACT or W3FAST\n");
234 return(NULL);
235 }
236 if ((wp = (WARP3D *)malloc(sizeof(WARP3D))) == NULL) {
237 eputs("new3dw: no memory\n");
238 return(NULL);
239 }
240 wp->ip = wp->ov = NULL;
241 wp->npts = 0;
242 wp->grid.flags = flgs;
243 wp->grid.gn[0] = wp->grid.gn[1] = wp->grid.gn[2] = 0;
244 return(wp);
245 }
246
247
248 WARP3D *
249 load3dw( /* load 3D warp from file */
250 char *fn,
251 WARP3D *wp
252 )
253 {
254 FILE *fp;
255 W3VEC inp, outp;
256
257 if ((fp = fopen(fn, "r")) == NULL) {
258 eputs(fn);
259 eputs(": cannot open\n");
260 return(NULL);
261 }
262 if (wp == NULL && (wp = new3dw(0)) == NULL)
263 goto memerr;
264 while (fgetvec(fp, inp) && fgetvec(fp, outp))
265 if (!add3dpt(wp, inp, outp))
266 goto memerr;
267 if (!feof(fp)) {
268 wputs(fn);
269 wputs(": non-number in 3D warp file\n");
270 }
271 goto cleanup;
272 memerr:
273 eputs("load3dw: out of memory\n");
274 cleanup:
275 fclose(fp);
276 return(wp);
277 }
278
279
280 extern int
281 set3dwfl( /* reset warp flags */
282 WARP3D *wp,
283 int flgs
284 )
285 {
286 if (flgs == wp->grid.flags)
287 return(0);
288 if ((flgs & (W3EXACT|W3FAST)) == (W3EXACT|W3FAST)) {
289 eputs("set3dwfl: only one of W3EXACT or W3FAST\n");
290 return(-1);
291 }
292 wp->grid.flags = flgs;
293 done3dgrid(&wp->grid); /* old grid is invalid */
294 return(0);
295 }
296
297
298 int
299 add3dpt( /* add 3D point pair to warp structure */
300 WARP3D *wp,
301 W3VEC pti,
302 W3VEC pto
303 )
304 {
305 double d2;
306 W3VEC *na;
307 int i;
308
309 if (wp->npts == 0) { /* initialize */
310 wp->ip = (W3VEC *)malloc(AHUNK*sizeof(W3VEC));
311 if (wp->ip == NULL) return(0);
312 wp->ov = (W3VEC *)malloc(AHUNK*sizeof(W3VEC));
313 if (wp->ov == NULL) return(0);
314 wp->d2min = 1e10;
315 wp->d2max = 0.;
316 W3VCPY(wp->llim, pti);
317 W3VCPY(wp->ulim, pti);
318 } else {
319 if (wp->npts % AHUNK == 0) { /* allocate another hunk */
320 na = (W3VEC *)realloc((void *)wp->ip,
321 (wp->npts+AHUNK)*sizeof(W3VEC));
322 if (na == NULL) return(0);
323 wp->ip = na;
324 na = (W3VEC *)realloc((void *)wp->ov,
325 (wp->npts+AHUNK)*sizeof(W3VEC));
326 if (na == NULL) return(0);
327 wp->ov = na;
328 }
329 for (i = 0; i < 3; i++) /* check boundaries */
330 if (pti[i] < wp->llim[i])
331 wp->llim[i] = pti[i];
332 else if (pti[i] > wp->ulim[i])
333 wp->ulim[i] = pti[i];
334 for (i = wp->npts; i--; ) { /* check distances */
335 d2 = wpdist2(pti, wp->ip[i]);
336 if (d2 < MIND*MIND) /* value is too close */
337 return(wp->npts);
338 if (d2 < wp->d2min)
339 wp->d2min = d2;
340 if (d2 > wp->d2max)
341 wp->d2max = d2;
342 }
343 }
344 W3VCPY(wp->ip[wp->npts], pti); /* add new point */
345 wp->ov[wp->npts][0] = pto[0] - pti[0];
346 wp->ov[wp->npts][1] = pto[1] - pti[1];
347 wp->ov[wp->npts][2] = pto[2] - pti[2];
348 done3dgrid(&wp->grid); /* old grid is invalid */
349 return(++wp->npts);
350 }
351
352
353 extern void
354 free3dw( /* free WARP3D data */
355 WARP3D *wp
356 )
357 {
358 done3dgrid(&wp->grid);
359 free(wp->ip);
360 free(wp->ov);
361 free(wp);
362 }
363
364
365 static unsigned long
366 gridhash( /* hash a grid point index */
367 const char *gp
368 )
369 {
370 return(((unsigned long)((const unsigned char*)gp)[0]<<GNBITS | ((const unsigned char*)gp)[1])<<GNBITS | ((const unsigned char*)gp)[2]);
371 }
372
373
374 static int
375 new3dgrid( /* initialize interpolating grid for warp */
376 WARP3D *wp
377 )
378 {
379 W3VEC gmax;
380 double gridstep, d;
381 int n;
382 int i;
383 /* free old grid (if any) */
384 done3dgrid(&wp->grid);
385 /* check parameters */
386 if (wp->npts < 2)
387 return(W3BADMAP); /* undefined for less than 2 points */
388 if (wp->d2max < MIND)
389 return(W3BADMAP); /* not enough disparity */
390 /* compute gamut */
391 W3VCPY(wp->grid.gmin, wp->llim);
392 W3VCPY(gmax, wp->ulim);
393 gridstep = sqrt(wp->d2min);
394 for (i = 0; i < 3; i++) {
395 wp->grid.gmin[i] -= .501*gridstep;
396 gmax[i] += .501*gridstep;
397 }
398 if (wp->grid.flags & W3EXACT) {
399 wp->grid.gn[0] = wp->grid.gn[1] = wp->grid.gn[2] = 1;
400 wp->grid.gstep[0] = gmax[0] - wp->grid.gmin[0];
401 wp->grid.gstep[1] = gmax[1] - wp->grid.gmin[1];
402 wp->grid.gstep[2] = gmax[2] - wp->grid.gmin[2];
403 return(W3OK); /* no interpolation, so no grid */
404 }
405 /* create grid */
406 for (i = 0; i < 3; i++) {
407 d = gmax[i] - wp->grid.gmin[i];
408 n = d/gridstep + .5;
409 if (n >= MAXGN-1)
410 n = MAXGN-2;
411 wp->grid.gstep[i] = d / n;
412 wp->grid.gn[i] = n;
413 }
414 /* initialize lookup table */
415 wp->grid.gtab.hashf = gridhash;
416 wp->grid.gtab.keycmp = NULL;
417 wp->grid.gtab.freek = free;
418 wp->grid.gtab.freed = NULL;
419 return(lu_init(&wp->grid.gtab, 1024) ? W3OK : W3ERROR);
420 }
421
422
423 static void
424 done3dgrid( /* free interpolating grid for warp */
425 struct grid3d *gp
426 )
427 {
428 if (gp->gn[0] == 0)
429 return;
430 lu_done(&gp->gtab);
431 gp->gn[0] = gp->gn[1] = gp->gn[2] = 0;
432 }