Back to index

radiance  4R0+20100331
xf.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char    RCSid[] = "$Id: xf.c,v 1.14 2003/02/28 20:11:30 greg Exp $";
00003 #endif
00004 /*
00005  * Routines for 4x4 homogeneous, rigid-body transformations
00006  */
00007 
00008 #include <stdio.h>
00009 #include <math.h>
00010 #include <stdlib.h>
00011 #include <string.h>
00012 #include "parser.h"
00013 
00014 #define  d2r(a)             ((PI/180.)*(a))
00015 
00016 #define  checkarg(a,l)      if (av[i][a] || badarg(ac-i-1,av+i+1,l)) goto done
00017 
00018 MAT4  m4ident = MAT4IDENT;
00019 
00020 static MAT4  m4tmp;         /* for efficiency */
00021 
00022 XF_SPEC       *xf_context = NULL;  /* current context */
00023 char   **xf_argend;         /* end of transform argument list */
00024 static char   **xf_argbeg;  /* beginning of transform argument list */
00025 
00026 
00027 int
00028 xf_handler(ac, av)          /* handle xf entity */
00029 int    ac;
00030 char   **av;
00031 {
00032        register XF_SPEC     *spec;
00033        register int  n;
00034        int    rv;
00035 
00036        if (ac == 1) {                     /* something with existing transform */
00037               if ((spec = xf_context) == NULL)
00038                      return(MG_ECNTXT);
00039               n = -1;
00040               if (spec->xarr != NULL) {   /* check for iteration */
00041                      register struct xf_array    *ap = spec->xarr;
00042 
00043                      (void)xf_aname((struct xf_array *)NULL);
00044                      n = ap->ndim;
00045                      while (n--) {
00046                             if (++ap->aarg[n].i < ap->aarg[n].n)
00047                                    break;
00048                             (void)strcpy(ap->aarg[n].arg, "0");
00049                             ap->aarg[n].i = 0;
00050                      }
00051                      if (n >= 0) {
00052                             if ((rv = mg_fgoto(&ap->spos)) != MG_OK)
00053                                    return(rv);
00054                             sprintf(ap->aarg[n].arg, "%d", ap->aarg[n].i);
00055                             (void)xf_aname(ap);
00056                      }
00057               }
00058               if (n < 0) {                /* pop transform */
00059                      xf_context = spec->prev;
00060                      free_xf(spec);
00061                      return(MG_OK);
00062               }
00063        } else {                    /* else allocate transform */
00064               if ((spec = new_xf(ac-1, av+1)) == NULL)
00065                      return(MG_EMEM);
00066               if (spec->xarr != NULL)
00067                      (void)xf_aname(spec->xarr);
00068               spec->prev = xf_context;    /* push onto stack */
00069               xf_context = spec;
00070        }
00071                                    /* translate new specification */
00072        n = xf_ac(spec);
00073        n -= xf_ac(spec->prev);            /* incremental comp. is more eff. */
00074        if (xf(&spec->xf, n, xf_av(spec)) != n)
00075               return(MG_ETYPE);
00076                                    /* check for vertex reversal */
00077        if ((spec->rev = (spec->xf.sca < 0.)))
00078               spec->xf.sca = -spec->xf.sca;
00079                                    /* compute total transformation */
00080        if (spec->prev != NULL) {
00081               multmat4(spec->xf.xfm, spec->xf.xfm, spec->prev->xf.xfm);
00082               spec->xf.sca *= spec->prev->xf.sca;
00083               spec->rev ^= spec->prev->rev;
00084        }
00085        spec->xid = comp_xfid(spec->xf.xfm);      /* compute unique ID */
00086        return(MG_OK);
00087 }
00088 
00089 
00090 XF_SPEC *
00091 new_xf(ac, av)                     /* allocate new transform structure */
00092 int    ac;
00093 char   **av;
00094 {
00095        register XF_SPEC     *spec;
00096        register int  i;
00097        char   *cp;
00098        int    n, ndim;
00099 
00100        ndim = 0;
00101        n = 0;                      /* compute space req'd by arguments */
00102        for (i = 0; i < ac; i++)
00103               if (!strcmp(av[i], "-a")) {
00104                      ndim++;
00105                      i++;
00106               } else
00107                      n += strlen(av[i]) + 1;
00108        if (ndim > XF_MAXDIM)
00109               return(NULL);
00110        spec = (XF_SPEC *)malloc(sizeof(XF_SPEC) + n);
00111        if (spec == NULL)
00112               return(NULL);
00113        if (ndim) {
00114               spec->xarr = (struct xf_array *)malloc(sizeof(struct xf_array));
00115               if (spec->xarr == NULL)
00116                      return(NULL);
00117               mg_fgetpos(&spec->xarr->spos);
00118               spec->xarr->ndim = 0;              /* incremented below */
00119        } else
00120               spec->xarr = NULL;
00121        spec->xac = ac + xf_argc;
00122                                    /* and store new xf arguments */
00123        if (xf_argbeg == NULL || xf_av(spec) < xf_argbeg) {
00124               register char **newav =
00125                             (char **)malloc((spec->xac+1)*sizeof(char *));
00126               if (newav == NULL)
00127                      return(NULL);
00128               for (i = xf_argc; i-- > 0; )
00129                      newav[ac+i] = xf_argend[i-xf_context->xac];
00130               *(xf_argend = newav + spec->xac) = NULL;
00131               if (xf_argbeg != NULL)
00132                      free((MEM_PTR)xf_argbeg);
00133               xf_argbeg = newav;
00134        }
00135        cp = (char *)(spec + 1);    /* use memory allocated above */
00136        for (i = 0; i < ac; i++)
00137               if (!strcmp(av[i], "-a")) {
00138                      xf_av(spec)[i++] = "-i";
00139                      xf_av(spec)[i] = strcpy(
00140                                    spec->xarr->aarg[spec->xarr->ndim].arg,
00141                                    "0");
00142                      spec->xarr->aarg[spec->xarr->ndim].i = 0;
00143                      spec->xarr->aarg[spec->xarr->ndim++].n = atoi(av[i]);
00144               } else {
00145                      xf_av(spec)[i] = strcpy(cp, av[i]);
00146                      cp += strlen(av[i]) + 1;
00147               }
00148        return(spec);
00149 }
00150 
00151 
00152 void
00153 free_xf(spec)               /* free a transform */
00154 register XF_SPEC     *spec;
00155 {
00156        if (spec->xarr != NULL)
00157               free((MEM_PTR)spec->xarr);
00158        free((MEM_PTR)spec);
00159 }
00160 
00161 
00162 int
00163 xf_aname(ap)                /* put out name for this instance */
00164 register struct xf_array    *ap;
00165 {
00166        static char   oname[10*XF_MAXDIM];
00167        static char   *oav[3] = {mg_ename[MG_E_OBJECT], oname};
00168        register int  i;
00169        register char *cp1, *cp2;
00170 
00171        if (ap == NULL)
00172               return(mg_handle(MG_E_OBJECT, 1, oav));
00173        cp1 = oname;
00174        *cp1 = 'a';
00175        for (i = 0; i < ap->ndim; i++) {
00176               for (cp2 = ap->aarg[i].arg; *cp2; )
00177                      *++cp1 = *cp2++;
00178               *++cp1 = '.';
00179        }
00180        *cp1 = '\0';
00181        return(mg_handle(MG_E_OBJECT, 2, oav));
00182 }
00183 
00184 
00185 long
00186 comp_xfid(xfm)                     /* compute unique ID from matrix */
00187 register MAT4 xfm;
00188 {
00189        static char   shifttab[64] = { 15, 5, 11, 5, 6, 3,
00190                             9, 15, 13, 2, 13, 5, 2, 12, 14, 11,
00191                             11, 12, 12, 3, 2, 11, 8, 12, 1, 12,
00192                             5, 4, 15, 9, 14, 5, 13, 14, 2, 10,
00193                             10, 14, 12, 3, 5, 5, 14, 6, 12, 11,
00194                             13, 9, 12, 8, 1, 6, 5, 12, 7, 13,
00195                             15, 8, 9, 2, 6, 11, 9, 11 };
00196        register int  i;
00197        register long xid;
00198 
00199        xid = 0;                    /* compute unique transform id */
00200        for (i = 0; i < sizeof(MAT4)/sizeof(unsigned short); i++)
00201               xid ^= (long)(((unsigned short *)xfm)[i]) << shifttab[i&63];
00202        return(xid);
00203 }
00204 
00205 
00206 void
00207 xf_clear()                  /* clear transform stack */
00208 {
00209        register XF_SPEC     *spec;
00210 
00211        if (xf_argbeg != NULL) {
00212               free((MEM_PTR)xf_argbeg);
00213               xf_argbeg = xf_argend = NULL;
00214        }
00215        while ((spec = xf_context) != NULL) {
00216               xf_context = spec->prev;
00217               free_xf(spec);
00218        }
00219 }
00220 
00221 
00222 void
00223 xf_xfmpoint(v1, v2)         /* transform a point by the current matrix */
00224 FVECT  v1, v2;
00225 {
00226        if (xf_context == NULL) {
00227               VCOPY(v1, v2);
00228               return;
00229        }
00230        multp3(v1, v2, xf_context->xf.xfm);
00231 }
00232 
00233 
00234 void
00235 xf_xfmvect(v1, v2)          /* transform a vector using current matrix */
00236 FVECT  v1, v2;
00237 {
00238        if (xf_context == NULL) {
00239               VCOPY(v1, v2);
00240               return;
00241        }
00242        multv3(v1, v2, xf_context->xf.xfm);
00243 }
00244 
00245 
00246 void
00247 xf_rotvect(v1, v2)          /* rotate a vector using current matrix */
00248 FVECT  v1, v2;
00249 {
00250        xf_xfmvect(v1, v2);
00251        if (xf_context == NULL)
00252               return;
00253        v1[0] /= xf_context->xf.sca;
00254        v1[1] /= xf_context->xf.sca;
00255        v1[2] /= xf_context->xf.sca;
00256 }
00257 
00258 
00259 double
00260 xf_scale(d)                 /* scale a number by the current transform */
00261 double d;
00262 {
00263        if (xf_context == NULL)
00264               return(d);
00265        return(d*xf_context->xf.sca);
00266 }
00267 
00268 
00269 void
00270 multmat4(m4a, m4b, m4c)            /* multiply m4b X m4c and put into m4a */
00271 MAT4  m4a;
00272 register MAT4  m4b, m4c;
00273 {
00274        register int  i, j;
00275        
00276        for (i = 4; i--; )
00277               for (j = 4; j--; )
00278                      m4tmp[i][j] = m4b[i][0]*m4c[0][j] +
00279                                   m4b[i][1]*m4c[1][j] +
00280                                   m4b[i][2]*m4c[2][j] +
00281                                   m4b[i][3]*m4c[3][j];
00282        
00283        copymat4(m4a, m4tmp);
00284 }
00285 
00286 
00287 void
00288 multv3(v3a, v3b, m4) /* transform vector v3b by m4 and put into v3a */
00289 FVECT  v3a;
00290 register FVECT  v3b;
00291 register MAT4  m4;
00292 {
00293        m4tmp[0][0] = v3b[0]*m4[0][0] + v3b[1]*m4[1][0] + v3b[2]*m4[2][0];
00294        m4tmp[0][1] = v3b[0]*m4[0][1] + v3b[1]*m4[1][1] + v3b[2]*m4[2][1];
00295        m4tmp[0][2] = v3b[0]*m4[0][2] + v3b[1]*m4[1][2] + v3b[2]*m4[2][2];
00296        
00297        v3a[0] = m4tmp[0][0];
00298        v3a[1] = m4tmp[0][1];
00299        v3a[2] = m4tmp[0][2];
00300 }
00301 
00302 
00303 void
00304 multp3(p3a, p3b, m4)        /* transform p3b by m4 and put into p3a */
00305 register FVECT  p3a;
00306 FVECT  p3b;
00307 register MAT4  m4;
00308 {
00309        multv3(p3a, p3b, m4);       /* transform as vector */
00310        p3a[0] += m4[3][0];  /* translate */
00311        p3a[1] += m4[3][1];
00312        p3a[2] += m4[3][2];
00313 }
00314 
00315 
00316 int
00317 xf(ret, ac, av)                    /* get transform specification */
00318 register XF  *ret;
00319 int  ac;
00320 char  **av;
00321 {
00322        MAT4  xfmat, m4;
00323        double  xfsca, dtmp;
00324        int  i, icnt;
00325 
00326        setident4(ret->xfm);
00327        ret->sca = 1.0;
00328 
00329        icnt = 1;
00330        setident4(xfmat);
00331        xfsca = 1.0;
00332 
00333        for (i = 0; i < ac && av[i][0] == '-'; i++) {
00334        
00335               setident4(m4);
00336               
00337               switch (av[i][1]) {
00338        
00339               case 't':                   /* translate */
00340                      checkarg(2,"fff");
00341                      m4[3][0] = atof(av[++i]);
00342                      m4[3][1] = atof(av[++i]);
00343                      m4[3][2] = atof(av[++i]);
00344                      break;
00345 
00346               case 'r':                   /* rotate */
00347                      switch (av[i][2]) {
00348                      case 'x':
00349                             checkarg(3,"f");
00350                             dtmp = d2r(atof(av[++i]));
00351                             m4[1][1] = m4[2][2] = cos(dtmp);
00352                             m4[2][1] = -(m4[1][2] = sin(dtmp));
00353                             break;
00354                      case 'y':
00355                             checkarg(3,"f");
00356                             dtmp = d2r(atof(av[++i]));
00357                             m4[0][0] = m4[2][2] = cos(dtmp);
00358                             m4[0][2] = -(m4[2][0] = sin(dtmp));
00359                             break;
00360                      case 'z':
00361                             checkarg(3,"f");
00362                             dtmp = d2r(atof(av[++i]));
00363                             m4[0][0] = m4[1][1] = cos(dtmp);
00364                             m4[1][0] = -(m4[0][1] = sin(dtmp));
00365                             break;
00366                      default:
00367                             goto done;
00368                      }
00369                      break;
00370 
00371               case 's':                   /* scale */
00372                      checkarg(2,"f");
00373                      dtmp = atof(av[i+1]);
00374                      if (dtmp == 0.0) goto done;
00375                      i++;
00376                      xfsca *=
00377                      m4[0][0] = 
00378                      m4[1][1] = 
00379                      m4[2][2] = dtmp;
00380                      break;
00381 
00382               case 'm':                   /* mirror */
00383                      switch (av[i][2]) {
00384                      case 'x':
00385                             checkarg(3,"");
00386                             xfsca *=
00387                             m4[0][0] = -1.0;
00388                             break;
00389                      case 'y':
00390                             checkarg(3,"");
00391                             xfsca *=
00392                             m4[1][1] = -1.0;
00393                             break;
00394                      case 'z':
00395                             checkarg(3,"");
00396                             xfsca *=
00397                             m4[2][2] = -1.0;
00398                             break;
00399                      default:
00400                             goto done;
00401                      }
00402                      break;
00403 
00404               case 'i':                   /* iterate */
00405                      checkarg(2,"i");
00406                      while (icnt-- > 0) {
00407                             multmat4(ret->xfm, ret->xfm, xfmat);
00408                             ret->sca *= xfsca;
00409                      }
00410                      icnt = atoi(av[++i]);
00411                      setident4(xfmat);
00412                      xfsca = 1.0;
00413                      continue;
00414 
00415               default:
00416                      goto done;
00417 
00418               }
00419               multmat4(xfmat, xfmat, m4);
00420        }
00421 done:
00422        while (icnt-- > 0) {
00423               multmat4(ret->xfm, ret->xfm, xfmat);
00424               ret->sca *= xfsca;
00425        }
00426        return(i);
00427 }