Back to index

radiance  4R0+20100331
Classes | Defines | Functions | Variables
bsdf.c File Reference
#include "standard.h"
#include "bsdf.h"
#include "paths.h"
#include "ezxml.h"
#include <ctype.h>

Go to the source code of this file.

Classes

struct  ANGLE_BASIS
struct  ANGLE_BASIS.lat

Defines

#define MAXLATS   46 /* maximum number of latitudes */
#define MAXABASES   3 /* limit on defined bases */
#define FEQ(a, b)   ((a)-(b) <= 1e-7 && (b)-(a) <= 1e-7)

Functions

static int ab_getvec (FVECT v, int ndx, void *p)
static int ab_getndx (FVECT v, void *p)
static double ab_getohm (int ndx, void *p)
static int ab_getvecR (FVECT v, int ndx, void *p)
static int ab_getndxR (FVECT v, void *p)
static void load_bsdf_data (struct BSDF_data *dp, ezxml_t wdb)
static int check_bsdf_data (struct BSDF_data *dp)
struct BSDF_dataload_BSDF (char *fname)
void free_BSDF (struct BSDF_data *b)
int r_BSDF_incvec (FVECT v, struct BSDF_data *b, int i, double rv, MAT4 xm)
int r_BSDF_outvec (FVECT v, struct BSDF_data *b, int o, double rv, MAT4 xm)
static int addrot (char *xfarg[], FVECT xp, FVECT yp, FVECT zp)
int getBSDF_xfm (MAT4 xm, FVECT nrm, UpDir ud)

Variables

static const char RCSid [] = "$Id: bsdf.c,v 2.2 2009/06/19 06:49:25 greg Exp $"
static ANGLE_BASIS abase_list [MAXABASES]
static int nabases = 3

Class Documentation

struct ANGLE_BASIS

Definition at line 17 of file bsdf.c.

Class Members
struct ANGLE_BASIS lat
char name
int nangles
struct ANGLE_BASIS.lat

Definition at line 20 of file bsdf.c.

Class Members
short nphis
float tmin

Define Documentation

#define FEQ (   a,
 
)    ((a)-(b) <= 1e-7 && (b)-(a) <= 1e-7)

Definition at line 478 of file bsdf.c.

#define MAXABASES   3 /* limit on defined bases */

Definition at line 26 of file bsdf.c.

#define MAXLATS   46 /* maximum number of latitudes */

Definition at line 14 of file bsdf.c.


Function Documentation

static int ab_getndx ( FVECT  v,
void *  p 
) [static]

Definition at line 91 of file bsdf.c.

{
       ANGLE_BASIS  *ab = (ANGLE_BASIS *)p;
       int    li, ndx;
       double pol, azi, d;

       if ((v[2] < -1.0) | (v[2] > 1.0))
              return(-1);
       pol = 180.0/PI*acos(v[2]);
       azi = 180.0/PI*atan2(v[1], v[0]);
       if (azi < 0.0) azi += 360.0;
       for (li = 1; ab->lat[li].tmin <= pol; li++)
              if (!ab->lat[li].nphis)
                     return(-1);
       --li;
       ndx = (int)((1./360.)*azi*ab->lat[li].nphis + 0.5);
       if (ndx >= ab->lat[li].nphis) ndx = 0;
       while (li--)
              ndx += ab->lat[li].nphis;
       return(ndx);
}

Here is the caller graph for this function:

static int ab_getndxR ( FVECT  v,
void *  p 
) [static]

Definition at line 161 of file bsdf.c.

