ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/bsdfrbf.c
(Generate patch)

Comparing ray/src/cv/bsdfrbf.c (file contents):
Revision 2.7 by greg, Wed Sep 25 17:42:45 2013 UTC vs.
Revision 2.29 by greg, Tue Dec 6 23:19:50 2016 UTC

# Line 7 | Line 7 | static const char RCSid[] = "$Id$";
7   *      G. Ward
8   */
9  
10 + /****************************************************************
11 + 1) Collect samples into a grid using the Shirley-Chiu
12 +        angular mapping from a hemisphere to a square.
13 +
14 + 2) Compute an adaptive quadtree by subdividing the grid so that
15 +        each leaf node has at least one sample up to as many
16 +        samples as fit nicely on a plane to within a certain
17 +        MSE tolerance.
18 +
19 + 3) Place one Gaussian lobe at each leaf node in the quadtree,
20 +        sizing it to have a radius equal to the leaf size and
21 +        a volume equal to the energy in that node.
22 + *****************************************************************/
23 +
24   #define _USE_MATH_DEFINES
25   #include <stdio.h>
26   #include <stdlib.h>
# Line 15 | Line 29 | static const char RCSid[] = "$Id$";
29   #include "bsdfrep.h"
30  
31   #ifndef RSCA
32 < #define RSCA            2.7             /* radius scaling factor (empirical) */
32 > #define RSCA            2.0             /* radius scaling factor (empirical) */
33   #endif
34 < #ifndef MAXFRAC
35 < #define MAXFRAC         0.5             /* maximum contribution to neighbor */
34 > #ifndef MAXSLOPE
35 > #define MAXSLOPE        1000.0          /* maximum slope for smooth region */
36   #endif
37 < #ifndef NNEIGH
38 < #define NNEIGH          10              /* number of neighbors to consider */
37 > #ifndef SMOOTH_MSE
38 > #define SMOOTH_MSE      5e-5            /* acceptable mean squared error */
39   #endif
40 <                                /* our loaded grid for this incident angle */
40 > #ifndef SMOOTH_MSER
41 > #define SMOOTH_MSER     0.03            /* acceptable relative MSE */
42 > #endif
43 > #define MAX_RAD         (GRIDRES/8)     /* maximum lobe radius */
44 >
45 > #define RBFALLOCB       10              /* RBF allocation block size */
46 >
47 >                                        /* loaded grid or comparison DSFs */
48   GRIDVAL                 dsf_grid[GRIDRES][GRIDRES];
49 +                                        /* allocated chrominance sums if any */
50 + float                   (*spec_grid)[GRIDRES][GRIDRES];
51 + int                     nspec_grid = 0;
52  
53 + /* Set up visible spectrum sampling */
54 + void
55 + set_spectral_samples(int nspec)
56 + {
57 +        if (rbf_colorimetry == RBCunknown) {
58 +                if (nspec_grid > 0) {
59 +                        free(spec_grid);
60 +                        spec_grid = NULL;
61 +                        nspec_grid = 0;
62 +                }
63 +                if (nspec == 1) {
64 +                        rbf_colorimetry = RBCphotopic;
65 +                        return;
66 +                }
67 +                if (nspec == 3) {
68 +                        rbf_colorimetry = RBCtristimulus;
69 +                        spec_grid = (float (*)[GRIDRES][GRIDRES])calloc(
70 +                                        2*GRIDRES*GRIDRES, sizeof(float) );
71 +                        if (spec_grid == NULL)
72 +                                goto mem_error;
73 +                        nspec_grid = 2;
74 +                        return;
75 +                }
76 +                fprintf(stderr,
77 +                        "%s: only 1 or 3 spectral samples currently supported\n",
78 +                                progname);
79 +                exit(1);
80 +        }
81 +        if (nspec != nspec_grid+1) {
82 +                fprintf(stderr,
83 +                        "%s: number of spectral samples cannot be changed\n",
84 +                                progname);
85 +                exit(1);
86 +        }
87 +        return;
88 + mem_error:
89 +        fprintf(stderr, "%s: out of memory in set_spectral_samples()\n",
90 +                        progname);
91 +        exit(1);
92 + }
93 +
94   /* Start new DSF input grid */
95   void
96   new_bsdf_data(double new_theta, double new_phi)
# Line 33 | Line 98 | new_bsdf_data(double new_theta, double new_phi)
98          if (!new_input_direction(new_theta, new_phi))
99                  exit(1);
100          memset(dsf_grid, 0, sizeof(dsf_grid));
101 +        if (nspec_grid > 0)
102 +                memset(spec_grid, 0, sizeof(float)*GRIDRES*GRIDRES*nspec_grid);
103   }
104  
105   /* Add BSDF data point */
106   void
107 < add_bsdf_data(double theta_out, double phi_out, double val, int isDSF)
107 > add_bsdf_data(double theta_out, double phi_out, const double val[], int isDSF)
108   {
109          FVECT   ovec;
110 +        double  cfact, Yval;
111          int     pos[2];
112  
113 +        if (nspec_grid > 2) {
114 +                fprintf(stderr, "%s: unsupported color space\n", progname);
115 +                exit(1);
116 +        }
117          if (!output_orient)             /* check output orientation */
118                  output_orient = 1 - 2*(theta_out > 90.);
119          else if (output_orient > 0 ^ theta_out < 90.) {
120 <                fputs("Cannot handle output angles on both sides of surface\n",
121 <                                stderr);
120 >                fprintf(stderr,
121 >                "%s: cannot handle output angles on both sides of surface\n",
122 >                                progname);
123                  exit(1);
124          }
125          ovec[2] = sin((M_PI/180.)*theta_out);
126          ovec[0] = cos((M_PI/180.)*phi_out) * ovec[2];
127          ovec[1] = sin((M_PI/180.)*phi_out) * ovec[2];
128          ovec[2] = sqrt(1. - ovec[2]*ovec[2]);
129 +                                        /* BSDF to DSF correction */
130 +        cfact = isDSF ? 1. : ovec[2];
131  
132 <        if (!isDSF)
58 <                val *= ovec[2];         /* convert from BSDF to DSF */
59 <
132 >        Yval = cfact * val[rbf_colorimetry==RBCtristimulus];
133                                          /* update BSDF histogram */
134 <        if (val < BSDF2BIG*ovec[2] && val > BSDF2SML*ovec[2])
135 <                ++bsdf_hist[histndx(val/ovec[2])];
134 >        if (BSDF2SML*ovec[2] < Yval && Yval < BSDF2BIG*ovec[2])
135 >                ++bsdf_hist[histndx(Yval/ovec[2])];
136  
137          pos_from_vec(pos, ovec);
138  
139 <        dsf_grid[pos[0]][pos[1]].vsum += val;
140 <        dsf_grid[pos[0]][pos[1]].nval++;
139 >        dsf_grid[pos[0]][pos[1]].sum.v += Yval;
140 >        dsf_grid[pos[0]][pos[1]].sum.n++;
141 >                                        /* add in X and Z values */
142 >        if (rbf_colorimetry == RBCtristimulus) {
143 >                spec_grid[0][pos[0]][pos[1]] += cfact * val[0];
144 >                spec_grid[1][pos[0]][pos[1]] += cfact * val[2];
145 >        }
146   }
147  
148 < /* Compute radii for non-empty bins */
71 < /* (distance to furthest empty bin for which non-empty bin is the closest) */
148 > /* Compute minimum BSDF from histogram (does not clear) */
149   static void
73 compute_radii(void)
74 {
75        unsigned int    fill_grid[GRIDRES][GRIDRES];
76        unsigned short  fill_cnt[GRIDRES][GRIDRES];
77        FVECT           ovec0, ovec1;
78        double          ang2, lastang2;
79        int             r, i, j, jn, ii, jj, inear, jnear;
80
81        r = GRIDRES/2;                          /* proceed in zig-zag */
82        for (i = 0; i < GRIDRES; i++)
83            for (jn = 0; jn < GRIDRES; jn++) {
84                j = (i&1) ? jn : GRIDRES-1-jn;
85                if (dsf_grid[i][j].nval)        /* find empty grid pos. */
86                        continue;
87                ovec_from_pos(ovec0, i, j);
88                inear = jnear = -1;             /* find nearest non-empty */
89                lastang2 = M_PI*M_PI;
90                for (ii = i-r; ii <= i+r; ii++) {
91                    if (ii < 0) continue;
92                    if (ii >= GRIDRES) break;
93                    for (jj = j-r; jj <= j+r; jj++) {
94                        if (jj < 0) continue;
95                        if (jj >= GRIDRES) break;
96                        if (!dsf_grid[ii][jj].nval)
97                                continue;
98                        ovec_from_pos(ovec1, ii, jj);
99                        ang2 = 2. - 2.*DOT(ovec0,ovec1);
100                        if (ang2 >= lastang2)
101                                continue;
102                        lastang2 = ang2;
103                        inear = ii; jnear = jj;
104                    }
105                }
106                if (inear < 0) {
107                        fprintf(stderr,
108                                "%s: Could not find non-empty neighbor!\n",
109                                        progname);
110                        exit(1);
111                }
112                ang2 = sqrt(lastang2);
113                r = ANG2R(ang2);                /* record if > previous */
114                if (r > dsf_grid[inear][jnear].crad)
115                        dsf_grid[inear][jnear].crad = r;
116                                                /* next search radius */
117                r = ang2*(2.*GRIDRES/M_PI) + 3;
118            }
119                                                /* blur radii over hemisphere */
120        memset(fill_grid, 0, sizeof(fill_grid));
121        memset(fill_cnt, 0, sizeof(fill_cnt));
122        for (i = 0; i < GRIDRES; i++)
123            for (j = 0; j < GRIDRES; j++) {
124                if (!dsf_grid[i][j].crad)
125                        continue;               /* missing distance */
126                r = R2ANG(dsf_grid[i][j].crad)*(2.*RSCA*GRIDRES/M_PI);
127                for (ii = i-r; ii <= i+r; ii++) {
128                    if (ii < 0) continue;
129                    if (ii >= GRIDRES) break;
130                    for (jj = j-r; jj <= j+r; jj++) {
131                        if (jj < 0) continue;
132                        if (jj >= GRIDRES) break;
133                        if ((ii-i)*(ii-i) + (jj-j)*(jj-j) > r*r)
134                                continue;
135                        fill_grid[ii][jj] += dsf_grid[i][j].crad;
136                        fill_cnt[ii][jj]++;
137                    }
138                }
139            }
140                                                /* copy back blurred radii */
141        for (i = 0; i < GRIDRES; i++)
142            for (j = 0; j < GRIDRES; j++)
143                if (fill_cnt[i][j])
144                        dsf_grid[i][j].crad = fill_grid[i][j]/fill_cnt[i][j];
145 }
146
147 /* Cull points for more uniform distribution, leave all nval 0 or 1 */
148 static void
149 cull_values(void)
150 {
151        FVECT   ovec0, ovec1;
152        double  maxang, maxang2;
153        int     i, j, ii, jj, r;
154                                                /* simple greedy algorithm */
155        for (i = 0; i < GRIDRES; i++)
156            for (j = 0; j < GRIDRES; j++) {
157                if (!dsf_grid[i][j].nval)
158                        continue;
159                if (!dsf_grid[i][j].crad)
160                        continue;               /* shouldn't happen */
161                ovec_from_pos(ovec0, i, j);
162                maxang = 2.*R2ANG(dsf_grid[i][j].crad);
163                if (maxang > ovec0[2])          /* clamp near horizon */
164                        maxang = ovec0[2];
165                r = maxang*(2.*GRIDRES/M_PI) + 1;
166                maxang2 = maxang*maxang;
167                for (ii = i-r; ii <= i+r; ii++) {
168                    if (ii < 0) continue;
169                    if (ii >= GRIDRES) break;
170                    for (jj = j-r; jj <= j+r; jj++) {
171                        if (jj < 0) continue;
172                        if (jj >= GRIDRES) break;
173                        if (!dsf_grid[ii][jj].nval)
174                                continue;
175                        if ((ii == i) & (jj == j))
176                                continue;       /* don't get self-absorbed */
177                        ovec_from_pos(ovec1, ii, jj);
178                        if (2. - 2.*DOT(ovec0,ovec1) >= maxang2)
179                                continue;
180                                                /* absorb sum */
181                        dsf_grid[i][j].vsum += dsf_grid[ii][jj].vsum;
182                        dsf_grid[i][j].nval += dsf_grid[ii][jj].nval;
183                                                /* keep value, though */
184                        dsf_grid[ii][jj].vsum /= (float)dsf_grid[ii][jj].nval;
185                        dsf_grid[ii][jj].nval = 0;
186                    }
187                }
188            }
189                                                /* final averaging pass */
190        for (i = 0; i < GRIDRES; i++)
191            for (j = 0; j < GRIDRES; j++)
192                if (dsf_grid[i][j].nval > 1) {
193                        dsf_grid[i][j].vsum /= (float)dsf_grid[i][j].nval;
194                        dsf_grid[i][j].nval = 1;
195                }
196 }
197
198 /* Compute minimum BSDF from histogram and clear it */
199 static void
150   comp_bsdf_min()
151   {
152 <        int     cnt;
153 <        int     i, target;
152 >        unsigned long   cnt, target;
153 >        int             i;
154  
155          cnt = 0;
156          for (i = HISTLEN; i--; )
# Line 214 | Line 164 | comp_bsdf_min()
164          for (i = 0; cnt <= target; i++)
165                  cnt += bsdf_hist[i];
166          bsdf_min = histval(i-1);
217        memset(bsdf_hist, 0, sizeof(bsdf_hist));
167   }
168  
169 < /* Find n nearest sub-sampled neighbors to the given grid position */
169 > /* Determine if the given region is empty of grid samples */
170   static int
171 < get_neighbors(int neigh[][2], int n, const int i, const int j)
171 > empty_region(int x0, int x1, int y0, int y1)
172   {
173 <        int     k = 0;
174 <        int     r;
175 <                                                /* search concentric squares */
176 <        for (r = 1; r < GRIDRES; r++) {
177 <                int     ii, jj;
178 <                for (ii = i-r; ii <= i+r; ii++) {
179 <                        int     jstep = 1;
180 <                        if (ii < 0) continue;
181 <                        if (ii >= GRIDRES) break;
182 <                        if ((i-r < ii) & (ii < i+r))
183 <                                jstep = r<<1;
184 <                        for (jj = j-r; jj <= j+r; jj += jstep) {
185 <                                if (jj < 0) continue;
186 <                                if (jj >= GRIDRES) break;
187 <                                if (dsf_grid[ii][jj].nval) {
188 <                                        neigh[k][0] = ii;
189 <                                        neigh[k][1] = jj;
190 <                                        if (++k >= n)
191 <                                                return(n);
192 <                                }
193 <                        }
173 >        int     x, y;
174 >
175 >        for (x = x0; x < x1; x++)
176 >            for (y = y0; y < y1; y++)
177 >                if (dsf_grid[x][y].sum.n)
178 >                        return(0);
179 >        return(1);
180 > }
181 >
182 > /* Determine if the given region is smooth enough to be a single lobe */
183 > static int
184 > smooth_region(int x0, int x1, int y0, int y1)
185 > {
186 >        RREAL   rMtx[3][3];
187 >        FVECT   xvec;
188 >        double  A, B, C, nvs, sqerr;
189 >        int     x, y, n;
190 >                                        /* compute planar regression */
191 >        memset(rMtx, 0, sizeof(rMtx));
192 >        memset(xvec, 0, sizeof(xvec));
193 >        for (x = x0; x < x1; x++)
194 >            for (y = y0; y < y1; y++)
195 >                if ((n = dsf_grid[x][y].sum.n) > 0) {
196 >                        double  z = dsf_grid[x][y].sum.v;
197 >                        rMtx[0][0] += x*x*(double)n;
198 >                        rMtx[0][1] += x*y*(double)n;
199 >                        rMtx[0][2] += x*(double)n;
200 >                        rMtx[1][1] += y*y*(double)n;
201 >                        rMtx[1][2] += y*(double)n;
202 >                        rMtx[2][2] += (double)n;
203 >                        xvec[0] += x*z;
204 >                        xvec[1] += y*z;
205 >                        xvec[2] += z;
206                  }
207 <        }
208 <        return(k);
207 >        rMtx[1][0] = rMtx[0][1];
208 >        rMtx[2][0] = rMtx[0][2];
209 >        rMtx[2][1] = rMtx[1][2];
210 >        nvs = rMtx[2][2];
211 >        if (SDinvXform(rMtx, rMtx) != SDEnone)
212 >                return(1);              /* colinear values */
213 >        A = DOT(rMtx[0], xvec);
214 >        B = DOT(rMtx[1], xvec);
215 >        if (A*A + B*B > MAXSLOPE*MAXSLOPE)      /* too steep? */
216 >                return(0);
217 >        C = DOT(rMtx[2], xvec);
218 >        sqerr = 0.0;                    /* compute mean squared error */
219 >        for (x = x0; x < x1; x++)
220 >            for (y = y0; y < y1; y++)
221 >                if ((n = dsf_grid[x][y].sum.n) > 0) {
222 >                        double  d = A*x + B*y + C - dsf_grid[x][y].sum.v/n;
223 >                        sqerr += n*d*d;
224 >                }
225 >        if (sqerr <= nvs*SMOOTH_MSE)    /* below absolute MSE threshold? */
226 >                return(1);
227 >                                        /* OR below relative MSE threshold? */
228 >        return(sqerr*nvs <= xvec[2]*xvec[2]*SMOOTH_MSER);
229   }
230  
231 < /* Adjust coded radius for the given grid position based on neighborhood */
231 > /* Create new lobe based on integrated samples in region */
232   static int
233 < adj_coded_radius(const int i, const int j)
233 > create_lobe(RBFVAL *rvp, int x0, int x1, int y0, int y1)
234   {
235 <        const double    rad0 = R2ANG(dsf_grid[i][j].crad);
236 <        double          currad = RSCA * rad0;
237 <        int             neigh[NNEIGH][2];
238 <        int             n;
239 <        FVECT           our_dir;
235 >        double  vtot = 0.0;
236 >        double  CIEXtot = 0.0, CIEZtot = 0.0;
237 >        int     nv = 0;
238 >        double  wxsum = 0.0, wysum = 0.0, wtsum = 0.0;
239 >        double  rad;
240 >        int     x, y;
241 >                                        /* compute average for region */
242 >        for (x = x0; x < x1; x++)
243 >            for (y = y0; y < y1; y++)
244 >                if (dsf_grid[x][y].sum.n) {
245 >                    const double        v = dsf_grid[x][y].sum.v;
246 >                    const int           n = dsf_grid[x][y].sum.n;
247  
248 <        ovec_from_pos(our_dir, i, j);
249 <        n = get_neighbors(neigh, NNEIGH, i, j);
250 <        while (n--) {
251 <                FVECT   their_dir;
252 <                double  max_ratio, rad_ok2;
253 <                                                /* check our value at neighbor */
254 <                ovec_from_pos(their_dir, neigh[n][0], neigh[n][1]);
255 <                max_ratio = MAXFRAC * dsf_grid[neigh[n][0]][neigh[n][1]].vsum
256 <                                / dsf_grid[i][j].vsum;
257 <                if (max_ratio >= 1)
258 <                        continue;
259 <                rad_ok2 = (DOT(their_dir,our_dir) - 1.)/log(max_ratio);
260 <                if (rad_ok2 >= currad*currad)
261 <                        continue;               /* value fraction OK */
262 <                currad = sqrt(rad_ok2);         /* else reduce lobe radius */
263 <                if (currad <= rad0)             /* limit how small we'll go */
264 <                        return(dsf_grid[i][j].crad);
248 >                    if (v > 0) {
249 >                        const double    wt = v / (double)n;
250 >                        wxsum += wt * x;
251 >                        wysum += wt * y;
252 >                        wtsum += wt;
253 >                    }
254 >                    vtot += v;
255 >                    nv += n;
256 >                    if (rbf_colorimetry == RBCtristimulus) {
257 >                        CIEXtot += spec_grid[0][x][y];
258 >                        CIEZtot += spec_grid[1][x][y];
259 >                    }
260 >                }
261 >        if (!nv) {
262 >                fprintf(stderr, "%s: internal - missing samples in create_lobe\n",
263 >                                progname);
264 >                exit(1);
265          }
266 <        return(ANG2R(currad));                  /* encode selected radius */
266 >        if (vtot <= 0)                  /* only create positive lobes */
267 >                return(0);
268 >                                        /* assign color */
269 >        if (rbf_colorimetry == RBCtristimulus) {
270 >                const double    df = 1.0 / (CIEXtot + vtot + CIEZtot);
271 >                C_COLOR         cclr;
272 >                c_cset(&cclr, CIEXtot*df, vtot*df);
273 >                rvp->chroma = c_encodeChroma(&cclr);
274 >        } else
275 >                rvp->chroma = c_dfchroma;
276 >                                        /* peak value based on integral */
277 >        vtot *= (x1-x0)*(y1-y0)*(2.*M_PI/GRIDRES/GRIDRES)/(double)nv;
278 >        rad = (RSCA/(double)GRIDRES)*(x1-x0);
279 >        rvp->peak =  vtot / ((2.*M_PI) * rad*rad);
280 >        rvp->crad = ANG2R(rad);         /* put peak at centroid */
281 >        rvp->gx = (int)(wxsum/wtsum + .5);
282 >        rvp->gy = (int)(wysum/wtsum + .5);
283 >        return(1);
284   }
285  
286 + /* Recursive function to build radial basis function representation */
287 + static int
288 + build_rbfrep(RBFVAL **arp, int *np, int x0, int x1, int y0, int y1)
289 + {
290 +        int     xmid = (x0+x1)>>1;
291 +        int     ymid = (y0+y1)>>1;
292 +        int     branched[4];
293 +        int     nadded, nleaves;
294 +                                        /* need to make this a leaf? */
295 +        if (empty_region(x0, xmid, y0, ymid) ||
296 +                        empty_region(xmid, x1, y0, ymid) ||
297 +                        empty_region(x0, xmid, ymid, y1) ||
298 +                        empty_region(xmid, x1, ymid, y1))
299 +                return(0);
300 +                                        /* add children (branches+leaves) */
301 +        if ((branched[0] = build_rbfrep(arp, np, x0, xmid, y0, ymid)) < 0)
302 +                return(-1);
303 +        if ((branched[1] = build_rbfrep(arp, np, xmid, x1, y0, ymid)) < 0)
304 +                return(-1);
305 +        if ((branched[2] = build_rbfrep(arp, np, x0, xmid, ymid, y1)) < 0)
306 +                return(-1);
307 +        if ((branched[3] = build_rbfrep(arp, np, xmid, x1, ymid, y1)) < 0)
308 +                return(-1);
309 +        nadded = branched[0] + branched[1] + branched[2] + branched[3];
310 +        nleaves = !branched[0] + !branched[1] + !branched[2] + !branched[3];
311 +        if (!nleaves)                   /* nothing but branches? */
312 +                return(nadded);
313 +                                        /* combine 4 leaves into 1? */
314 +        if ((nleaves == 4) & (x1-x0 <= MAX_RAD) &&
315 +                        smooth_region(x0, x1, y0, y1))
316 +                return(0);
317 +                                        /* need more array space? */
318 +        if ((*np+nleaves-1)>>RBFALLOCB != (*np-1)>>RBFALLOCB) {
319 +                *arp = (RBFVAL *)realloc(*arp,
320 +                                sizeof(RBFVAL)*(*np+nleaves-1+(1<<RBFALLOCB)));
321 +                if (*arp == NULL)
322 +                        return(-1);
323 +        }
324 +                                        /* create lobes for leaves */
325 +        if (!branched[0] && create_lobe(*arp+*np, x0, xmid, y0, ymid)) {
326 +                ++(*np); ++nadded;
327 +        }
328 +        if (!branched[1] && create_lobe(*arp+*np, xmid, x1, y0, ymid)) {
329 +                ++(*np); ++nadded;
330 +        }
331 +        if (!branched[2] && create_lobe(*arp+*np, x0, xmid, ymid, y1)) {
332 +                ++(*np); ++nadded;
333 +        }
334 +        if (!branched[3] && create_lobe(*arp+*np, xmid, x1, ymid, y1)) {
335 +                ++(*np); ++nadded;
336 +        }
337 +        return(nadded);
338 + }
339 +
340   /* Count up filled nodes and build RBF representation from current grid */
341   RBFNODE *
342 < make_rbfrep(void)
342 > make_rbfrep()
343   {
285        int     niter = 16;
286        double  lastVar, thisVar = 100.;
287        int     nn;
344          RBFNODE *newnode;
345 <        RBFVAL  *itera;
346 <        int     i, j;
291 <                                /* compute RBF radii */
292 <        compute_radii();
293 <                                /* coagulate lobes */
294 <        cull_values();
295 <        nn = 0;                 /* count selected bins */
296 <        for (i = 0; i < GRIDRES; i++)
297 <            for (j = 0; j < GRIDRES; j++)
298 <                nn += dsf_grid[i][j].nval;
345 >        RBFVAL  *rbfarr;
346 >        int     nn;
347                                  /* compute minimum BSDF */
348          comp_bsdf_min();
349 <                                /* allocate RBF array */
350 <        newnode = (RBFNODE *)malloc(sizeof(RBFNODE) + sizeof(RBFVAL)*(nn-1));
349 >                                /* create RBF node list */
350 >        rbfarr = NULL; nn = 0;
351 >        if (build_rbfrep(&rbfarr, &nn, 0, GRIDRES, 0, GRIDRES) <= 0) {
352 >                if (nn)
353 >                        goto memerr;
354 >                fprintf(stderr,
355 >                        "%s: warning - skipping bad incidence (%.1f,%.1f)\n",
356 >                                progname, theta_in_deg, phi_in_deg);
357 >                return(NULL);
358 >        }
359 >                                /* (re)allocate RBF array */
360 >        newnode = (RBFNODE *)realloc(rbfarr,
361 >                        sizeof(RBFNODE) + sizeof(RBFVAL)*(nn-1));
362          if (newnode == NULL)
363                  goto memerr;
364 +                                /* copy computed lobes into RBF node */
365 +        memmove(newnode->rbfa, newnode, sizeof(RBFVAL)*nn);
366          newnode->ord = -1;
367          newnode->next = NULL;
368          newnode->ejl = NULL;
# Line 309 | Line 370 | make_rbfrep(void)
370          newnode->invec[0] = cos((M_PI/180.)*phi_in_deg)*newnode->invec[2];
371          newnode->invec[1] = sin((M_PI/180.)*phi_in_deg)*newnode->invec[2];
372          newnode->invec[2] = input_orient*sqrt(1. - newnode->invec[2]*newnode->invec[2]);
373 <        newnode->vtotal = 0;
373 >        newnode->vtotal = .0;
374          newnode->nrbf = nn;
375 <        nn = 0;                 /* fill RBF array */
376 <        for (i = 0; i < GRIDRES; i++)
377 <            for (j = 0; j < GRIDRES; j++)
317 <                if (dsf_grid[i][j].nval) {
318 <                        newnode->rbfa[nn].peak = dsf_grid[i][j].vsum;
319 <                        newnode->rbfa[nn].crad = adj_coded_radius(i, j);
320 <                        newnode->rbfa[nn].gx = i;
321 <                        newnode->rbfa[nn].gy = j;
322 <                        ++nn;
323 <                }
324 <                                /* iterate to improve interpolation accuracy */
325 <        itera = (RBFVAL *)malloc(sizeof(RBFVAL)*newnode->nrbf);
326 <        if (itera == NULL)
327 <                goto memerr;
328 <        memcpy(itera, newnode->rbfa, sizeof(RBFVAL)*newnode->nrbf);
329 <        do {
330 <                double  dsum = 0, dsum2 = 0;
331 <                nn = 0;
332 <                for (i = 0; i < GRIDRES; i++)
333 <                    for (j = 0; j < GRIDRES; j++)
334 <                        if (dsf_grid[i][j].nval) {
335 <                                FVECT   odir;
336 <                                double  corr;
337 <                                ovec_from_pos(odir, i, j);
338 <                                itera[nn++].peak *= corr =
339 <                                        dsf_grid[i][j].vsum /
340 <                                                eval_rbfrep(newnode, odir);
341 <                                dsum += 1. - corr;
342 <                                dsum2 += (1.-corr)*(1.-corr);
343 <                        }
344 <                memcpy(newnode->rbfa, itera, sizeof(RBFVAL)*newnode->nrbf);
345 <                lastVar = thisVar;
346 <                thisVar = dsum2/(double)nn;
375 >                                /* compute sum for normalization */
376 >        while (nn-- > 0)
377 >                newnode->vtotal += rbf_volume(&newnode->rbfa[nn]);
378   #ifdef DEBUG
379 <                fprintf(stderr, "Avg., RMS error: %.1f%%  %.1f%%\n",
349 <                                        100.*dsum/(double)nn,
350 <                                        100.*sqrt(thisVar));
351 < #endif
352 <        } while (--niter > 0 && lastVar-thisVar > 0.02*lastVar);
353 <
354 <        free(itera);
355 <        nn = 0;                 /* compute sum for normalization */
356 <        while (nn < newnode->nrbf)
357 <                newnode->vtotal += rbf_volume(&newnode->rbfa[nn++]);
358 < #ifdef DEBUG
379 >        fprintf(stderr, "Built RBF with %d lobes\n", newnode->nrbf);
380          fprintf(stderr, "Integrated DSF at (%.1f,%.1f) deg. is %.2f\n",
381                          get_theta180(newnode->invec), get_phi360(newnode->invec),
382                          newnode->vtotal);
383   #endif
384          insert_dsf(newnode);
364
385          return(newnode);
386   memerr:
387          fprintf(stderr, "%s: Out of memory in make_rbfrep()\n", progname);

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines