Back to index

radiance  4R0+20100331
replmarks.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char RCSid[] = "$Id: replmarks.c,v 2.15 2008/01/25 02:11:13 greg Exp $";
00003 #endif
00004 /*
00005  * Replace markers in Radiance scene description with objects or instances.
00006  *
00007  *     Created:      17 Feb 1991   Greg Ward
00008  */
00009 
00010 #include <stdlib.h>
00011 #include <ctype.h>
00012 #include <math.h>
00013 #include <stdio.h>
00014 
00015 #include "platform.h"
00016 #include "rtio.h"
00017 #include "rtprocess.h"
00018 #include "fvect.h"
00019 
00020 #ifdef  M_PI
00021 #define  PI          ((double)M_PI)
00022 #else
00023 #define  PI          3.14159265358979323846
00024 #endif
00025 
00026 #define  FEQ(a,b)    ((a)-(b) <= 1e-7 && (b)-(a) <= 1e-7)
00027 
00028 #define  MAXVERT     6      /* maximum number of vertices for markers */
00029 #define  MAXMARK     128    /* maximum number of markers */
00030 
00031 #define  USE_XFORM   1      /* use !xform inline command */
00032 #define  USE_INSTANCE       2      /* use instance primitive */
00033 #define  USE_MESH    3      /* use mesh primitive */
00034 
00035 typedef struct {
00036        short  beg, end;            /* beginning and ending vertex */
00037        float  len2;                /* length squared */
00038 }  EDGE;                    /* a marker edge */
00039 
00040 struct mrkr {
00041        char   *modout;             /* output modifier */
00042        double mscale;                     /* scale by this to get unit */
00043        char   *modin;                     /* input modifier indicating marker */
00044        char   *objname;            /* output object file or octree */
00045        int    usetype;             /* one of USE_* above */
00046 }  marker[MAXMARK+1];              /* array of markers */
00047 int    nmarkers = 0;        /* number of markers */
00048 
00049 int    expand;                     /* expand commands? */
00050 
00051 char   *progname;
00052 
00053 static void convert(char *name, FILE *fin);
00054 static void cvcomm(char *fname, FILE *fin);
00055 static void cvobject(char *fname, FILE *fin);
00056 static void replace(char *fname, struct mrkr *m, char *mark, FILE *fin);
00057 static int edgecmp(const void *e1, const void *e2);
00058 static int buildxf(char *xf, double markscale, FILE *fin);
00059 static int addrot(char *xf, FVECT xp, FVECT yp, FVECT zp);
00060 
00061 
00062 int
00063 main(
00064        int    argc,
00065        char   *argv[]
00066 )
00067 {
00068        FILE   *fp;
00069        int    i, j;
00070 
00071        progname = argv[0];
00072        i = 1;
00073        while (i < argc && argv[i][0] == '-') {
00074               do {
00075                      switch (argv[i][1]) {
00076                      case 'i':
00077                             marker[nmarkers].usetype = USE_INSTANCE;
00078                             marker[nmarkers].objname = argv[++i];
00079                             break;
00080                      case 'I':
00081                             marker[nmarkers].usetype = USE_MESH;
00082                             marker[nmarkers].objname = argv[++i];
00083                             break;
00084                      case 'x':
00085                             marker[nmarkers].usetype = USE_XFORM;
00086                             marker[nmarkers].objname = argv[++i];
00087                             break;
00088                      case 'e':
00089                             expand = 1;
00090                             break;
00091                      case 'm':
00092                             marker[nmarkers].modout = argv[++i];
00093                             break;
00094                      case 's':
00095                             marker[nmarkers].mscale = atof(argv[++i]);
00096                             break;
00097                      default:
00098                             goto userr;
00099                      }
00100                      if (++i >= argc)
00101                             goto userr;
00102               } while (argv[i][0] == '-');
00103               if (marker[nmarkers].objname == NULL)
00104                      goto userr;
00105               if (nmarkers >= MAXMARK) {
00106                      fprintf(stderr, "%s: too many markers\n", progname);
00107                      return 1;
00108               }
00109               marker[nmarkers++].modin = argv[i++];
00110               marker[nmarkers].mscale = marker[nmarkers-1].mscale;
00111        }
00112        if (nmarkers == 0)
00113               goto userr;
00114                                    /* simple header */
00115        putchar('#');
00116        for (j = 0; j < i; j++) {
00117               putchar(' ');
00118               fputs(argv[j], stdout);
00119        }
00120        putchar('\n');
00121        if (i == argc)
00122               convert("<stdin>", stdin);
00123        else
00124               for ( ; i < argc; i++) {
00125                      if ((fp = fopen(argv[i], "r")) == NULL) {
00126                             perror(argv[i]);
00127                             exit(1);
00128                      }
00129                      convert(argv[i], fp);
00130                      fclose(fp);
00131               }
00132        return 0;
00133 userr:
00134        fprintf(stderr,
00135 "Usage: %s [-e][-s size][-m modout] {-x objfile|-i octree|-I mesh} modname .. [file ..]\n",
00136               progname);
00137        return 1;
00138 }
00139 
00140 
00141 void
00142 convert(             /* replace marks in a stream */
00143        char   *name,
00144        register FILE *fin
00145 )
00146 {
00147        register int  c;
00148 
00149        while ((c = getc(fin)) != EOF) {
00150               if (isspace(c))                           /* blank */
00151                      continue;
00152               if (c == '#') {                           /* comment */
00153                      putchar(c);
00154                      do {
00155                             if ((c = getc(fin)) == EOF)
00156                                    return;
00157                             putchar(c);
00158                      } while (c != '\n');
00159               } else if (c == '!') {                    /* command */
00160                      ungetc(c, fin);
00161                      cvcomm(name, fin);
00162               } else {                           /* object */
00163                      ungetc(c, fin);
00164                      cvobject(name, fin);
00165               }
00166        }
00167 }
00168 
00169 
00170 void
00171 cvcomm(              /* convert a command */
00172        char   *fname,
00173        FILE   *fin
00174 )
00175 {
00176        FILE   *pin;
00177        char   buf[512], *fgetline();
00178 
00179        fgetline(buf, sizeof(buf), fin);
00180        if (expand) {
00181               if ((pin = popen(buf+1, "r")) == NULL) {
00182                      fprintf(stderr,
00183                      "%s: (%s): cannot execute \"%s\"\n",
00184                                    progname, fname, buf);
00185                      exit(1);
00186               }
00187               convert(buf, pin);
00188               pclose(pin);
00189        } else
00190               printf("\n%s\n", buf);
00191 }
00192 
00193 
00194 void
00195 cvobject(            /* convert an object */
00196        char   *fname,
00197        FILE   *fin
00198 )
00199 {
00200        extern char   *fgetword();
00201        char   buf[128], typ[16], nam[128];
00202        int    i, n;
00203        register int  j;
00204 
00205        if (fgetword(buf, sizeof(buf), fin) == NULL ||
00206                      fgetword(typ, sizeof(typ), fin) == NULL ||
00207                      fgetword(nam, sizeof(nam), fin) == NULL)
00208               goto readerr;
00209        if (!strcmp(typ, "polygon"))
00210               for (j = 0; j < nmarkers; j++)
00211                      if (!strcmp(buf, marker[j].modin)) {
00212                             replace(fname, &marker[j], nam, fin);
00213                             return;
00214                      }
00215        putchar('\n'); fputword(buf, stdout);
00216        printf(" %s ", typ);
00217        fputword(nam, stdout); putchar('\n');
00218        if (!strcmp(typ, "alias")) {              /* alias special case */
00219               if (fgetword(buf, sizeof(buf), fin) == NULL)
00220                      goto readerr;
00221               putchar('\t'); fputword(buf, stdout); putchar('\n');
00222               return;
00223        }
00224        for (i = 0; i < 3; i++) {          /* pass along arguments */
00225               if (fscanf(fin, "%d", &n) != 1)
00226                      goto readerr;
00227               printf("%d", n);
00228               for (j = 0; j < n; j++) {
00229                      if (fgetword(buf, sizeof(buf), fin) == NULL)
00230                             goto readerr;
00231                      if (j%3 == 0)
00232                             putchar('\n');
00233                      putchar('\t');
00234                      fputword(buf, stdout);
00235               }
00236               putchar('\n');
00237        }
00238        return;
00239 readerr:
00240        fprintf(stderr, "%s: (%s): read error for %s \"%s\"\n",
00241                      progname, fname, typ, nam);
00242 }
00243 
00244 
00245 void
00246 replace(             /* replace marker */
00247        char   *fname,
00248        register struct mrkr *m,
00249        char   *mark,
00250        FILE   *fin
00251 )
00252 {
00253        int    n;
00254        char   buf[256];
00255 
00256        buf[0] = '\0';                     /* bug fix thanks to schorsch */
00257        if (m->usetype == USE_XFORM) {
00258               sprintf(buf, "xform -n %s", mark);
00259               if (m->modout != NULL)
00260                      sprintf(buf+strlen(buf), " -m %s", m->modout);
00261               if (buildxf(buf+strlen(buf), m->mscale, fin) < 0)
00262                      goto badxf;
00263               sprintf(buf+strlen(buf), " %s", m->objname);
00264               if (expand) {
00265                      fflush(stdout);
00266                      system(buf);
00267               } else
00268                      printf("\n!%s\n", buf);
00269        } else {
00270               if ((n = buildxf(buf, m->mscale, fin)) < 0)
00271                      goto badxf;
00272               printf("\n%s %s %s\n",
00273                             m->modout==NULL?"void":m->modout,
00274                             m->usetype==USE_INSTANCE?"instance":"mesh",
00275                             mark);
00276               printf("%d %s%s\n0\n0\n", n+1, m->objname, buf);
00277        }
00278        return;
00279 badxf:
00280        fprintf(stderr, "%s: (%s): bad arguments for marker \"%s\"\n",
00281                      progname, fname, mark);
00282        exit(1);
00283 }
00284 
00285 
00286 int
00287 edgecmp(                    /* compare two edges, descending order */
00288        const void *e1,
00289        const void *e2
00290 )
00291 {
00292        if (((EDGE*)e1)->len2 > ((EDGE*)e2)->len2)
00293               return(-1);
00294        if (((EDGE*)e1)->len2 < ((EDGE*)e2)->len2)
00295               return(1);
00296        return(0);
00297 }
00298 
00299 
00300 int
00301 buildxf(             /* build transform for marker */
00302        register char *xf,
00303        double markscale,
00304        FILE   *fin
00305 )
00306 {
00307        static FVECT  vlist[MAXVERT];
00308        static EDGE   elist[MAXVERT];
00309        FVECT  xvec, yvec, zvec;
00310        double xlen;
00311        int    n;
00312        register int  i;
00313        /*
00314         * Read and sort vectors:  longest is hypotenuse,
00315         *     second longest is x' axis,
00316         *     third longest is y' axis (approximate),
00317         *     other vectors are ignored.
00318         * It is an error if the x' and y' axes do
00319         *     not share a common vertex (their origin).
00320         */
00321        if (fscanf(fin, "%*d %*d %d", &n) != 1)
00322               return(-1);
00323        if (n%3 != 0)
00324               return(-1);
00325        n /= 3;
00326        if (n < 3 || n > MAXVERT)
00327               return(-1);
00328                                    /* sort edges in descending order */
00329        for (i = 0; i < n; i++) {
00330               if (fscanf(fin, "%lf %lf %lf", &vlist[i][0],
00331                             &vlist[i][1], &vlist[i][2]) != 3)
00332                      return(-1);
00333               if (i) {
00334                      elist[i].beg = i-1;
00335                      elist[i].end = i;
00336                      elist[i].len2 = dist2(vlist[i-1],vlist[i]);
00337               }
00338        }
00339        elist[0].beg = n-1;
00340        elist[0].end = 0;
00341        elist[0].len2 = dist2(vlist[n-1],vlist[0]);
00342        qsort(elist, n, sizeof(EDGE), edgecmp);
00343                                    /* find x' and y' */
00344        if (elist[1].end == elist[2].beg || elist[1].end == elist[2].end) {
00345               i = elist[1].beg;
00346               elist[1].beg = elist[1].end;
00347               elist[1].end = i;
00348        }
00349        if (elist[2].end == elist[1].beg) {
00350               i = elist[2].beg;
00351               elist[2].beg = elist[2].end;
00352               elist[2].end = i;
00353        }
00354        if (elist[1].beg != elist[2].beg)
00355               return(-1);          /* x' and y' not connected! */
00356        for (i = 0; i < 3; i++) {
00357               xvec[i] = vlist[elist[1].end][i] - vlist[elist[1].beg][i];
00358               yvec[i] = vlist[elist[2].end][i] - vlist[elist[2].beg][i];
00359        }
00360        if ((xlen = normalize(xvec)) == 0.0)
00361               return(-1);
00362        fcross(zvec, xvec, yvec);
00363        if (normalize(zvec) == 0.0)
00364               return(-1);
00365        fcross(yvec, zvec, xvec);
00366        n = 0;                      /* start transformation... */
00367        if (markscale > 0.0) {             /* add scale factor */
00368               sprintf(xf, " -s %f", xlen*markscale);
00369               n += 2;
00370               while (*xf) ++xf;
00371        }
00372                                    /* add rotation */
00373        n += addrot(xf, xvec, yvec, zvec);
00374        while (*xf) ++xf;
00375                                    /* add translation */
00376        n += 4;
00377        sprintf(xf, " -t %f %f %f", vlist[elist[1].beg][0],
00378                      vlist[elist[1].beg][1], vlist[elist[1].beg][2]);
00379        return(n);                  /* all done */
00380 }
00381 
00382 
00383 int
00384 addrot(              /* compute rotation (x,y,z) => (xp,yp,zp) */
00385        register char *xf,
00386        FVECT xp,
00387        FVECT yp,
00388        FVECT zp
00389 )
00390 {
00391        int    n;
00392        double theta;
00393 
00394        if (yp[2]*yp[2] + zp[2]*zp[2] < 2.*FTINY*FTINY) {
00395               /* Special case for X' along Z-axis */
00396               theta = -atan2(yp[0], yp[1]);
00397               sprintf(xf, " -ry %f -rz %f",
00398                             xp[2] < 0.0 ? 90.0 : -90.0,
00399                             theta*(180./PI));
00400               return(4);
00401        }
00402        n = 0;
00403        theta = atan2(yp[2], zp[2]);
00404        if (!FEQ(theta,0.0)) {
00405               sprintf(xf, " -rx %f", theta*(180./PI));
00406               while (*xf) ++xf;
00407               n += 2;
00408        }
00409        theta = asin(-xp[2]);
00410        if (!FEQ(theta,0.0)) {
00411               sprintf(xf, " -ry %f", theta*(180./PI));
00412               while (*xf) ++xf;
00413               n += 2;
00414        }
00415        theta = atan2(xp[1], xp[0]);
00416        if (!FEQ(theta,0.0)) {
00417               sprintf(xf, " -rz %f", theta*(180./PI));
00418               /* while (*xf) ++xf; */
00419               n += 2;
00420        }
00421        return(n);
00422 }