{
       FVECT  v2;
       
       v2[0] = -v[0];
       v2[1] = -v[1];
       v2[2] = -v[2];

       return ab_getndx(v2, p);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static double ab_getohm ( int  ndx,
void *  p 
) [static]

Definition at line 118 of file bsdf.c.

{
       ANGLE_BASIS  *ab = (ANGLE_BASIS *)p;
       int    li;
       double theta, theta1;
       
       if ((ndx < 0) | (ndx >= ab->nangles))
              return(0);
       for (li = 0; ndx >= ab->lat[li].nphis; li++)
              ndx -= ab->lat[li].nphis;
       theta1 = PI/180. * ab->lat[li+1].tmin;
       if (ab->lat[li].nphis == 1) {             /* special case */
              if (ab->lat[li].tmin > FTINY)
                     error(USER, "unsupported BSDF coordinate system");
              return(2.*PI*(1. - cos(theta1)));
       }
       theta = PI/180. * ab->lat[li].tmin;
       return(2.*PI*(cos(theta) - cos(theta1))/(double)ab->lat[li].nphis);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int ab_getvec ( FVECT  v,
int  ndx,
void *  p 
) [static]

Definition at line 66 of file bsdf.c.

{
       ANGLE_BASIS  *ab = (ANGLE_BASIS *)p;
       int    li;
       double pol, azi, d;
       
       if ((ndx < 0) | (ndx >= ab->nangles))
              return(0);
       for (li = 0; ndx >= ab->lat[li].nphis; li++)
              ndx -= ab->lat[li].nphis;
       pol = PI/180.*0.5*(ab->lat[li].tmin + ab->lat[li+1].tmin);
       azi = 2.*PI*ndx/ab->lat[li].nphis;
       v[2] = d = cos(pol);
       d = sqrt(1. - d*d);  /* sin(pol) */
       v[0] = cos(azi)*d;
       v[1] = sin(azi)*d;
       return(1);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int ab_getvecR ( FVECT  v,
int  ndx,
void *  p 
) [static]

Definition at line 143 of file bsdf.c.

{
       if (!ab_getvec(v, ndx, p))
              return(0);

       v[0] = -v[0];
       v[1] = -v[1];
       v[2] = -v[2];

       return(1);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int addrot ( char *  xfarg[],
FVECT  xp,
FVECT  yp,
FVECT  zp 
) [static]

Definition at line 481 of file bsdf.c.

{
       static char   bufs[3][16];
       int    bn = 0;
       char   **xfp = xfarg;
       double theta;

       if (yp[2]*yp[2] + zp[2]*zp[2] < 2.*FTINY*FTINY) {
              /* Special case for X' along Z-axis */
              theta = -atan2(yp[0], yp[1]);
              *xfp++ = "-ry";
              *xfp++ = xp[2] < 0.0 ? "90" : "-90";
              *xfp++ = "-rz";
              sprintf(bufs[bn], "%f", theta*(180./PI));
              *xfp++ = bufs[bn++];
              return(xfp - xfarg);
       }
       theta = atan2(yp[2], zp[2]);
       if (!FEQ(theta,0.0)) {
              *xfp++ = "-rx";
              sprintf(bufs[bn], "%f", theta*(180./PI));
              *xfp++ = bufs[bn++];
       }
       theta = asin(-xp[2]);
       if (!FEQ(theta,0.0)) {
              *xfp++ = "-ry";
              sprintf(bufs[bn], " %f", theta*(180./PI));
              *xfp++ = bufs[bn++];
       }
       theta = atan2(xp[1], xp[0]);
       if (!FEQ(theta,0.0)) {
              *xfp++ = "-rz";
              sprintf(bufs[bn], "%f", theta*(180./PI));
              *xfp++ = bufs[bn++];
       }
       *xfp = NULL;
       return(xfp - xfarg);
}

Here is the caller graph for this function:

static int check_bsdf_data ( struct BSDF_data dp) [static]

Definition at line 253 of file bsdf.c.

{
       double        *omega_iarr, *omega_oarr;
       double        dom, contrib, hemi_total;
       int           nneg;
       FVECT         v;
       int           i, o;

       if (dp == NULL || dp->bsdf == NULL)
              return(0);
       omega_iarr = (double *)calloc(dp->ninc, sizeof(double));
       omega_oarr = (double *)calloc(dp->nout, sizeof(double));
       if ((omega_iarr == NULL) | (omega_oarr == NULL))
              error(SYSTEM, "out of memory in check_bsdf_data");
                                   /* incoming projected solid angles */
       hemi_total = .0;
       for (i = dp->ninc; i--; ) {
              dom = getBSDF_incohm(dp,i);
              if (dom <= .0) {
                     error(WARNING, "zero/negative incoming solid angle");
                     continue;
              }
              if (!getBSDF_incvec(v,dp,i) || v[2] > FTINY) {
                     error(WARNING, "illegal incoming BSDF direction");
                     free(omega_iarr); free(omega_oarr);
                     return(0);
              }
              hemi_total += omega_iarr[i] = dom * -v[2];
       }
       if ((hemi_total > 1.02*PI) | (hemi_total < 0.98*PI)) {
              sprintf(errmsg, "incoming BSDF hemisphere off by %.1f%%",
                            100.*(hemi_total/PI - 1.));
              error(WARNING, errmsg);
       }
       dom = PI / hemi_total;             /* fix normalization */
       for (i = dp->ninc; i--; )
              omega_iarr[i] *= dom;
                                   /* outgoing projected solid angles */
       hemi_total = .0;
       for (o = dp->nout; o--; ) {
              dom = getBSDF_outohm(dp,o);
              if (dom <= .0) {
                     error(WARNING, "zero/negative outgoing solid angle");
                     continue;
              }
              if (!getBSDF_outvec(v,dp,o) || v[2] < -FTINY) {
                     error(WARNING, "illegal outgoing BSDF direction");
                     free(omega_iarr); free(omega_oarr);
                     return(0);
              }
              hemi_total += omega_oarr[o] = dom * v[2];
       }
       if ((hemi_total > 1.02*PI) | (hemi_total < 0.98*PI)) {
              sprintf(errmsg, "outgoing BSDF hemisphere off by %.1f%%",
                            100.*(hemi_total/PI - 1.));
              error(WARNING, errmsg);
       }
       dom = PI / hemi_total;             /* fix normalization */
       for (o = dp->nout; o--; )
              omega_oarr[o] *= dom;
       nneg = 0;                   /* check outgoing totals */
       for (i = 0; i < dp->ninc; i++) {
              hemi_total = .0;
              for (o = dp->nout; o--; ) {
                     double f = BSDF_value(dp,i,o);
                     if (f >= .0)
                            hemi_total += f*omega_oarr[o];
                     else {
                            nneg += (f < -FTINY);
                            BSDF_value(dp,i,o) = .0f;
                     }
              }
              if (hemi_total > 1.02) {
                     sprintf(errmsg,
                     "incoming BSDF direction %d passes %.1f%% of light",
                                   i, 100.*hemi_total);
                     error(WARNING, errmsg);
              }
       }
       if (nneg) {
              sprintf(errmsg, "%d negative BSDF values (ignored)", nneg);
              error(WARNING, errmsg);
       }
                                   /* reverse roles and check again */
       for (o = 0; o < dp->nout; o++) {
              hemi_total = .0;
              for (i = dp->ninc; i--; )
                     hemi_total += BSDF_value(dp,i,o) * omega_iarr[i];

              if (hemi_total > 1.02) {
                     sprintf(errmsg,
                     "outgoing BSDF direction %d collects %.1f%% of light",
                                   o, 100.*hemi_total);
                     error(WARNING, errmsg);
              }
       }
       free(omega_iarr); free(omega_oarr);
       return(1);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void free_BSDF ( struct BSDF_data b)

Definition at line 416 of file bsdf.c.

{
       if (b == NULL)
              return;
       if (b->bsdf != NULL)
              free(b->bsdf);
       free(b);
}

Here is the caller graph for this function:

int getBSDF_xfm ( MAT4  xm,
FVECT  nrm,
UpDir  ud 
)

Definition at line 527 of file bsdf.c.

{
       char   *xfargs[7];
       XF     myxf;
       FVECT  updir, xdest, ydest;

       updir[0] = updir[1] = updir[2] = 0.;
       switch (ud) {
       case UDzneg:
              updir[2] = -1.;
              break;
       case UDyneg:
              updir[1] = -1.;
              break;
       case UDxneg:
              updir[0] = -1.;
              break;
       case UDxpos:
              updir[0] = 1.;
              break;
       case UDypos:
              updir[1] = 1.;
              break;
       case UDzpos:
              updir[2] = 1.;
              break;
       case UDunknown:
              return(0);
       }
       fcross(xdest, updir, nrm);
       if (normalize(xdest) == 0.0)
              return(0);
       fcross(ydest, nrm, xdest);
       xf(&myxf, addrot(xfargs, xdest, ydest, nrm), xfargs);
       copymat4(xm, myxf.xfm);
       return(1);
}

Here is the call graph for this function:

Here is the caller graph for this function:

struct BSDF_data* load_BSDF ( char *  fname) [read]

Definition at line 356 of file bsdf.c.

{
       char                 *path;
       ezxml_t                     fl, wtl, wld, wdb;
       struct BSDF_data     *dp;
       
       path = getpath(fname, getrlibpath(), R_OK);
       if (path == NULL) {
              sprintf(errmsg, "cannot find BSDF file \"%s\"", fname);
              error(WARNING, errmsg);
              return(NULL);
       }
       fl = ezxml_parse_file(path);
       if (fl == NULL) {
              sprintf(errmsg, "cannot open BSDF \"%s\"", path);
              error(WARNING, errmsg);
              return(NULL);
       }
       if (ezxml_error(fl)[0]) {
              sprintf(errmsg, "BSDF \"%s\" %s", path, ezxml_error(fl));
              error(WARNING, errmsg);
              ezxml_free(fl);
              return(NULL);
       }
       if (strcmp(ezxml_name(fl), "WindowElement")) {
              sprintf(errmsg,
                     "BSDF \"%s\": top level node not 'WindowElement'",
                            path);
              error(WARNING, errmsg);
              ezxml_free(fl);
              return(NULL);
       }
       wtl = ezxml_child(ezxml_child(fl, "Optical"), "Layer");
       dp = (struct BSDF_data *)calloc(1, sizeof(struct BSDF_data));
       for (wld = ezxml_child(wtl, "WavelengthData");
                            wld != NULL; wld = wld->next) {
              if (strcmp(ezxml_txt(ezxml_child(wld,"Wavelength")), "Visible"))
                     continue;
              wdb = ezxml_child(wld, "WavelengthDataBlock");
              if (wdb == NULL) continue;
              if (strcmp(ezxml_txt(ezxml_child(wdb,"WavelengthDataDirection")),
                                   "Transmission Front"))
                     continue;
              load_bsdf_data(dp, wdb);    /* load front BTDF */
              break;                      /* ignore the rest */
       }
       ezxml_free(fl);                           /* done with XML file */
       if (!check_bsdf_data(dp)) {
              sprintf(errmsg, "bad/missing BTDF data in \"%s\"", path);
              error(WARNING, errmsg);
              free_BSDF(dp);
              dp = NULL;
       }
       return(dp);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void load_bsdf_data ( struct BSDF_data dp,
ezxml_t  wdb 
) [static]

Definition at line 177 of file bsdf.c.

{
       char  *cbasis = ezxml_txt(ezxml_child(wdb,"ColumnAngleBasis"));
       char  *rbasis = ezxml_txt(ezxml_child(wdb,"RowAngleBasis"));
       char  *sdata;
       int  i;
       
       if ((cbasis == NULL) | (rbasis == NULL)) {
              error(WARNING, "missing column/row basis for BSDF");
              return;
       }
       /* XXX need to add routines for loading in foreign bases */
       for (i = nabases; i--; )
              if (!strcmp(cbasis, abase_list[i].name)) {
                     dp->ninc = abase_list[i].nangles;
                     dp->ib_priv = (void *)&abase_list[i];
                     dp->ib_vec = ab_getvecR;
                     dp->ib_ndx = ab_getndxR;
                     dp->ib_ohm = ab_getohm;
                     break;
              }
       if (i < 0) {
              sprintf(errmsg, "unsupported ColumnAngleBasis '%s'", cbasis);
              error(WARNING, errmsg);
              return;
       }
       for (i = nabases; i--; )
              if (!strcmp(rbasis, abase_list[i].name)) {
                     dp->nout = abase_list[i].nangles;
                     dp->ob_priv = (void *)&abase_list[i];
                     dp->ob_vec = ab_getvec;
                     dp->ob_ndx = ab_getndx;
                     dp->ob_ohm = ab_getohm;
                     break;
              }
       if (i < 0) {
              sprintf(errmsg, "unsupported RowAngleBasis '%s'", cbasis);
              error(WARNING, errmsg);
              return;
       }
                            /* read BSDF data */
       sdata  = ezxml_txt(ezxml_child(wdb,"ScatteringData"));
       if (sdata == NULL) {
              error(WARNING, "missing BSDF ScatteringData");
              return;
       }
       dp->bsdf = (float *)malloc(sizeof(float)*dp->ninc*dp->nout);
       if (dp->bsdf == NULL)
              error(SYSTEM, "out of memory in load_bsdf_data");
       for (i = 0; i < dp->ninc*dp->nout; i++) {
              char  *sdnext = fskip(sdata);
              if (sdnext == NULL) {
                     error(WARNING, "bad/missing BSDF ScatteringData");
                     free(dp->bsdf); dp->bsdf = NULL;
                     return;
              }
              while (*sdnext && isspace(*sdnext))
                     sdnext++;
              if (*sdnext == ',') sdnext++;
              dp->bsdf[i] = atof(sdata);
              sdata = sdnext;
       }
       while (isspace(*sdata))
              sdata++;
       if (*sdata) {
              sprintf(errmsg, "%d extra characters after BSDF ScatteringData",
                            strlen(sdata));
              error(WARNING, errmsg);
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

int r_BSDF_incvec ( FVECT  v,
struct BSDF_data b,
int  i,
double  rv,
MAT4  xm 
)

Definition at line 429 of file bsdf.c.

{
       FVECT  pert;
       double rad;
       int    j;
       
       if (!getBSDF_incvec(v, b, i))
              return(0);
       rad = sqrt(getBSDF_incohm(b, i) / PI);
       multisamp(pert, 3, rv);
       for (j = 0; j < 3; j++)
              v[j] += rad*(2.*pert[j] - 1.);
       if (xm != NULL)
              multv3(v, v, xm);
       return(normalize(v) != 0.0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int r_BSDF_outvec ( FVECT  v,
struct BSDF_data b,
int  o,
double  rv,
MAT4  xm 
)

Definition at line 454 of file bsdf.c.

{
       FVECT  pert;
       double rad;
       int    j;
       
       if (!getBSDF_outvec(v, b, o))
              return(0);
       rad = sqrt(getBSDF_outohm(b, o) / PI);
       multisamp(pert, 3, rv);
       for (j = 0; j < 3; j++)
              v[j] += rad*(2.*pert[j] - 1.);
       if (xm != NULL)
              multv3(v, v, xm);
       return(normalize(v) != 0.0);
}

Here is the call graph for this function:


Variable Documentation

Definition at line 28 of file bsdf.c.

int nabases = 3 [static]

Definition at line 62 of file bsdf.c.

const char RCSid[] = "$Id: bsdf.c,v 2.2 2009/06/19 06:49:25 greg Exp $" [static]

Definition at line 2 of file bsdf.c.