ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/warp3d.c
Revision: 3.5
Committed: Sat Feb 22 02:07:28 2003 UTC (21 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R5
Changes since 3.4: +5 -12 lines
Log Message:
Changes and check-in for 3.5 release
Includes new source files and modifications not recorded for many years
See ray/doc/notes/ReleaseNotes for notes between 3.1 and 3.5 release

File Contents

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