| 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> | 
| 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 | < | /* our loaded grid for this incident angle */ | 
| 34 | > | #ifndef SMOOTH_MSE | 
| 35 | > | #define SMOOTH_MSE      5e-5            /* acceptable mean squared error */ | 
| 36 | > | #endif | 
| 37 | > | #ifndef SMOOTH_MSER | 
| 38 | > | #define SMOOTH_MSER     0.03            /* acceptable relative MSE */ | 
| 39 | > | #endif | 
| 40 | > | #define MAX_RAD         (GRIDRES/8)     /* maximum lobe radius */ | 
| 41 | > |  | 
| 42 | > | #define RBFALLOCB       10              /* RBF allocation block size */ | 
| 43 | > |  | 
| 44 | > | /* loaded grid or comparison DSFs */ | 
| 45 |  | GRIDVAL                 dsf_grid[GRIDRES][GRIDRES]; | 
| 46 |  |  | 
| 47 |  | /* Start new DSF input grid */ | 
| 81 |  |  | 
| 82 |  | pos_from_vec(pos, ovec); | 
| 83 |  |  | 
| 84 | < | dsf_grid[pos[0]][pos[1]].vsum += val; | 
| 85 | < | dsf_grid[pos[0]][pos[1]].nval++; | 
| 84 | > | dsf_grid[pos[0]][pos[1]].sum.v += val; | 
| 85 | > | dsf_grid[pos[0]][pos[1]].sum.n++; | 
| 86 |  | } | 
| 87 |  |  | 
| 88 | < | /* Compute radii for non-empty bins */ | 
| 65 | < | /* (distance to furthest empty bin for which non-empty bin is the closest) */ | 
| 88 | > | /* Compute minimum BSDF from histogram (does not clear) */ | 
| 89 |  | static void | 
| 90 | < | compute_radii(void) | 
| 90 | > | comp_bsdf_min() | 
| 91 |  | { | 
| 92 | < | unsigned int    fill_grid[GRIDRES][GRIDRES]; | 
| 93 | < | unsigned short  fill_cnt[GRIDRES][GRIDRES]; | 
| 71 | < | FVECT           ovec0, ovec1; | 
| 72 | < | double          ang2, lastang2; | 
| 73 | < | int             r, i, j, jn, ii, jj, inear, jnear; | 
| 92 | > | unsigned long   cnt, target; | 
| 93 | > | int             i; | 
| 94 |  |  | 
| 95 | < | r = GRIDRES/2;                          /* proceed in zig-zag */ | 
| 96 | < | for (i = 0; i < GRIDRES; i++) | 
| 97 | < | for (jn = 0; jn < GRIDRES; jn++) { | 
| 98 | < | j = (i&1) ? jn : GRIDRES-1-jn; | 
| 99 | < | if (dsf_grid[i][j].nval)        /* find empty grid pos. */ | 
| 100 | < | continue; | 
| 101 | < | ovec_from_pos(ovec0, i, j); | 
| 102 | < | inear = jnear = -1;             /* find nearest non-empty */ | 
| 103 | < | lastang2 = M_PI*M_PI; | 
| 104 | < | for (ii = i-r; ii <= i+r; ii++) { | 
| 105 | < | if (ii < 0) continue; | 
| 106 | < | if (ii >= GRIDRES) break; | 
| 107 | < | for (jj = j-r; jj <= j+r; jj++) { | 
| 108 | < | if (jj < 0) continue; | 
| 109 | < | if (jj >= GRIDRES) break; | 
| 110 | < | if (!dsf_grid[ii][jj].nval) | 
| 111 | < | continue; | 
| 112 | < | ovec_from_pos(ovec1, ii, jj); | 
| 113 | < | ang2 = 2. - 2.*DOT(ovec0,ovec1); | 
| 114 | < | if (ang2 >= lastang2) | 
| 115 | < | continue; | 
| 116 | < | lastang2 = ang2; | 
| 117 | < | inear = ii; jnear = jj; | 
| 118 | < | } | 
| 95 | > | cnt = 0; | 
| 96 | > | for (i = HISTLEN; i--; ) | 
| 97 | > | cnt += bsdf_hist[i]; | 
| 98 | > | if (!cnt) {                             /* shouldn't happen */ | 
| 99 | > | bsdf_min = 0; | 
| 100 | > | return; | 
| 101 | > | } | 
| 102 | > | target = cnt/100;                       /* ignore bottom 1% */ | 
| 103 | > | cnt = 0; | 
| 104 | > | for (i = 0; cnt <= target; i++) | 
| 105 | > | cnt += bsdf_hist[i]; | 
| 106 | > | bsdf_min = histval(i-1); | 
| 107 | > | } | 
| 108 | > |  | 
| 109 | > | /* Determine if the given region is empty of grid samples */ | 
| 110 | > | static int | 
| 111 | > | empty_region(int x0, int x1, int y0, int y1) | 
| 112 | > | { | 
| 113 | > | int     x, y; | 
| 114 | > |  | 
| 115 | > | for (x = x0; x < x1; x++) | 
| 116 | > | for (y = y0; y < y1; y++) | 
| 117 | > | if (dsf_grid[x][y].sum.n) | 
| 118 | > | return(0); | 
| 119 | > | return(1); | 
| 120 | > | } | 
| 121 | > |  | 
| 122 | > | /* Determine if the given region is smooth enough to be a single lobe */ | 
| 123 | > | static int | 
| 124 | > | smooth_region(int x0, int x1, int y0, int y1) | 
| 125 | > | { | 
| 126 | > | RREAL   rMtx[3][3]; | 
| 127 | > | FVECT   xvec; | 
| 128 | > | double  A, B, C, nvs, sqerr; | 
| 129 | > | int     x, y, n; | 
| 130 | > | /* compute planar regression */ | 
| 131 | > | memset(rMtx, 0, sizeof(rMtx)); | 
| 132 | > | memset(xvec, 0, sizeof(xvec)); | 
| 133 | > | for (x = x0; x < x1; x++) | 
| 134 | > | for (y = y0; y < y1; y++) | 
| 135 | > | if ((n = dsf_grid[x][y].sum.n) > 0) { | 
| 136 | > | double  z = dsf_grid[x][y].sum.v; | 
| 137 | > | rMtx[0][0] += x*x*(double)n; | 
| 138 | > | rMtx[0][1] += x*y*(double)n; | 
| 139 | > | rMtx[0][2] += x*(double)n; | 
| 140 | > | rMtx[1][1] += y*y*(double)n; | 
| 141 | > | rMtx[1][2] += y*(double)n; | 
| 142 | > | rMtx[2][2] += (double)n; | 
| 143 | > | xvec[0] += x*z; | 
| 144 | > | xvec[1] += y*z; | 
| 145 | > | xvec[2] += z; | 
| 146 |  | } | 
| 147 | < | if (inear < 0) { | 
| 148 | < | fprintf(stderr, | 
| 149 | < | "%s: Could not find non-empty neighbor!\n", | 
| 150 | < | progname); | 
| 151 | < | exit(1); | 
| 147 | > | rMtx[1][0] = rMtx[0][1]; | 
| 148 | > | rMtx[2][0] = rMtx[0][2]; | 
| 149 | > | rMtx[2][1] = rMtx[1][2]; | 
| 150 | > | nvs = rMtx[2][2]; | 
| 151 | > | if (SDinvXform(rMtx, rMtx) != SDEnone) | 
| 152 | > | return(1);              /* colinear values */ | 
| 153 | > | A = DOT(rMtx[0], xvec); | 
| 154 | > | B = DOT(rMtx[1], xvec); | 
| 155 | > | C = DOT(rMtx[2], xvec); | 
| 156 | > | sqerr = 0.0;                    /* compute mean squared error */ | 
| 157 | > | for (x = x0; x < x1; x++) | 
| 158 | > | for (y = y0; y < y1; y++) | 
| 159 | > | if ((n = dsf_grid[x][y].sum.n) > 0) { | 
| 160 | > | double  d = A*x + B*y + C - dsf_grid[x][y].sum.v/n; | 
| 161 | > | sqerr += n*d*d; | 
| 162 |  | } | 
| 163 | < | ang2 = sqrt(lastang2); | 
| 164 | < | r = ANG2R(ang2);                /* record if > previous */ | 
| 165 | < | if (r > dsf_grid[inear][jnear].crad) | 
| 166 | < | dsf_grid[inear][jnear].crad = r; | 
| 110 | < | /* next search radius */ | 
| 111 | < | r = ang2*(2.*GRIDRES/M_PI) + 3; | 
| 112 | < | } | 
| 113 | < | /* blur radii over hemisphere */ | 
| 114 | < | memset(fill_grid, 0, sizeof(fill_grid)); | 
| 115 | < | memset(fill_cnt, 0, sizeof(fill_cnt)); | 
| 116 | < | for (i = 0; i < GRIDRES; i++) | 
| 117 | < | for (j = 0; j < GRIDRES; j++) { | 
| 118 | < | if (!dsf_grid[i][j].crad) | 
| 119 | < | continue;               /* missing distance */ | 
| 120 | < | r = R2ANG(dsf_grid[i][j].crad)*(2.*RSCA*GRIDRES/M_PI); | 
| 121 | < | for (ii = i-r; ii <= i+r; ii++) { | 
| 122 | < | if (ii < 0) continue; | 
| 123 | < | if (ii >= GRIDRES) break; | 
| 124 | < | for (jj = j-r; jj <= j+r; jj++) { | 
| 125 | < | if (jj < 0) continue; | 
| 126 | < | if (jj >= GRIDRES) break; | 
| 127 | < | if ((ii-i)*(ii-i) + (jj-j)*(jj-j) > r*r) | 
| 128 | < | continue; | 
| 129 | < | fill_grid[ii][jj] += dsf_grid[i][j].crad; | 
| 130 | < | fill_cnt[ii][jj]++; | 
| 131 | < | } | 
| 132 | < | } | 
| 133 | < | } | 
| 134 | < | /* copy back blurred radii */ | 
| 135 | < | for (i = 0; i < GRIDRES; i++) | 
| 136 | < | for (j = 0; j < GRIDRES; j++) | 
| 137 | < | if (fill_cnt[i][j]) | 
| 138 | < | dsf_grid[i][j].crad = fill_grid[i][j]/fill_cnt[i][j]; | 
| 163 | > | if (sqerr <= nvs*SMOOTH_MSE)    /* below absolute MSE threshold? */ | 
| 164 | > | return(1); | 
| 165 | > | /* OR below relative MSE threshold? */ | 
| 166 | > | return(sqerr*nvs <= xvec[2]*xvec[2]*SMOOTH_MSER); | 
| 167 |  | } | 
| 168 |  |  | 
| 169 | < | /* Cull points for more uniform distribution, leave all nval 0 or 1 */ | 
| 170 | < | static void | 
| 171 | < | cull_values(void) | 
| 169 | > | /* Create new lobe based on integrated samples in region */ | 
| 170 | > | static int | 
| 171 | > | create_lobe(RBFVAL *rvp, int x0, int x1, int y0, int y1) | 
| 172 |  | { | 
| 173 | < | FVECT   ovec0, ovec1; | 
| 174 | < | double  maxang, maxang2; | 
| 175 | < | int     i, j, ii, jj, r; | 
| 176 | < | /* simple greedy algorithm */ | 
| 177 | < | for (i = 0; i < GRIDRES; i++) | 
| 178 | < | for (j = 0; j < GRIDRES; j++) { | 
| 179 | < | if (!dsf_grid[i][j].nval) | 
| 180 | < | continue; | 
| 181 | < | if (!dsf_grid[i][j].crad) | 
| 182 | < | continue;               /* shouldn't happen */ | 
| 183 | < | ovec_from_pos(ovec0, i, j); | 
| 184 | < | maxang = 2.*R2ANG(dsf_grid[i][j].crad); | 
| 185 | < | if (maxang > ovec0[2])          /* clamp near horizon */ | 
| 186 | < | maxang = ovec0[2]; | 
| 187 | < | r = maxang*(2.*GRIDRES/M_PI) + 1; | 
| 188 | < | maxang2 = maxang*maxang; | 
| 189 | < | for (ii = i-r; ii <= i+r; ii++) { | 
| 162 | < | if (ii < 0) continue; | 
| 163 | < | if (ii >= GRIDRES) break; | 
| 164 | < | for (jj = j-r; jj <= j+r; jj++) { | 
| 165 | < | if (jj < 0) continue; | 
| 166 | < | if (jj >= GRIDRES) break; | 
| 167 | < | if (!dsf_grid[ii][jj].nval) | 
| 168 | < | continue; | 
| 169 | < | if ((ii == i) & (jj == j)) | 
| 170 | < | continue;       /* don't get self-absorbed */ | 
| 171 | < | ovec_from_pos(ovec1, ii, jj); | 
| 172 | < | if (2. - 2.*DOT(ovec0,ovec1) >= maxang2) | 
| 173 | < | continue; | 
| 174 | < | /* absorb sum */ | 
| 175 | < | dsf_grid[i][j].vsum += dsf_grid[ii][jj].vsum; | 
| 176 | < | dsf_grid[i][j].nval += dsf_grid[ii][jj].nval; | 
| 177 | < | /* keep value, though */ | 
| 178 | < | dsf_grid[ii][jj].vsum /= (float)dsf_grid[ii][jj].nval; | 
| 179 | < | dsf_grid[ii][jj].nval = 0; | 
| 173 | > | double  vtot = 0.0; | 
| 174 | > | int     nv = 0; | 
| 175 | > | double  wxsum = 0.0, wysum = 0.0, wtsum = 0.0; | 
| 176 | > | double  rad; | 
| 177 | > | int     x, y; | 
| 178 | > | /* compute average for region */ | 
| 179 | > | for (x = x0; x < x1; x++) | 
| 180 | > | for (y = y0; y < y1; y++) | 
| 181 | > | if (dsf_grid[x][y].sum.n) { | 
| 182 | > | const double        v = dsf_grid[x][y].sum.v; | 
| 183 | > | const int           n = dsf_grid[x][y].sum.n; | 
| 184 | > |  | 
| 185 | > | if (v > 0) { | 
| 186 | > | double  wt = v / (double)n; | 
| 187 | > | wxsum += wt * x; | 
| 188 | > | wysum += wt * y; | 
| 189 | > | wtsum += wt; | 
| 190 |  | } | 
| 191 | + | vtot += v; | 
| 192 | + | nv += n; | 
| 193 |  | } | 
| 194 | < | } | 
| 195 | < | /* final averaging pass */ | 
| 196 | < | for (i = 0; i < GRIDRES; i++) | 
| 197 | < | for (j = 0; j < GRIDRES; j++) | 
| 198 | < | if (dsf_grid[i][j].nval > 1) { | 
| 199 | < | dsf_grid[i][j].vsum /= (float)dsf_grid[i][j].nval; | 
| 200 | < | dsf_grid[i][j].nval = 1; | 
| 201 | < | } | 
| 194 | > | if (!nv) { | 
| 195 | > | fprintf(stderr, "%s: internal - missing samples in create_lobe\n", | 
| 196 | > | progname); | 
| 197 | > | exit(1); | 
| 198 | > | } | 
| 199 | > | if (vtot <= 0)                  /* only create positive lobes */ | 
| 200 | > | return(0); | 
| 201 | > | /* peak value based on integral */ | 
| 202 | > | vtot *= (x1-x0)*(y1-y0)*(2.*M_PI/GRIDRES/GRIDRES)/(double)nv; | 
| 203 | > | rad = (RSCA/(double)GRIDRES)*(x1-x0); | 
| 204 | > | rvp->peak =  vtot / ((2.*M_PI) * rad*rad); | 
| 205 | > | rvp->crad = ANG2R(rad);         /* put peak at centroid */ | 
| 206 | > | rvp->gx = (int)(wxsum/wtsum + .5); | 
| 207 | > | rvp->gy = (int)(wysum/wtsum + .5); | 
| 208 | > | return(1); | 
| 209 |  | } | 
| 210 |  |  | 
| 211 | + | /* Recursive function to build radial basis function representation */ | 
| 212 | + | static int | 
| 213 | + | build_rbfrep(RBFVAL **arp, int *np, int x0, int x1, int y0, int y1) | 
| 214 | + | { | 
| 215 | + | int     xmid = (x0+x1)>>1; | 
| 216 | + | int     ymid = (y0+y1)>>1; | 
| 217 | + | int     branched[4]; | 
| 218 | + | int     nadded, nleaves; | 
| 219 | + | /* need to make this a leaf? */ | 
| 220 | + | if (empty_region(x0, xmid, y0, ymid) || | 
| 221 | + | empty_region(xmid, x1, y0, ymid) || | 
| 222 | + | empty_region(x0, xmid, ymid, y1) || | 
| 223 | + | empty_region(xmid, x1, ymid, y1)) | 
| 224 | + | return(0); | 
| 225 | + | /* add children (branches+leaves) */ | 
| 226 | + | if ((branched[0] = build_rbfrep(arp, np, x0, xmid, y0, ymid)) < 0) | 
| 227 | + | return(-1); | 
| 228 | + | if ((branched[1] = build_rbfrep(arp, np, xmid, x1, y0, ymid)) < 0) | 
| 229 | + | return(-1); | 
| 230 | + | if ((branched[2] = build_rbfrep(arp, np, x0, xmid, ymid, y1)) < 0) | 
| 231 | + | return(-1); | 
| 232 | + | if ((branched[3] = build_rbfrep(arp, np, xmid, x1, ymid, y1)) < 0) | 
| 233 | + | return(-1); | 
| 234 | + | nadded = branched[0] + branched[1] + branched[2] + branched[3]; | 
| 235 | + | nleaves = !branched[0] + !branched[1] + !branched[2] + !branched[3]; | 
| 236 | + | if (!nleaves)                   /* nothing but branches? */ | 
| 237 | + | return(nadded); | 
| 238 | + | /* combine 4 leaves into 1? */ | 
| 239 | + | if ((nleaves == 4) & (x1-x0 <= MAX_RAD) && | 
| 240 | + | smooth_region(x0, x1, y0, y1)) | 
| 241 | + | return(0); | 
| 242 | + | /* need more array space? */ | 
| 243 | + | if ((*np+nleaves-1)>>RBFALLOCB != (*np-1)>>RBFALLOCB) { | 
| 244 | + | *arp = (RBFVAL *)realloc(*arp, | 
| 245 | + | sizeof(RBFVAL)*(*np+nleaves-1+(1<<RBFALLOCB))); | 
| 246 | + | if (*arp == NULL) | 
| 247 | + | return(-1); | 
| 248 | + | } | 
| 249 | + | /* create lobes for leaves */ | 
| 250 | + | if (!branched[0] && create_lobe(*arp+*np, x0, xmid, y0, ymid)) { | 
| 251 | + | ++(*np); ++nadded; | 
| 252 | + | } | 
| 253 | + | if (!branched[1] && create_lobe(*arp+*np, xmid, x1, y0, ymid)) { | 
| 254 | + | ++(*np); ++nadded; | 
| 255 | + | } | 
| 256 | + | if (!branched[2] && create_lobe(*arp+*np, x0, xmid, ymid, y1)) { | 
| 257 | + | ++(*np); ++nadded; | 
| 258 | + | } | 
| 259 | + | if (!branched[3] && create_lobe(*arp+*np, xmid, x1, ymid, y1)) { | 
| 260 | + | ++(*np); ++nadded; | 
| 261 | + | } | 
| 262 | + | return(nadded); | 
| 263 | + | } | 
| 264 | + |  | 
| 265 |  | /* Count up filled nodes and build RBF representation from current grid */ | 
| 266 |  | RBFNODE * | 
| 267 | < | make_rbfrep(void) | 
| 267 | > | make_rbfrep() | 
| 268 |  | { | 
| 196 | – | int     niter = 16; | 
| 197 | – | double  lastVar, thisVar = 100.; | 
| 198 | – | int     nn; | 
| 269 |  | RBFNODE *newnode; | 
| 270 | < | RBFVAL  *itera; | 
| 271 | < | int     i, j; | 
| 272 | < | /* compute RBF radii */ | 
| 273 | < | compute_radii(); | 
| 274 | < | /* coagulate lobes */ | 
| 275 | < | cull_values(); | 
| 276 | < | nn = 0;                 /* count selected bins */ | 
| 277 | < | for (i = 0; i < GRIDRES; i++) | 
| 278 | < | for (j = 0; j < GRIDRES; j++) | 
| 279 | < | nn += dsf_grid[i][j].nval; | 
| 280 | < | /* allocate RBF array */ | 
| 281 | < | newnode = (RBFNODE *)malloc(sizeof(RBFNODE) + sizeof(RBFVAL)*(nn-1)); | 
| 270 | > | RBFVAL  *rbfarr; | 
| 271 | > | int     nn; | 
| 272 | > | /* compute minimum BSDF */ | 
| 273 | > | comp_bsdf_min(); | 
| 274 | > | /* create RBF node list */ | 
| 275 | > | rbfarr = NULL; nn = 0; | 
| 276 | > | if (build_rbfrep(&rbfarr, &nn, 0, GRIDRES, 0, GRIDRES) <= 0) { | 
| 277 | > | if (nn) | 
| 278 | > | goto memerr; | 
| 279 | > | fprintf(stderr, | 
| 280 | > | "%s: warning - skipping bad incidence (%.1f,%.1f)\n", | 
| 281 | > | progname, theta_in_deg, phi_in_deg); | 
| 282 | > | return(NULL); | 
| 283 | > | } | 
| 284 | > | /* (re)allocate RBF array */ | 
| 285 | > | newnode = (RBFNODE *)realloc(rbfarr, | 
| 286 | > | sizeof(RBFNODE) + sizeof(RBFVAL)*(nn-1)); | 
| 287 |  | if (newnode == NULL) | 
| 288 |  | goto memerr; | 
| 289 | + | /* copy computed lobes into RBF node */ | 
| 290 | + | memmove(newnode->rbfa, newnode, sizeof(RBFVAL)*nn); | 
| 291 |  | newnode->ord = -1; | 
| 292 |  | newnode->next = NULL; | 
| 293 |  | newnode->ejl = NULL; | 
| 295 |  | newnode->invec[0] = cos((M_PI/180.)*phi_in_deg)*newnode->invec[2]; | 
| 296 |  | newnode->invec[1] = sin((M_PI/180.)*phi_in_deg)*newnode->invec[2]; | 
| 297 |  | newnode->invec[2] = input_orient*sqrt(1. - newnode->invec[2]*newnode->invec[2]); | 
| 298 | < | newnode->vtotal = 0; | 
| 298 | > | newnode->vtotal = .0; | 
| 299 |  | newnode->nrbf = nn; | 
| 300 | < | nn = 0;                 /* fill RBF array */ | 
| 301 | < | for (i = 0; i < GRIDRES; i++) | 
| 302 | < | for (j = 0; j < GRIDRES; j++) | 
| 226 | < | if (dsf_grid[i][j].nval) { | 
| 227 | < | newnode->rbfa[nn].peak = dsf_grid[i][j].vsum; | 
| 228 | < | newnode->rbfa[nn].crad = RSCA*dsf_grid[i][j].crad + .5; | 
| 229 | < | newnode->rbfa[nn].gx = i; | 
| 230 | < | newnode->rbfa[nn].gy = j; | 
| 231 | < | ++nn; | 
| 232 | < | } | 
| 233 | < | /* iterate to improve interpolation accuracy */ | 
| 234 | < | itera = (RBFVAL *)malloc(sizeof(RBFVAL)*newnode->nrbf); | 
| 235 | < | if (itera == NULL) | 
| 236 | < | goto memerr; | 
| 237 | < | memcpy(itera, newnode->rbfa, sizeof(RBFVAL)*newnode->nrbf); | 
| 238 | < | do { | 
| 239 | < | double  dsum = 0, dsum2 = 0; | 
| 240 | < | nn = 0; | 
| 241 | < | for (i = 0; i < GRIDRES; i++) | 
| 242 | < | for (j = 0; j < GRIDRES; j++) | 
| 243 | < | if (dsf_grid[i][j].nval) { | 
| 244 | < | FVECT   odir; | 
| 245 | < | double  corr; | 
| 246 | < | ovec_from_pos(odir, i, j); | 
| 247 | < | itera[nn++].peak *= corr = | 
| 248 | < | dsf_grid[i][j].vsum / | 
| 249 | < | eval_rbfrep(newnode, odir); | 
| 250 | < | dsum += 1. - corr; | 
| 251 | < | dsum2 += (1.-corr)*(1.-corr); | 
| 252 | < | } | 
| 253 | < | memcpy(newnode->rbfa, itera, sizeof(RBFVAL)*newnode->nrbf); | 
| 254 | < | lastVar = thisVar; | 
| 255 | < | thisVar = dsum2/(double)nn; | 
| 300 | > | /* compute sum for normalization */ | 
| 301 | > | while (nn-- > 0) | 
| 302 | > | newnode->vtotal += rbf_volume(&newnode->rbfa[nn]); | 
| 303 |  | #ifdef DEBUG | 
| 304 | < | fprintf(stderr, "Avg., RMS error: %.1f%%  %.1f%%\n", | 
| 258 | < | 100.*dsum/(double)nn, | 
| 259 | < | 100.*sqrt(thisVar)); | 
| 260 | < | #endif | 
| 261 | < | } while (--niter > 0 && lastVar-thisVar > 0.02*lastVar); | 
| 262 | < |  | 
| 263 | < | free(itera); | 
| 264 | < | nn = 0;                 /* compute sum for normalization */ | 
| 265 | < | while (nn < newnode->nrbf) | 
| 266 | < | newnode->vtotal += rbf_volume(&newnode->rbfa[nn++]); | 
| 267 | < | #ifdef DEBUG | 
| 304 | > | fprintf(stderr, "Built RBF with %d lobes\n", newnode->nrbf); | 
| 305 |  | fprintf(stderr, "Integrated DSF at (%.1f,%.1f) deg. is %.2f\n", | 
| 306 |  | get_theta180(newnode->invec), get_phi360(newnode->invec), | 
| 307 |  | newnode->vtotal); | 
| 308 |  | #endif | 
| 309 |  | insert_dsf(newnode); | 
| 273 | – |  | 
| 310 |  | return(newnode); | 
| 311 |  | memerr: | 
| 312 |  | fprintf(stderr, "%s: Out of memory in make_rbfrep()\n", progname); |