ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/bsdfpeaks.c
Revision: 2.2
Committed: Wed May 21 21:21:25 2025 UTC (10 days, 16 hours ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.1: +9 -9 lines
Log Message:
refactor(bsdfpeaks): Minor typing fixes

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: bsdfpeaks.c,v 2.1 2025/05/21 17:23:07 greg Exp $";
3 #endif
4 /*
5 * Compute minimum FWHM peak for each incident direction in SIR input.
6 * Report FWHM of corresponding peaks in XML representations if provided.
7 */
8
9 #define _USE_MATH_DEFINES
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <math.h>
13 #include "bsdfrep.h"
14
15 typedef struct {
16 float peakv; /* peak BSDF value */
17 float width; /* smallest FWHM (deg) */
18 RBFNODE *rbs; /* incident system */
19 int ndx; /* peak index for RBFVAL */
20 } FWHM; /* struct to hold peak value */
21
22 typedef double eval_f(const FVECT vin, const FVECT vout, const void *p);
23
24 char *progname; /* needed by bsdfrep.c */
25
26 /* Comparison function to put larger peaks first */
27 int
28 cmpFWHM(const void *p0, const void *p1)
29 {
30 float diff = (*(const FWHM *)p0).peakv -
31 (*(const FWHM *)p1).peakv;
32
33 if (diff > 0) return(-1);
34 if (diff < 0) return(1);
35 return(0);
36 }
37
38 /* BSDF evaluation function for RBF system */
39 double
40 rbf_eval(const FVECT vin, const FVECT vout, const void *p)
41 {
42 /* XXX verify vin == p->invec ? */
43 return(eval_rbfrep((const RBFNODE *)p, vout));
44 }
45
46 /* BSDF evaluation for XML input */
47 double
48 bsdf_eval(const FVECT vin, const FVECT vout, const void *p)
49 {
50 SDValue sv;
51
52 if (SDreportError(
53 SDevalBSDF(&sv, vin, vout, (const SDData *)p),
54 stderr))
55 exit(1);
56
57 return(sv.cieY);
58 }
59
60 /* Find full-width, half-maximum in radians around BSDF direction */
61 double
62 getFWHM(const FVECT vin, const FVECT vc, double rad0, eval_f *ev, const void *p)
63 {
64 const double peakv = (*ev)(vin, vc, p);
65 double rad1 = rad0; /* current radii */
66
67 while (rad0 < M_PI/2.) { /* look for FWHM */
68 FVECT v0, vt;
69 double phi;
70 v0[0] = 1; v0[1] = v0[2] = 0;
71 geodesic(v0, vc, v0, rad0, GEOD_RAD); /* use vc as pivot */
72 for (phi = 0; phi < 2.*M_PI; phi += M_PI/18.) {
73 spinvector(vt, v0, vc, phi);
74 if ((*ev)(vin, vt, p) <= .5*peakv) { /* found one side? */
75 FVECT vt1;
76 while (rad1 < M_PI/2.) { /* bracket peak */
77 geodesic(vt1, vt, vc, rad0+rad1, GEOD_RAD);
78 if ((*ev)(vin, vt1, p) <= .5*peakv)
79 return(rad0+rad1); /* got both! */
80 rad1 *= 1.05; /* else bump rad1 */
81 }
82 }
83 }
84 rad1 = rad0 *= 1.05; /* or expand search */
85 }
86 return(M_PI); /* failure return */
87 }
88
89 /* Get outgoing direction for the given FWHM record */
90 void
91 getOutDir(FVECT vo, FWHM *dp)
92 {
93 RBFVAL *vp = dp->rbs->rbfa + dp->ndx;
94
95 ovec_from_pos(vo, vp->gx, vp->gy);
96 }
97
98 /* Assign FWHM record for specified RBF system */
99 void
100 assignFWHM(FWHM *dp, RBFNODE *rbf)
101 {
102 FVECT vo;
103 int j;
104 double rad;
105
106 dp->rbs = rbf;
107 dp->ndx = 0; /* find peak outgoing */
108 for (j = rbf->nrbf; --j; )
109 if (rbf->rbfa[j].peak > rbf->rbfa[dp->ndx].peak)
110 dp->ndx = j;
111 /* record peak */
112 getOutDir(vo, dp);
113 dp->peakv = eval_rbfrep(rbf, vo);
114 /* get FWHM angle in degrees */
115 dp->width = 180./M_PI * getFWHM(rbf->invec, vo,
116 R2ANG(rbf->rbfa[dp->ndx].crad),
117 rbf_eval, rbf);
118 }
119
120 /* Evaluate FWHM for each incident direction recorded in SIR */
121 int
122 main(int argc, char *argv[])
123 {
124 RBFNODE *rbf;
125 SDData *sdp;
126 FILE *fp;
127 int ndirs;
128 FWHM *peaka;
129 int i;
130
131 progname = argv[0];
132 if (argc < 2)
133 goto userr;
134
135 fp = fopen(argv[1], "rb"); /* load SIR input */
136 if (fp == NULL) {
137 fprintf(stderr, "%s: cannot open BSDF interpolant '%s'\n",
138 progname, argv[1]);
139 return(1);
140 }
141 if (!load_bsdf_rep(fp))
142 return(1);
143 fclose(fp);
144 for (i = 2; i < argc; i++) /* check/load any XMLs */
145 if (SDcacheFile(argv[i]) == NULL)
146 return(1);
147 ndirs = 0; /* count input directions */
148 for (rbf = dsf_list; rbf != NULL; rbf = rbf->next) {
149 if (rbf->nrbf <= 0) {
150 ndirs = 0;
151 break;
152 }
153 ++ndirs;
154 }
155 if (!ndirs) {
156 fprintf(stderr, "%s: missing/bad RBFs in '%s'\n", progname, argv[1]);
157 return(1);
158 }
159 /* print output header */
160 printf("%d incident directions in '%s': %s -> %s\n", ndirs, argv[1],
161 input_orient>0 ? "Front" : "Back",
162 output_orient>0 ? "Front" : "Back");
163 fputs("Incident (theta, phi)\tExiting (theta, phi)\tPeak\tFWHM", stdout);
164 for (i = 2; i < argc; i++)
165 printf("\t'%s'", argv[i]);
166 fputc('\n', stdout);
167 /* find SIR peaks */
168 peaka = (FWHM *)malloc(sizeof(FWHM)*ndirs);
169 if (peaka == NULL) return(1);
170 for (i = 0, rbf = dsf_list; i < ndirs; i++, rbf = rbf->next)
171 assignFWHM(&peaka[i], rbf);
172 /* sort strong to weak */
173 qsort(peaka, ndirs, sizeof(FWHM), cmpFWHM);
174
175 for (i = 0; i < ndirs; i++) { /* report FWHM for each incidence */
176 FVECT vout;
177 int j;
178 getOutDir(vout, &peaka[i]);
179 printf("%.0f %.0f\t%.0f %.0f", get_theta180(peaka[i].rbs->invec),
180 get_phi360(peaka[i].rbs->invec),
181 get_theta180(vout), get_phi360(vout));
182 /* peak and FWHM from SIR */
183 printf("\t%.2e\t%.1f", peaka[i].peakv, peaka[i].width);
184 /* FWHM for each XML */
185 for (j = 2; j < argc; j++) {
186 const SDData *sd = SDcacheFile(argv[j]);
187 double psa;
188 if (SDreportError(
189 SDsizeBSDF(&psa, peaka[i].rbs->invec,
190 NULL, SDqueryMin, sd),
191 stderr))
192 return(1);
193
194 printf("\t%.1f", 180./M_PI * getFWHM(peaka[i].rbs->invec,
195 vout, sqrt(psa/M_PI),
196 bsdf_eval, sd));
197 }
198 fputc('\n', stdout);
199 }
200 return(0);
201 userr:
202 fprintf(stderr, "Usage: %s bsdf.sir [bsdfrep1.xml ..]\n", progname);
203 return(1);
204 }