ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/glarendx.c
Revision: 2.4
Committed: Thu Mar 24 11:06:59 1994 UTC (30 years, 1 month ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.3: +150 -51 lines
Log Message:
Raphael added dgi, brs_gi, and ugr index calculations

File Contents

# Content
1 /* Copyright (c) 1991 Regents of the University of California */
2
3 #ifndef lint
4 static char SCCSid[] = "$SunId$ LBL";
5 #endif
6
7 /*
8 * Compute Glare Index given by program name or -t option:
9 *
10 * dgi - Daylight Glare Index
11 * brs_gi - Building Research Station Glare Index (Petherbridge
12 * & Hopkinson)
13 * ugr - Unified Glare Rating System (Fischer)
14 * guth_dgr - Guth discomfort glare rating
15 * guth_vcp - Guth visual comfort probability
16 * cie_cgi - CIE Glare Index (1983, due to Einhorn)
17 * vert_dir - Direct vertical illuminance
18 * vert_ind - Indirect vertical illuminance (from input)
19 * vert_ill - Total vertical illuminance
20 *
21 * 12 April 1991 Greg Ward EPFL
22 * 19 April 1993 R. Compagnon EPFL (added dgi, brs_gi, ugr)
23 */
24
25 #include "standard.h"
26 #include "view.h"
27
28 extern double erfc();
29
30 double posindex();
31
32 double direct(), guth_dgr(), guth_vcp(), cie_cgi(),
33 indirect(), total(), dgi(), brs_gi(), ugr();
34
35 struct named_func {
36 char *name;
37 double (*func)();
38 char *descrip;
39 } all_funcs[] = {
40 {"dgi", dgi, "Daylight Glare Index"},
41 {"brs_gi", brs_gi, "BRS Glare Index"},
42 {"ugr", ugr, "Unified Glare Rating"},
43 {"guth_vcp", guth_vcp, "Guth Visual Comfort Probability"},
44 {"cie_cgi", cie_cgi, "CIE Glare Index (Einhorn)"},
45 {"guth_dgr", guth_dgr, "Guth Disability Glare Rating"},
46 {"vert_dir", direct, "Direct Vertical Illuminance"},
47 {"vert_ill", total, "Total Vertical Illuminance"},
48 {"vert_ind", indirect, "Indirect Vertical Illuminance"},
49 {NULL}
50 };
51
52 struct glare_src {
53 FVECT dir; /* source direction */
54 double dom; /* solid angle */
55 double lum; /* average luminance */
56 struct glare_src *next;
57 } *all_srcs = NULL;
58
59 struct glare_dir {
60 double ang; /* angle (in radians) */
61 double indirect; /* indirect illuminance */
62 struct glare_dir *next;
63 } *all_dirs = NULL;
64
65 #define newp(type) (type *)malloc(sizeof(type))
66
67 char *progname;
68 int print_header = 1;
69
70 VIEW midview = STDVIEW;
71
72 int wrongformat = 0;
73
74
75 main(argc, argv)
76 int argc;
77 char *argv[];
78 {
79 extern char *rindex();
80 struct named_func *funp;
81 char *progtail;
82 int i;
83 /* get program name */
84 progname = argv[0];
85 progtail = rindex(progname, '/'); /* final component */
86 if (progtail == NULL)
87 progtail = progname;
88 else
89 progtail++;
90 /* get options */
91 for (i = 1; i < argc && argv[i][0] == '-'; i++)
92 switch (argv[i][1]) {
93 case 't':
94 progtail = argv[++i];
95 break;
96 case 'h':
97 print_header = 0;
98 break;
99 default:
100 goto userr;
101 }
102 if (i < argc-1)
103 goto userr;
104 if (i == argc-1) /* open file */
105 if (freopen(argv[i], "r", stdin) == NULL) {
106 perror(argv[i]);
107 exit(1);
108 }
109 /* find and run calculation */
110 for (funp = all_funcs; funp->name != NULL; funp++)
111 if (!strcmp(funp->name, progtail)) {
112 init();
113 read_input();
114 if (print_header) {
115 printargs(i, argv, stdout);
116 putchar('\n');
117 }
118 print_values(funp->func);
119 exit(0); /* we're done */
120 }
121 /* invalid function */
122 userr:
123 fprintf(stderr, "Usage: %s -t type [-h] [input]\n", progname);
124 fprintf(stderr, "\twhere 'type' is one of the following:\n");
125 for (funp = all_funcs; funp->name != NULL; funp++)
126 fprintf(stderr, "\t%12s\t%s\n", funp->name, funp->descrip);
127 exit(1);
128 }
129
130
131 headline(s) /* get line from header */
132 char *s;
133 {
134 char fmt[32];
135
136 if (print_header) /* copy to output */
137 fputs(s, stdout);
138 if (isview(s))
139 sscanview(&midview, s);
140 else if (isformat(s)) {
141 formatval(fmt, s);
142 wrongformat = strcmp(fmt, "ascii");
143 }
144 }
145
146
147 init() /* initialize calculation */
148 {
149 /* read header */
150 getheader(stdin, headline, NULL);
151 if (wrongformat) {
152 fprintf(stderr, "%s: bad input format\n", progname);
153 exit(1);
154 }
155 /* set view */
156 if (setview(&midview) != NULL) {
157 fprintf(stderr, "%s: bad view information in input\n",
158 progname);
159 exit(1);
160 }
161 }
162
163
164 read_input() /* read glare sources from stdin */
165 {
166 #define S_SEARCH 0
167 #define S_SOURCE 1
168 #define S_DIREC 2
169 int state = S_SEARCH;
170 char buf[128];
171 register struct glare_src *gs;
172 register struct glare_dir *gd;
173
174 while (fgets(buf, sizeof(buf), stdin) != NULL)
175 switch (state) {
176 case S_SEARCH:
177 if (!strcmp(buf, "BEGIN glare source\n"))
178 state = S_SOURCE;
179 else if (!strcmp(buf, "BEGIN indirect illuminance\n"))
180 state = S_DIREC;
181 break;
182 case S_SOURCE:
183 if (!strncmp(buf, "END", 3)) {
184 state = S_SEARCH;
185 break;
186 }
187 if ((gs = newp(struct glare_src)) == NULL)
188 goto memerr;
189 if (sscanf(buf, "%lf %lf %lf %lf %lf",
190 &gs->dir[0], &gs->dir[1], &gs->dir[2],
191 &gs->dom, &gs->lum) != 5)
192 goto readerr;
193 normalize(gs->dir);
194 gs->next = all_srcs;
195 all_srcs = gs;
196 break;
197 case S_DIREC:
198 if (!strncmp(buf, "END", 3)) {
199 state = S_SEARCH;
200 break;
201 }
202 if ((gd = newp(struct glare_dir)) == NULL)
203 goto memerr;
204 if (sscanf(buf, "%lf %lf",
205 &gd->ang, &gd->indirect) != 2)
206 goto readerr;
207 gd->ang *= PI/180.0; /* convert to radians */
208 gd->next = all_dirs;
209 all_dirs = gd;
210 break;
211 }
212 return;
213 memerr:
214 perror(progname);
215 exit(1);
216 readerr:
217 fprintf(stderr, "%s: read error on input\n", progname);
218 exit(1);
219 #undef S_SEARCH
220 #undef S_SOURCE
221 #undef S_DIREC
222 }
223
224
225 print_values(funp) /* print out calculations */
226 double (*funp)();
227 {
228 register struct glare_dir *gd;
229
230 for (gd = all_dirs; gd != NULL; gd = gd->next)
231 printf("%f\t%f\n", gd->ang*(180.0/PI), (*funp)(gd));
232 }
233
234
235 double
236 direct(gd) /* compute direct vertical illuminance */
237 struct glare_dir *gd;
238 {
239 FVECT mydir;
240 double d, dval;
241 register struct glare_src *gs;
242
243 spinvector(mydir, midview.vdir, midview.vup, gd->ang);
244 dval = 0.0;
245 for (gs = all_srcs; gs != NULL; gs = gs->next) {
246 d = DOT(mydir,gs->dir);
247 if (d > FTINY)
248 dval += d * gs->dom * gs->lum;
249 }
250 return(dval);
251 }
252
253
254 double
255 indirect(gd) /* return indirect vertical illuminance */
256 struct glare_dir *gd;
257 {
258 return(gd->indirect);
259 }
260
261
262 double
263 total(gd) /* return total vertical illuminance */
264 struct glare_dir *gd;
265 {
266 return(direct(gd)+gd->indirect);
267 }
268
269
270 /*
271 * posindex - compute glare position index from:
272 *
273 * Source Direction
274 * View Direction
275 * View Up Direction
276 *
277 * All vectors are assumed to be normalized.
278 * This function is an implementation of the method proposed by
279 * Robert Levin in his 1975 JIES article.
280 * This calculation presumes the view direction and up vectors perpendicular.
281 * We return a value less than zero for improper positions.
282 */
283
284 double
285 posindex(sd, vd, vu) /* compute position index */
286 FVECT sd, vd, vu;
287 {
288 double sigma, tau;
289 double d;
290
291 d = DOT(sd,vd);
292 if (d <= 0.0)
293 return(-1.0);
294 if (d >= 1.0)
295 return(1.0);
296 sigma = acos(d) * (180./PI);
297 d = fabs(DOT(sd,vu)/sqrt(1.0-d*d));
298 if (d >= 1.0)
299 tau = 0.0;
300 else
301 tau = acos(d) * (180./PI);
302 return( exp( sigma*( (35.2 - tau*.31889 - 1.22*exp(-.22222*tau))*1e-3
303 + sigma*(21. + tau*(.26667 + tau*-.002963))*1e-5 )
304 ) );
305 }
306
307
308 double
309 dgi(gd) /* compute Daylight Glare Index */
310 struct glare_dir *gd;
311 {
312 register struct glare_src *gs;
313 FVECT mydir,testdir[7],vhor;
314 double r,omega,p[7],sum;
315 int i,n;
316
317 spinvector(mydir, midview.vdir, midview.vup, gd->ang);
318 sum = 0.0; n = 0;
319 for (gs = all_srcs; gs != NULL; gs = gs->next) {
320
321 /* compute 1/p^2 weighted solid angle of the source */
322 r = sqrt(1 - pow(1.-gs->dom/2./PI,2.));
323 fcross(vhor,gs->dir,midview.vup);
324 normalize(vhor);
325 VCOPY(testdir[0],gs->dir);
326 fvsum(testdir[1],gs->dir,vhor,r);
327 fvsum(testdir[2],gs->dir,vhor,0.5*r);
328 fvsum(testdir[5],testdir[2],midview.vup,-0.866*r);
329 fvsum(testdir[2],testdir[2],midview.vup,0.866*r);
330 fvsum(testdir[3],gs->dir,vhor,-r);
331 fvsum(testdir[4],gs->dir,vhor,-0.5*r);
332 fvsum(testdir[6],testdir[4],midview.vup,0.866*r);
333 fvsum(testdir[4],testdir[4],midview.vup,-0.866*r);
334 for (i = 0; i < 7; i++) {
335 normalize(testdir[i]);
336 p[i] = pow(posindex(testdir[i],mydir,midview.vup),-2.0);
337 if (p[i] <= FTINY) p[i] = 0.0;
338 }
339 r = 1-gs->dom/2./PI;
340 omega = gs->dom*p[0];
341 omega += (r*PI*(1+1/r/r)-2*PI)*(-p[0]+(p[1]+p[2])*0.5);
342 omega += (2*PI-r*PI*(1+1/r/r))*(-p[0]-0.1667*(p[1]+p[3])
343 +0.3334*(p[2]+p[4]+p[5]+p[6]));
344
345 sum += pow(gs->lum,1.6) * pow(omega,0.8) /
346 (gd->indirect/PI + 0.07*sqrt(gs->dom)*gs->lum);
347 n++;
348 }
349 if (n == 0)
350 return(0.0);
351 return( 10*log10(0.478*sum) );
352 }
353
354
355 double
356 brs_gi(gd) /* compute BRS Glare Index */
357 struct glare_dir *gd;
358 {
359 register struct glare_src *gs;
360 FVECT mydir;
361 double p;
362 double sum;
363
364 spinvector(mydir, midview.vdir, midview.vup, gd->ang);
365 sum = 0.0;
366 for (gs = all_srcs; gs != NULL; gs = gs->next) {
367 p = posindex(gs->dir, mydir, midview.vup);
368 if (p <= FTINY)
369 continue;
370 sum += pow(gs->lum/p,1.6) * pow(gs->dom,0.8);
371 }
372 if (sum <= FTINY)
373 return(0.0);
374 sum /= gd->indirect/PI;
375 return(10*log10(0.478*sum));
376 }
377
378
379 double
380 guth_dgr(gd) /* compute Guth discomfort glare rating */
381 struct glare_dir *gd;
382 {
383 #define q(w) (20.4*w+1.52*pow(w,.2)-.075)
384 register struct glare_src *gs;
385 FVECT mydir;
386 double p;
387 double sum;
388 double wtot, brsum;
389 int n;
390
391 spinvector(mydir, midview.vdir, midview.vup, gd->ang);
392 sum = wtot = brsum = 0.0; n = 0;
393 for (gs = all_srcs; gs != NULL; gs = gs->next) {
394 p = posindex(gs->dir, mydir, midview.vup);
395 if (p <= FTINY)
396 continue;
397 sum += gs->lum * q(gs->dom) / p;
398 brsum += gs->lum * gs->dom;
399 wtot += gs->dom;
400 n++;
401 }
402 if (n == 0)
403 return(0.0);
404 return( pow(.5*sum/pow((brsum+(5.-wtot)*gd->indirect/PI)/5.,.44),
405 pow((double)n, -.0914) ) );
406 #undef q
407 }
408
409
410 extern double erf(), erfc();
411
412 #ifndef M_SQRT2
413 #define M_SQRT2 1.41421356237309504880
414 #endif
415
416 #define norm_integral(z) (1.-.5*erfc((z)/M_SQRT2))
417
418
419 double
420 guth_vcp(gd) /* compute Guth visual comfort probability */
421 struct glare_dir *gd;
422 {
423 double dgr;
424
425 dgr = guth_dgr(gd);
426 if (dgr <= FTINY)
427 return(100.0);
428 return(100.*norm_integral(6.374-1.3227*log(dgr)));
429 }
430
431
432 double
433 cie_cgi(gd) /* compute CIE Glare Index */
434 struct glare_dir *gd;
435 {
436 register struct glare_src *gs;
437 FVECT mydir;
438 double dillum;
439 double p;
440 double sum;
441
442 spinvector(mydir, midview.vdir, midview.vup, gd->ang);
443 sum = 0.0;
444 for (gs = all_srcs; gs != NULL; gs = gs->next) {
445 p = posindex(gs->dir, mydir, midview.vup);
446 if (p <= FTINY)
447 continue;
448 sum += gs->lum*gs->lum * gs->dom / (p*p);
449 }
450 if (sum <= FTINY)
451 return(0.0);
452 dillum = direct(gd);
453 return(8.*log10(2.*sum*(1.+dillum/500.)/(dillum+gd->indirect)));
454 }
455
456
457 double
458 ugr(gd) /* compute Unified Glare Rating */
459 struct glare_dir *gd;
460 {
461 register struct glare_src *gs;
462 FVECT mydir;
463 double p;
464 double sum;
465
466 spinvector(mydir, midview.vdir, midview.vup, gd->ang);
467 sum = 0.0;
468 for (gs = all_srcs; gs != NULL; gs = gs->next) {
469 p = posindex(gs->dir, mydir, midview.vup);
470 if (p <= FTINY)
471 continue;
472 sum += gs->lum*gs->lum * gs->dom / (p*p);
473 }
474 if (sum <= FTINY)
475 return(0.0);
476 return(8.*log10(0.25*sum*PI/gd->indirect));
477 }