ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/srcsupp.c
Revision: 2.20
Committed: Sun Jun 22 18:05:28 2014 UTC (9 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad4R2P2, rad4R2, rad4R2P1
Changes since 2.19: +95 -73 lines
Log Message:
ANSIfication

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: srcsupp.c,v 2.19 2014/06/17 18:57:41 greg Exp $";
3 #endif
4 /*
5 * Support routines for source objects and materials
6 *
7 * External symbols declared in source.h
8 */
9
10 #include "copyright.h"
11
12 #include "ray.h"
13
14 #include "otypes.h"
15
16 #include "source.h"
17
18 #include "cone.h"
19
20 #include "face.h"
21
22 #define SRCINC 32 /* realloc increment for array */
23
24 SRCREC *source = NULL; /* our list of sources */
25 int nsources = 0; /* the number of sources */
26
27 SRCFUNC sfun[NUMOTYPE]; /* source dispatch table */
28
29
30 void
31 initstypes(void) /* initialize source dispatch table */
32 {
33 extern VSMATERIAL mirror_vs, direct1_vs, direct2_vs;
34 static SOBJECT fsobj = {fsetsrc, flatpart, fgetplaneq, fgetmaxdisk};
35 static SOBJECT ssobj = {ssetsrc, nopart};
36 static SOBJECT sphsobj = {sphsetsrc, nopart};
37 static SOBJECT cylsobj = {cylsetsrc, cylpart};
38 static SOBJECT rsobj = {rsetsrc, flatpart, rgetplaneq, rgetmaxdisk};
39
40 sfun[MAT_MIRROR].mf = &mirror_vs;
41 sfun[MAT_DIRECT1].mf = &direct1_vs;
42 sfun[MAT_DIRECT2].mf = &direct2_vs;
43 sfun[OBJ_FACE].of = &fsobj;
44 sfun[OBJ_SOURCE].of = &ssobj;
45 sfun[OBJ_SPHERE].of = &sphsobj;
46 sfun[OBJ_CYLINDER].of = &cylsobj;
47 sfun[OBJ_RING].of = &rsobj;
48 }
49
50
51 int
52 newsource(void) /* allocate new source in our array */
53 {
54 if (nsources == 0)
55 source = (SRCREC *)malloc(SRCINC*sizeof(SRCREC));
56 else if (nsources%SRCINC == 0)
57 source = (SRCREC *)realloc((void *)source,
58 (unsigned)(nsources+SRCINC)*sizeof(SRCREC));
59 if (source == NULL)
60 return(-1);
61 source[nsources].sflags = 0;
62 source[nsources].nhits = 1;
63 source[nsources].ntests = 2; /* initial hit probability = 50% */
64 #if SHADCACHE
65 source[nsources].obscache = NULL;
66 #endif
67 return(nsources++);
68 }
69
70
71 void
72 setflatss( /* set sampling for a flat source */
73 SRCREC *src
74 )
75 {
76 double mult;
77 int i;
78
79 src->ss[SV][0] = src->ss[SV][1] = src->ss[SV][2] = 0.0;
80 for (i = 0; i < 3; i++)
81 if (src->snorm[i] < 0.6 && src->snorm[i] > -0.6)
82 break;
83 src->ss[SV][i] = 1.0;
84 fcross(src->ss[SU], src->ss[SV], src->snorm);
85 mult = .5 * sqrt( src->ss2 / DOT(src->ss[SU],src->ss[SU]) );
86 for (i = 0; i < 3; i++)
87 src->ss[SU][i] *= mult;
88 fcross(src->ss[SV], src->snorm, src->ss[SU]);
89 }
90
91
92 void
93 fsetsrc( /* set a face as a source */
94 SRCREC *src,
95 OBJREC *so
96 )
97 {
98 FACE *f;
99 int i, j;
100 double d;
101
102 src->sa.success = 2*AIMREQT-1; /* bitch on second failure */
103 src->so = so;
104 /* get the face */
105 f = getface(so);
106 if (f->area == 0.0)
107 objerror(so, USER, "zero source area");
108 /* find the center */
109 for (j = 0; j < 3; j++) {
110 src->sloc[j] = 0.0;
111 for (i = 0; i < f->nv; i++)
112 src->sloc[j] += VERTEX(f,i)[j];
113 src->sloc[j] /= (double)f->nv;
114 }
115 if (!inface(src->sloc, f))
116 objerror(so, USER, "cannot hit source center");
117 src->sflags |= SFLAT;
118 VCOPY(src->snorm, f->norm);
119 src->ss2 = f->area;
120 /* find maximum radius */
121 src->srad = 0.;
122 for (i = 0; i < f->nv; i++) {
123 d = dist2(VERTEX(f,i), src->sloc);
124 if (d > src->srad)
125 src->srad = d;
126 }
127 src->srad = sqrt(src->srad);
128 /* compute size vectors */
129 if (f->nv == 4) /* parallelogram case */
130 for (j = 0; j < 3; j++) {
131 src->ss[SU][j] = .5*(VERTEX(f,1)[j]-VERTEX(f,0)[j]);
132 src->ss[SV][j] = .5*(VERTEX(f,3)[j]-VERTEX(f,0)[j]);
133 }
134 else
135 setflatss(src);
136 }
137
138
139 void
140 ssetsrc( /* set a source as a source */
141 SRCREC *src,
142 OBJREC *so
143 )
144 {
145 double theta;
146
147 src->sa.success = 2*AIMREQT-1; /* bitch on second failure */
148 src->so = so;
149 if (so->oargs.nfargs != 4)
150 objerror(so, USER, "bad arguments");
151 src->sflags |= (SDISTANT|SCIR);
152 VCOPY(src->sloc, so->oargs.farg);
153 if (normalize(src->sloc) == 0.0)
154 objerror(so, USER, "zero direction");
155 theta = PI/180.0/2.0 * so->oargs.farg[3];
156 if (theta <= FTINY)
157 objerror(so, USER, "zero size");
158 src->ss2 = 2.0*PI * (1.0 - cos(theta));
159 /* the following is approximate */
160 src->srad = sqrt(src->ss2/PI);
161 VCOPY(src->snorm, src->sloc);
162 setflatss(src); /* hey, whatever works */
163 src->ss[SW][0] = src->ss[SW][1] = src->ss[SW][2] = 0.0;
164 }
165
166
167 void
168 sphsetsrc( /* set a sphere as a source */
169 SRCREC *src,
170 OBJREC *so
171 )
172 {
173 int i;
174
175 src->sa.success = 2*AIMREQT-1; /* bitch on second failure */
176 src->so = so;
177 if (so->oargs.nfargs != 4)
178 objerror(so, USER, "bad # arguments");
179 if (so->oargs.farg[3] <= FTINY)
180 objerror(so, USER, "illegal source radius");
181 src->sflags |= SCIR;
182 VCOPY(src->sloc, so->oargs.farg);
183 src->srad = so->oargs.farg[3];
184 src->ss2 = PI * src->srad * src->srad;
185 for (i = 0; i < 3; i++)
186 src->ss[SU][i] = src->ss[SV][i] = src->ss[SW][i] = 0.0;
187 for (i = 0; i < 3; i++)
188 src->ss[i][i] = 0.7236 * so->oargs.farg[3];
189 }
190
191
192 void
193 rsetsrc( /* set a ring (disk) as a source */
194 SRCREC *src,
195 OBJREC *so
196 )
197 {
198 CONE *co;
199
200 src->sa.success = 2*AIMREQT-1; /* bitch on second failure */
201 src->so = so;
202 /* get the ring */
203 co = getcone(so, 0);
204 if (CO_R1(co) <= FTINY)
205 objerror(so, USER, "illegal source radius");
206 VCOPY(src->sloc, CO_P0(co));
207 if (CO_R0(co) > 0.0)
208 objerror(so, USER, "cannot hit source center");
209 src->sflags |= (SFLAT|SCIR);
210 VCOPY(src->snorm, co->ad);
211 src->srad = CO_R1(co);
212 src->ss2 = PI * src->srad * src->srad;
213 setflatss(src);
214 }
215
216
217 void
218 cylsetsrc( /* set a cylinder as a source */
219 SRCREC *src,
220 OBJREC *so
221 )
222 {
223 CONE *co;
224 int i;
225
226 src->sa.success = 4*AIMREQT-1; /* bitch on fourth failure */
227 src->so = so;
228 /* get the cylinder */
229 co = getcone(so, 0);
230 if (CO_R0(co) <= FTINY)
231 objerror(so, USER, "illegal source radius");
232 if (CO_R0(co) > .2*co->al) /* heuristic constraint */
233 objerror(so, WARNING, "source aspect too small");
234 src->sflags |= SCYL;
235 for (i = 0; i < 3; i++)
236 src->sloc[i] = .5 * (CO_P1(co)[i] + CO_P0(co)[i]);
237 src->srad = .5*co->al;
238 src->ss2 = 2.*CO_R0(co)*co->al;
239 /* set sampling vectors */
240 for (i = 0; i < 3; i++)
241 src->ss[SU][i] = .5 * co->al * co->ad[i];
242 src->ss[SV][0] = src->ss[SV][1] = src->ss[SV][2] = 0.0;
243 for (i = 0; i < 3; i++)
244 if (co->ad[i] < 0.6 && co->ad[i] > -0.6)
245 break;
246 src->ss[SV][i] = 1.0;
247 fcross(src->ss[SW], src->ss[SV], co->ad);
248 normalize(src->ss[SW]);
249 for (i = 0; i < 3; i++)
250 src->ss[SW][i] *= .8559 * CO_R0(co);
251 fcross(src->ss[SV], src->ss[SW], co->ad);
252 }
253
254
255 SPOT *
256 makespot( /* make a spotlight */
257 OBJREC *m
258 )
259 {
260 SPOT *ns;
261
262 if ((ns = (SPOT *)m->os) != NULL)
263 return(ns);
264 if ((ns = (SPOT *)malloc(sizeof(SPOT))) == NULL)
265 return(NULL);
266 if (m->oargs.farg[3] <= FTINY)
267 objerror(m, USER, "zero angle");
268 ns->siz = 2.0*PI * (1.0 - cos(PI/180.0/2.0 * m->oargs.farg[3]));
269 VCOPY(ns->aim, m->oargs.farg+4);
270 if ((ns->flen = normalize(ns->aim)) == 0.0)
271 objerror(m, USER, "zero focus vector");
272 m->os = (char *)ns;
273 return(ns);
274 }
275
276
277 int
278 spotout( /* check if we're outside spot region */
279 RAY *r,
280 SPOT *s
281 )
282 {
283 double d;
284 FVECT vd;
285
286 if (s == NULL)
287 return(0);
288 if (s->flen < -FTINY) { /* distant source */
289 vd[0] = s->aim[0] - r->rorg[0];
290 vd[1] = s->aim[1] - r->rorg[1];
291 vd[2] = s->aim[2] - r->rorg[2];
292 d = DOT(r->rdir,vd);
293 /* wrong side?
294 if (d <= FTINY)
295 return(1); */
296 d = DOT(vd,vd) - d*d;
297 if (PI*d > s->siz)
298 return(1); /* out */
299 return(0); /* OK */
300 }
301 /* local source */
302 if (s->siz < 2.0*PI * (1.0 + DOT(s->aim,r->rdir)))
303 return(1); /* out */
304 return(0); /* OK */
305 }
306
307
308 double
309 fgetmaxdisk( /* get center and squared radius of face */
310 FVECT ocent,
311 OBJREC *op
312 )
313 {
314 double maxrad2;
315 double d;
316 int i, j;
317 FACE *f;
318
319 f = getface(op);
320 if (f->area == 0.)
321 return(0.);
322 for (i = 0; i < 3; i++) {
323 ocent[i] = 0.;
324 for (j = 0; j < f->nv; j++)
325 ocent[i] += VERTEX(f,j)[i];
326 ocent[i] /= (double)f->nv;
327 }
328 d = DOT(ocent,f->norm);
329 for (i = 0; i < 3; i++)
330 ocent[i] += (f->offset - d)*f->norm[i];
331 maxrad2 = 0.;
332 for (j = 0; j < f->nv; j++) {
333 d = dist2(VERTEX(f,j), ocent);
334 if (d > maxrad2)
335 maxrad2 = d;
336 }
337 return(maxrad2);
338 }
339
340
341 double
342 rgetmaxdisk( /* get center and squared radius of ring */
343 FVECT ocent,
344 OBJREC *op
345 )
346 {
347 CONE *co;
348
349 co = getcone(op, 0);
350 VCOPY(ocent, CO_P0(co));
351 return(CO_R1(co)*CO_R1(co));
352 }
353
354
355 double
356 fgetplaneq( /* get plane equation for face */
357 FVECT nvec,
358 OBJREC *op
359 )
360 {
361 FACE *fo;
362
363 fo = getface(op);
364 VCOPY(nvec, fo->norm);
365 return(fo->offset);
366 }
367
368
369 double
370 rgetplaneq( /* get plane equation for ring */
371 FVECT nvec,
372 OBJREC *op
373 )
374 {
375 CONE *co;
376
377 co = getcone(op, 0);
378 VCOPY(nvec, co->ad);
379 return(DOT(nvec, CO_P0(co)));
380 }
381
382
383 int
384 commonspot( /* set sp1 to intersection of sp1 and sp2 */
385 SPOT *sp1,
386 SPOT *sp2,
387 FVECT org
388 )
389 {
390 FVECT cent;
391 double rad2, cos1, cos2;
392
393 cos1 = 1. - sp1->siz/(2.*PI);
394 cos2 = 1. - sp2->siz/(2.*PI);
395 if (sp2->siz >= 2.*PI-FTINY) /* BIG, just check overlap */
396 return(DOT(sp1->aim,sp2->aim) >= cos1*cos2 -
397 sqrt((1.-cos1*cos1)*(1.-cos2*cos2)));
398 /* compute and check disks */
399 rad2 = intercircle(cent, sp1->aim, sp2->aim,
400 1./(cos1*cos1) - 1., 1./(cos2*cos2) - 1.);
401 if (rad2 <= FTINY || normalize(cent) == 0.)
402 return(0);
403 VCOPY(sp1->aim, cent);
404 sp1->siz = 2.*PI*(1. - 1./sqrt(1.+rad2));
405 return(1);
406 }
407
408
409 int
410 commonbeam( /* set sp1 to intersection of sp1 and sp2 */
411 SPOT *sp1,
412 SPOT *sp2,
413 FVECT dir
414 )
415 {
416 FVECT cent, c1, c2;
417 double rad2, d;
418 /* move centers to common plane */
419 d = DOT(sp1->aim, dir);
420 VSUM(c1, sp1->aim, dir, -d);
421 d = DOT(sp2->aim, dir);
422 VSUM(c2, sp2->aim, dir, -d);
423 /* compute overlap */
424 rad2 = intercircle(cent, c1, c2, sp1->siz/PI, sp2->siz/PI);
425 if (rad2 <= FTINY)
426 return(0);
427 VCOPY(sp1->aim, cent);
428 sp1->siz = PI*rad2;
429 return(1);
430 }
431
432
433 int
434 checkspot( /* check spotlight for behind source */
435 SPOT *sp, /* spotlight */
436 FVECT nrm /* source surface normal */
437 )
438 {
439 double d, d1;
440
441 d = DOT(sp->aim, nrm);
442 if (d > FTINY) /* center in front? */
443 return(1);
444 /* else check horizon */
445 d1 = 1. - sp->siz/(2.*PI);
446 return(1.-FTINY-d*d < d1*d1);
447 }
448
449
450 double
451 spotdisk( /* intersect spot with object op */
452 FVECT oc,
453 OBJREC *op,
454 SPOT *sp,
455 FVECT pos
456 )
457 {
458 FVECT onorm;
459 double offs, d, dist;
460
461 offs = getplaneq(onorm, op);
462 d = -DOT(onorm, sp->aim);
463 if (d >= -FTINY && d <= FTINY)
464 return(0.);
465 dist = (DOT(pos, onorm) - offs)/d;
466 if (dist < 0.)
467 return(0.);
468 VSUM(oc, pos, sp->aim, dist);
469 return(sp->siz*dist*dist/PI/(d*d));
470 }
471
472
473 double
474 beamdisk( /* intersect beam with object op */
475 FVECT oc,
476 OBJREC *op,
477 SPOT *sp,
478 FVECT dir
479 )
480 {
481 FVECT onorm;
482 double offs, d, dist;
483
484 offs = getplaneq(onorm, op);
485 d = -DOT(onorm, dir);
486 if (d >= -FTINY && d <= FTINY)
487 return(0.);
488 dist = (DOT(sp->aim, onorm) - offs)/d;
489 VSUM(oc, sp->aim, dir, dist);
490 return(sp->siz/PI/(d*d));
491 }
492
493
494 double
495 intercircle( /* intersect two circles */
496 FVECT cc, /* midpoint (return value) */
497 FVECT c1, /* circle centers */
498 FVECT c2,
499 double r1s, /* radii squared */
500 double r2s
501 )
502 {
503 double a2, d2, l;
504 FVECT disp;
505
506 VSUB(disp, c2, c1);
507 d2 = DOT(disp,disp);
508 /* circle within overlap? */
509 if (r1s < r2s) {
510 if (r2s >= r1s + d2) {
511 VCOPY(cc, c1);
512 return(r1s);
513 }
514 } else {
515 if (r1s >= r2s + d2) {
516 VCOPY(cc, c2);
517 return(r2s);
518 }
519 }
520 a2 = .25*(2.*(r1s+r2s) - d2 - (r2s-r1s)*(r2s-r1s)/d2);
521 /* no overlap? */
522 if (a2 <= 0.)
523 return(0.);
524 /* overlap, compute center */
525 l = sqrt((r1s - a2)/d2);
526 VSUM(cc, c1, disp, l);
527 return(a2);
528 }