| 1 | greg | 2.1 | #ifndef lint | 
| 2 | greg | 2.28 | static const char RCSid[] = "$Id: bsdfrbf.c,v 2.27 2016/01/29 16:21:55 greg Exp $"; | 
| 3 | greg | 2.1 | #endif | 
| 4 |  |  | /* | 
| 5 |  |  | * Radial basis function representation for BSDF data. | 
| 6 |  |  | * | 
| 7 |  |  | *      G. Ward | 
| 8 |  |  | */ | 
| 9 |  |  |  | 
| 10 | greg | 2.13 | /**************************************************************** | 
| 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 | greg | 2.1 | #define _USE_MATH_DEFINES | 
| 25 |  |  | #include <stdio.h> | 
| 26 |  |  | #include <stdlib.h> | 
| 27 |  |  | #include <string.h> | 
| 28 |  |  | #include <math.h> | 
| 29 |  |  | #include "bsdfrep.h" | 
| 30 |  |  |  | 
| 31 | greg | 2.12 | #ifndef RSCA | 
| 32 | greg | 2.25 | #define RSCA            2.0             /* radius scaling factor (empirical) */ | 
| 33 | greg | 2.9 | #endif | 
| 34 | greg | 2.12 | #ifndef SMOOTH_MSE | 
| 35 | greg | 2.19 | #define SMOOTH_MSE      5e-5            /* acceptable mean squared error */ | 
| 36 | greg | 2.1 | #endif | 
| 37 | greg | 2.12 | #ifndef SMOOTH_MSER | 
| 38 | greg | 2.18 | #define SMOOTH_MSER     0.03            /* acceptable relative MSE */ | 
| 39 | greg | 2.7 | #endif | 
| 40 | greg | 2.12 | #define MAX_RAD         (GRIDRES/8)     /* maximum lobe radius */ | 
| 41 |  |  |  | 
| 42 |  |  | #define RBFALLOCB       10              /* RBF allocation block size */ | 
| 43 |  |  |  | 
| 44 | greg | 2.25 | /* loaded grid or comparison DSFs */ | 
| 45 | greg | 2.1 | GRIDVAL                 dsf_grid[GRIDRES][GRIDRES]; | 
| 46 | greg | 2.27 | /* allocated chrominance sums if any */ | 
| 47 |  |  | float                   (*spec_grid)[GRIDRES][GRIDRES]; | 
| 48 |  |  | int                     nspec_grid = 0; | 
| 49 |  |  |  | 
| 50 |  |  | /* Set up visible spectrum sampling */ | 
| 51 |  |  | void | 
| 52 |  |  | set_spectral_samples(int nspec) | 
| 53 |  |  | { | 
| 54 |  |  | if (rbf_colorimetry == RBCunknown) { | 
| 55 |  |  | if (nspec_grid > 0) { | 
| 56 |  |  | free(spec_grid); | 
| 57 |  |  | spec_grid = NULL; | 
| 58 |  |  | nspec_grid = 0; | 
| 59 |  |  | } | 
| 60 |  |  | if (nspec == 1) { | 
| 61 |  |  | rbf_colorimetry = RBCphotopic; | 
| 62 |  |  | return; | 
| 63 |  |  | } | 
| 64 |  |  | if (nspec == 3) { | 
| 65 |  |  | rbf_colorimetry = RBCtristimulus; | 
| 66 |  |  | spec_grid = (float (*)[GRIDRES][GRIDRES])calloc( | 
| 67 |  |  | 2*GRIDRES*GRIDRES, sizeof(float) ); | 
| 68 |  |  | if (spec_grid == NULL) | 
| 69 |  |  | goto mem_error; | 
| 70 |  |  | nspec_grid = 2; | 
| 71 |  |  | return; | 
| 72 |  |  | } | 
| 73 |  |  | fprintf(stderr, | 
| 74 |  |  | "%s: only 1 or 3 spectral samples currently supported\n", | 
| 75 |  |  | progname); | 
| 76 |  |  | exit(1); | 
| 77 |  |  | } | 
| 78 |  |  | if (nspec != nspec_grid+1) { | 
| 79 |  |  | fprintf(stderr, | 
| 80 |  |  | "%s: number of spectral samples cannot be changed\n", | 
| 81 |  |  | progname); | 
| 82 |  |  | exit(1); | 
| 83 |  |  | } | 
| 84 |  |  | return; | 
| 85 |  |  | mem_error: | 
| 86 |  |  | fprintf(stderr, "%s: out of memory in set_spectral_samples()\n", | 
| 87 |  |  | progname); | 
| 88 |  |  | exit(1); | 
| 89 |  |  | } | 
| 90 | greg | 2.1 |  | 
| 91 |  |  | /* Start new DSF input grid */ | 
| 92 |  |  | void | 
| 93 |  |  | new_bsdf_data(double new_theta, double new_phi) | 
| 94 |  |  | { | 
| 95 |  |  | if (!new_input_direction(new_theta, new_phi)) | 
| 96 |  |  | exit(1); | 
| 97 |  |  | memset(dsf_grid, 0, sizeof(dsf_grid)); | 
| 98 | greg | 2.27 | if (nspec_grid > 0) | 
| 99 |  |  | memset(spec_grid, 0, sizeof(float)*GRIDRES*GRIDRES*nspec_grid); | 
| 100 | greg | 2.1 | } | 
| 101 |  |  |  | 
| 102 |  |  | /* Add BSDF data point */ | 
| 103 |  |  | void | 
| 104 | greg | 2.27 | add_bsdf_data(double theta_out, double phi_out, const double val[], int isDSF) | 
| 105 | greg | 2.1 | { | 
| 106 |  |  | FVECT   ovec; | 
| 107 | greg | 2.27 | double  cfact, Yval; | 
| 108 | greg | 2.1 | int     pos[2]; | 
| 109 |  |  |  | 
| 110 | greg | 2.27 | if (nspec_grid > 2) { | 
| 111 |  |  | fprintf(stderr, "%s: unsupported color space\n", progname); | 
| 112 |  |  | exit(1); | 
| 113 |  |  | } | 
| 114 | greg | 2.1 | if (!output_orient)             /* check output orientation */ | 
| 115 |  |  | output_orient = 1 - 2*(theta_out > 90.); | 
| 116 |  |  | else if (output_orient > 0 ^ theta_out < 90.) { | 
| 117 | greg | 2.27 | fprintf(stderr, | 
| 118 |  |  | "%s: cannot handle output angles on both sides of surface\n", | 
| 119 |  |  | progname); | 
| 120 | greg | 2.1 | exit(1); | 
| 121 |  |  | } | 
| 122 |  |  | ovec[2] = sin((M_PI/180.)*theta_out); | 
| 123 |  |  | ovec[0] = cos((M_PI/180.)*phi_out) * ovec[2]; | 
| 124 |  |  | ovec[1] = sin((M_PI/180.)*phi_out) * ovec[2]; | 
| 125 |  |  | ovec[2] = sqrt(1. - ovec[2]*ovec[2]); | 
| 126 | greg | 2.27 | /* BSDF to DSF correction */ | 
| 127 |  |  | cfact = isDSF ? 1. : ovec[2]; | 
| 128 | greg | 2.1 |  | 
| 129 | greg | 2.27 | Yval = cfact * val[rbf_colorimetry==RBCtristimulus]; | 
| 130 | greg | 2.4 | /* update BSDF histogram */ | 
| 131 | greg | 2.27 | if (BSDF2SML*ovec[2] < Yval && Yval < BSDF2BIG*ovec[2]) | 
| 132 |  |  | ++bsdf_hist[histndx(Yval/ovec[2])]; | 
| 133 | greg | 2.4 |  | 
| 134 | greg | 2.1 | pos_from_vec(pos, ovec); | 
| 135 |  |  |  | 
| 136 | greg | 2.27 | dsf_grid[pos[0]][pos[1]].sum.v += Yval; | 
| 137 | greg | 2.20 | dsf_grid[pos[0]][pos[1]].sum.n++; | 
| 138 | greg | 2.27 | /* add in X and Z values */ | 
| 139 |  |  | if (rbf_colorimetry == RBCtristimulus) { | 
| 140 | greg | 2.28 | spec_grid[0][pos[0]][pos[1]] += cfact * val[0]; | 
| 141 |  |  | spec_grid[1][pos[0]][pos[1]] += cfact * val[2]; | 
| 142 | greg | 2.27 | } | 
| 143 | greg | 2.1 | } | 
| 144 |  |  |  | 
| 145 | greg | 2.11 | /* Compute minimum BSDF from histogram (does not clear) */ | 
| 146 | greg | 2.5 | static void | 
| 147 |  |  | comp_bsdf_min() | 
| 148 |  |  | { | 
| 149 | greg | 2.17 | unsigned long   cnt, target; | 
| 150 |  |  | int             i; | 
| 151 | greg | 2.5 |  | 
| 152 |  |  | cnt = 0; | 
| 153 |  |  | for (i = HISTLEN; i--; ) | 
| 154 |  |  | cnt += bsdf_hist[i]; | 
| 155 |  |  | if (!cnt) {                             /* shouldn't happen */ | 
| 156 |  |  | bsdf_min = 0; | 
| 157 |  |  | return; | 
| 158 |  |  | } | 
| 159 |  |  | target = cnt/100;                       /* ignore bottom 1% */ | 
| 160 |  |  | cnt = 0; | 
| 161 |  |  | for (i = 0; cnt <= target; i++) | 
| 162 |  |  | cnt += bsdf_hist[i]; | 
| 163 |  |  | bsdf_min = histval(i-1); | 
| 164 |  |  | } | 
| 165 |  |  |  | 
| 166 | greg | 2.12 | /* Determine if the given region is empty of grid samples */ | 
| 167 | greg | 2.6 | static int | 
| 168 | greg | 2.12 | empty_region(int x0, int x1, int y0, int y1) | 
| 169 | greg | 2.6 | { | 
| 170 | greg | 2.12 | int     x, y; | 
| 171 |  |  |  | 
| 172 |  |  | for (x = x0; x < x1; x++) | 
| 173 |  |  | for (y = y0; y < y1; y++) | 
| 174 | greg | 2.20 | if (dsf_grid[x][y].sum.n) | 
| 175 | greg | 2.12 | return(0); | 
| 176 |  |  | return(1); | 
| 177 |  |  | } | 
| 178 |  |  |  | 
| 179 |  |  | /* Determine if the given region is smooth enough to be a single lobe */ | 
| 180 |  |  | static int | 
| 181 |  |  | smooth_region(int x0, int x1, int y0, int y1) | 
| 182 |  |  | { | 
| 183 |  |  | RREAL   rMtx[3][3]; | 
| 184 |  |  | FVECT   xvec; | 
| 185 |  |  | double  A, B, C, nvs, sqerr; | 
| 186 |  |  | int     x, y, n; | 
| 187 |  |  | /* compute planar regression */ | 
| 188 |  |  | memset(rMtx, 0, sizeof(rMtx)); | 
| 189 |  |  | memset(xvec, 0, sizeof(xvec)); | 
| 190 |  |  | for (x = x0; x < x1; x++) | 
| 191 |  |  | for (y = y0; y < y1; y++) | 
| 192 | greg | 2.20 | if ((n = dsf_grid[x][y].sum.n) > 0) { | 
| 193 |  |  | double  z = dsf_grid[x][y].sum.v; | 
| 194 | greg | 2.13 | rMtx[0][0] += x*x*(double)n; | 
| 195 |  |  | rMtx[0][1] += x*y*(double)n; | 
| 196 |  |  | rMtx[0][2] += x*(double)n; | 
| 197 |  |  | rMtx[1][1] += y*y*(double)n; | 
| 198 |  |  | rMtx[1][2] += y*(double)n; | 
| 199 |  |  | rMtx[2][2] += (double)n; | 
| 200 | greg | 2.12 | xvec[0] += x*z; | 
| 201 |  |  | xvec[1] += y*z; | 
| 202 |  |  | xvec[2] += z; | 
| 203 |  |  | } | 
| 204 |  |  | rMtx[1][0] = rMtx[0][1]; | 
| 205 | greg | 2.15 | rMtx[2][0] = rMtx[0][2]; | 
| 206 | greg | 2.12 | rMtx[2][1] = rMtx[1][2]; | 
| 207 |  |  | nvs = rMtx[2][2]; | 
| 208 |  |  | if (SDinvXform(rMtx, rMtx) != SDEnone) | 
| 209 | greg | 2.16 | return(1);              /* colinear values */ | 
| 210 | greg | 2.12 | A = DOT(rMtx[0], xvec); | 
| 211 |  |  | B = DOT(rMtx[1], xvec); | 
| 212 |  |  | C = DOT(rMtx[2], xvec); | 
| 213 |  |  | sqerr = 0.0;                    /* compute mean squared error */ | 
| 214 |  |  | for (x = x0; x < x1; x++) | 
| 215 |  |  | for (y = y0; y < y1; y++) | 
| 216 | greg | 2.20 | if ((n = dsf_grid[x][y].sum.n) > 0) { | 
| 217 |  |  | double  d = A*x + B*y + C - dsf_grid[x][y].sum.v/n; | 
| 218 | greg | 2.12 | sqerr += n*d*d; | 
| 219 | greg | 2.6 | } | 
| 220 | greg | 2.12 | if (sqerr <= nvs*SMOOTH_MSE)    /* below absolute MSE threshold? */ | 
| 221 |  |  | return(1); | 
| 222 | greg | 2.13 | /* OR below relative MSE threshold? */ | 
| 223 | greg | 2.12 | return(sqerr*nvs <= xvec[2]*xvec[2]*SMOOTH_MSER); | 
| 224 |  |  | } | 
| 225 |  |  |  | 
| 226 |  |  | /* Create new lobe based on integrated samples in region */ | 
| 227 | greg | 2.21 | static int | 
| 228 | greg | 2.12 | create_lobe(RBFVAL *rvp, int x0, int x1, int y0, int y1) | 
| 229 |  |  | { | 
| 230 |  |  | double  vtot = 0.0; | 
| 231 | greg | 2.27 | double  CIEXtot = 0.0, CIEZtot = 0.0; | 
| 232 | greg | 2.12 | int     nv = 0; | 
| 233 | greg | 2.25 | double  wxsum = 0.0, wysum = 0.0, wtsum = 0.0; | 
| 234 | greg | 2.12 | double  rad; | 
| 235 |  |  | int     x, y; | 
| 236 |  |  | /* compute average for region */ | 
| 237 |  |  | for (x = x0; x < x1; x++) | 
| 238 | greg | 2.25 | for (y = y0; y < y1; y++) | 
| 239 |  |  | if (dsf_grid[x][y].sum.n) { | 
| 240 |  |  | const double        v = dsf_grid[x][y].sum.v; | 
| 241 |  |  | const int           n = dsf_grid[x][y].sum.n; | 
| 242 |  |  |  | 
| 243 |  |  | if (v > 0) { | 
| 244 | greg | 2.27 | const double    wt = v / (double)n; | 
| 245 | greg | 2.25 | wxsum += wt * x; | 
| 246 |  |  | wysum += wt * y; | 
| 247 |  |  | wtsum += wt; | 
| 248 |  |  | } | 
| 249 |  |  | vtot += v; | 
| 250 |  |  | nv += n; | 
| 251 | greg | 2.27 | if (rbf_colorimetry == RBCtristimulus) { | 
| 252 |  |  | CIEXtot += spec_grid[0][x][y]; | 
| 253 |  |  | CIEZtot += spec_grid[1][x][y]; | 
| 254 |  |  | } | 
| 255 | greg | 2.25 | } | 
| 256 | greg | 2.12 | if (!nv) { | 
| 257 |  |  | fprintf(stderr, "%s: internal - missing samples in create_lobe\n", | 
| 258 |  |  | progname); | 
| 259 |  |  | exit(1); | 
| 260 | greg | 2.6 | } | 
| 261 | greg | 2.21 | if (vtot <= 0)                  /* only create positive lobes */ | 
| 262 |  |  | return(0); | 
| 263 | greg | 2.27 | /* assign color */ | 
| 264 |  |  | if (rbf_colorimetry == RBCtristimulus) { | 
| 265 |  |  | const double    df = 1.0 / (CIEXtot + vtot + CIEZtot); | 
| 266 |  |  | C_COLOR         cclr; | 
| 267 |  |  | c_cset(&cclr, CIEXtot*df, vtot*df); | 
| 268 |  |  | rvp->chroma = c_encodeChroma(&cclr); | 
| 269 |  |  | } else | 
| 270 |  |  | rvp->chroma = c_dfchroma; | 
| 271 | greg | 2.12 | /* peak value based on integral */ | 
| 272 |  |  | vtot *= (x1-x0)*(y1-y0)*(2.*M_PI/GRIDRES/GRIDRES)/(double)nv; | 
| 273 |  |  | rad = (RSCA/(double)GRIDRES)*(x1-x0); | 
| 274 |  |  | rvp->peak =  vtot / ((2.*M_PI) * rad*rad); | 
| 275 | greg | 2.25 | rvp->crad = ANG2R(rad);         /* put peak at centroid */ | 
| 276 |  |  | rvp->gx = (int)(wxsum/wtsum + .5); | 
| 277 |  |  | rvp->gy = (int)(wysum/wtsum + .5); | 
| 278 | greg | 2.21 | return(1); | 
| 279 | greg | 2.6 | } | 
| 280 |  |  |  | 
| 281 | greg | 2.12 | /* Recursive function to build radial basis function representation */ | 
| 282 | greg | 2.6 | static int | 
| 283 | greg | 2.12 | build_rbfrep(RBFVAL **arp, int *np, int x0, int x1, int y0, int y1) | 
| 284 | greg | 2.6 | { | 
| 285 | greg | 2.12 | int     xmid = (x0+x1)>>1; | 
| 286 |  |  | int     ymid = (y0+y1)>>1; | 
| 287 |  |  | int     branched[4]; | 
| 288 |  |  | int     nadded, nleaves; | 
| 289 |  |  | /* need to make this a leaf? */ | 
| 290 |  |  | if (empty_region(x0, xmid, y0, ymid) || | 
| 291 |  |  | empty_region(xmid, x1, y0, ymid) || | 
| 292 |  |  | empty_region(x0, xmid, ymid, y1) || | 
| 293 |  |  | empty_region(xmid, x1, ymid, y1)) | 
| 294 |  |  | return(0); | 
| 295 |  |  | /* add children (branches+leaves) */ | 
| 296 |  |  | if ((branched[0] = build_rbfrep(arp, np, x0, xmid, y0, ymid)) < 0) | 
| 297 |  |  | return(-1); | 
| 298 |  |  | if ((branched[1] = build_rbfrep(arp, np, xmid, x1, y0, ymid)) < 0) | 
| 299 |  |  | return(-1); | 
| 300 |  |  | if ((branched[2] = build_rbfrep(arp, np, x0, xmid, ymid, y1)) < 0) | 
| 301 |  |  | return(-1); | 
| 302 |  |  | if ((branched[3] = build_rbfrep(arp, np, xmid, x1, ymid, y1)) < 0) | 
| 303 |  |  | return(-1); | 
| 304 |  |  | nadded = branched[0] + branched[1] + branched[2] + branched[3]; | 
| 305 |  |  | nleaves = !branched[0] + !branched[1] + !branched[2] + !branched[3]; | 
| 306 |  |  | if (!nleaves)                   /* nothing but branches? */ | 
| 307 |  |  | return(nadded); | 
| 308 |  |  | /* combine 4 leaves into 1? */ | 
| 309 | greg | 2.14 | if ((nleaves == 4) & (x1-x0 <= MAX_RAD) && | 
| 310 |  |  | smooth_region(x0, x1, y0, y1)) | 
| 311 | greg | 2.12 | return(0); | 
| 312 |  |  | /* need more array space? */ | 
| 313 |  |  | if ((*np+nleaves-1)>>RBFALLOCB != (*np-1)>>RBFALLOCB) { | 
| 314 |  |  | *arp = (RBFVAL *)realloc(*arp, | 
| 315 |  |  | sizeof(RBFVAL)*(*np+nleaves-1+(1<<RBFALLOCB))); | 
| 316 |  |  | if (*arp == NULL) | 
| 317 |  |  | return(-1); | 
| 318 | greg | 2.6 | } | 
| 319 | greg | 2.12 | /* create lobes for leaves */ | 
| 320 | greg | 2.21 | if (!branched[0] && create_lobe(*arp+*np, x0, xmid, y0, ymid)) { | 
| 321 |  |  | ++(*np); ++nadded; | 
| 322 |  |  | } | 
| 323 |  |  | if (!branched[1] && create_lobe(*arp+*np, xmid, x1, y0, ymid)) { | 
| 324 |  |  | ++(*np); ++nadded; | 
| 325 |  |  | } | 
| 326 |  |  | if (!branched[2] && create_lobe(*arp+*np, x0, xmid, ymid, y1)) { | 
| 327 |  |  | ++(*np); ++nadded; | 
| 328 |  |  | } | 
| 329 |  |  | if (!branched[3] && create_lobe(*arp+*np, xmid, x1, ymid, y1)) { | 
| 330 |  |  | ++(*np); ++nadded; | 
| 331 |  |  | } | 
| 332 | greg | 2.12 | return(nadded); | 
| 333 | greg | 2.6 | } | 
| 334 |  |  |  | 
| 335 | greg | 2.1 | /* Count up filled nodes and build RBF representation from current grid */ | 
| 336 |  |  | RBFNODE * | 
| 337 | greg | 2.12 | make_rbfrep() | 
| 338 | greg | 2.1 | { | 
| 339 | greg | 2.12 | RBFNODE *newnode; | 
| 340 |  |  | RBFVAL  *rbfarr; | 
| 341 | greg | 2.1 | int     nn; | 
| 342 | greg | 2.5 | /* compute minimum BSDF */ | 
| 343 |  |  | comp_bsdf_min(); | 
| 344 | greg | 2.12 | /* create RBF node list */ | 
| 345 |  |  | rbfarr = NULL; nn = 0; | 
| 346 | greg | 2.22 | if (build_rbfrep(&rbfarr, &nn, 0, GRIDRES, 0, GRIDRES) <= 0) { | 
| 347 |  |  | if (nn) | 
| 348 |  |  | goto memerr; | 
| 349 | greg | 2.24 | fprintf(stderr, | 
| 350 |  |  | "%s: warning - skipping bad incidence (%.1f,%.1f)\n", | 
| 351 |  |  | progname, theta_in_deg, phi_in_deg); | 
| 352 |  |  | return(NULL); | 
| 353 | greg | 2.22 | } | 
| 354 | greg | 2.12 | /* (re)allocate RBF array */ | 
| 355 |  |  | newnode = (RBFNODE *)realloc(rbfarr, | 
| 356 |  |  | sizeof(RBFNODE) + sizeof(RBFVAL)*(nn-1)); | 
| 357 | greg | 2.2 | if (newnode == NULL) | 
| 358 |  |  | goto memerr; | 
| 359 | greg | 2.12 | /* copy computed lobes into RBF node */ | 
| 360 |  |  | memmove(newnode->rbfa, newnode, sizeof(RBFVAL)*nn); | 
| 361 | greg | 2.1 | newnode->ord = -1; | 
| 362 |  |  | newnode->next = NULL; | 
| 363 |  |  | newnode->ejl = NULL; | 
| 364 |  |  | newnode->invec[2] = sin((M_PI/180.)*theta_in_deg); | 
| 365 |  |  | newnode->invec[0] = cos((M_PI/180.)*phi_in_deg)*newnode->invec[2]; | 
| 366 |  |  | newnode->invec[1] = sin((M_PI/180.)*phi_in_deg)*newnode->invec[2]; | 
| 367 |  |  | newnode->invec[2] = input_orient*sqrt(1. - newnode->invec[2]*newnode->invec[2]); | 
| 368 | greg | 2.12 | newnode->vtotal = .0; | 
| 369 | greg | 2.1 | newnode->nrbf = nn; | 
| 370 | greg | 2.12 | /* compute sum for normalization */ | 
| 371 |  |  | while (nn-- > 0) | 
| 372 |  |  | newnode->vtotal += rbf_volume(&newnode->rbfa[nn]); | 
| 373 | greg | 2.3 | #ifdef DEBUG | 
| 374 | greg | 2.12 | fprintf(stderr, "Built RBF with %d lobes\n", newnode->nrbf); | 
| 375 | greg | 2.3 | fprintf(stderr, "Integrated DSF at (%.1f,%.1f) deg. is %.2f\n", | 
| 376 |  |  | get_theta180(newnode->invec), get_phi360(newnode->invec), | 
| 377 |  |  | newnode->vtotal); | 
| 378 |  |  | #endif | 
| 379 | greg | 2.1 | insert_dsf(newnode); | 
| 380 |  |  | return(newnode); | 
| 381 | greg | 2.2 | memerr: | 
| 382 |  |  | fprintf(stderr, "%s: Out of memory in make_rbfrep()\n", progname); | 
| 383 |  |  | exit(1); | 
| 384 | greg | 2.1 | } |