/* Copyright (c) 1992 Regents of the University of California */ #ifndef lint static char SCCSid[] = "$SunId$ LBL"; #endif /* * Replace markers in Radiance scene description with objects or instances. * * Created: 17 Feb 1991 Greg Ward */ #include #include #include #include "fvect.h" #ifdef M_PI #define PI ((double)M_PI) #else #define PI 3.14159265358979323846 #endif #define FEQ(a,b) ((a)-(b) <= 1e-7 && (b)-(a) <= 1e-7) #define MAXVERT 6 /* maximum number of vertices for markers */ #define MAXMARK 32 /* maximum number of markers */ #ifdef DCL_ATOF extern double atof(); #endif typedef struct { short beg, end; /* beginning and ending vertex */ float len2; /* length squared */ } EDGE; /* a marker edge */ struct mrkr { char *modout; /* output modifier */ double mscale; /* scale by this to get unit */ char *modin; /* input modifier indicating marker */ char *objname; /* output object file or octree */ int doxform; /* true if xform, false if instance */ } marker[MAXMARK]; /* array of markers */ int nmarkers = 0; /* number of markers */ int expand; /* expand commands? */ char *progname; main(argc, argv) int argc; char *argv[]; { FILE *fp; int i, j; progname = argv[0]; i = 1; while (i < argc && argv[i][0] == '-') { do { switch (argv[i][1]) { case 'i': marker[nmarkers].doxform = 0; marker[nmarkers].objname = argv[++i]; break; case 'x': marker[nmarkers].doxform = 1; marker[nmarkers].objname = argv[++i]; break; case 'e': expand = 1; break; case 'm': marker[nmarkers].modout = argv[++i]; break; case 's': marker[nmarkers].mscale = atof(argv[++i]); break; default: goto userr; } if (++i >= argc) goto userr; } while (argv[i][0] == '-'); if (marker[nmarkers].objname == NULL) goto userr; marker[nmarkers++].modin = argv[i++]; if (nmarkers >= MAXMARK) break; marker[nmarkers].mscale = marker[nmarkers-1].mscale; } if (nmarkers == 0) goto userr; /* simple header */ putchar('#'); for (j = 0; j < i; j++) { putchar(' '); fputs(argv[j], stdout); } putchar('\n'); if (i == argc) convert("", stdin); else for ( ; i < argc; i++) { if ((fp = fopen(argv[i], "r")) == NULL) { perror(argv[i]); exit(1); } convert(argv[i], fp); fclose(fp); } exit(0); userr: fprintf(stderr, "Usage: %s [-e][-s size][-m modout] {-x objfile|-i octree} modname .. [file ..]\n", progname); exit(1); } convert(name, fin) /* replace marks in a stream */ char *name; register FILE *fin; { register int c; while ((c = getc(fin)) != EOF) { if (isspace(c)) /* blank */ continue; if (c == '#') { /* comment */ putchar(c); do { if ((c = getc(fin)) == EOF) return; putchar(c); } while (c != '\n'); } else if (c == '!') { /* command */ ungetc(c, fin); cvcomm(name, fin); } else { /* object */ ungetc(c, fin); cvobject(name, fin); } } } cvcomm(fname, fin) /* convert a command */ char *fname; FILE *fin; { FILE *pin, *popen(); char buf[512], *fgetline(); fgetline(buf, sizeof(buf), fin); if (expand) { if ((pin = popen(buf+1, "r")) == NULL) { fprintf(stderr, "%s: (%s): cannot execute \"%s\"\n", progname, fname, buf); exit(1); } convert(buf, pin); pclose(pin); } else printf("\n%s\n", buf); } cvobject(fname, fin) /* convert an object */ char *fname; FILE *fin; { char buf[128], typ[16], nam[128]; int i, n; register int j; if (fscanf(fin, "%s %s %s", buf, typ, nam) != 3) goto readerr; if (!strcmp(typ, "polygon")) for (j = 0; j < nmarkers; j++) if (!strcmp(buf, marker[j].modin)) { replace(fname, &marker[j], nam, fin); return; } printf("\n%s %s %s\n", buf, typ, nam); if (!strcmp(typ, "alias")) { /* alias special case */ if (fscanf(fin, "%s", buf) != 1) goto readerr; printf("\t%s\n", buf); return; } for (i = 0; i < 3; i++) { /* pass along arguments */ if (fscanf(fin, "%d", &n) != 1) goto readerr; printf("%d", n); for (j = 0; j < n; j++) { if (fscanf(fin, "%s", buf) != 1) goto readerr; if (j%3 == 0) putchar('\n'); printf("\t%s", buf); } putchar('\n'); } return; readerr: fprintf(stderr, "%s: (%s): read error for %s \"%s\"\n", progname, fname, typ, nam); } replace(fname, m, mark, fin) /* replace marker */ char *fname; register struct mrkr *m; char *mark; FILE *fin; { int n; char buf[256]; if (m->doxform) { sprintf(buf, "xform -e -n %s", mark); if (m->modout != NULL) sprintf(buf+strlen(buf), " -m %s", m->modout); if (buildxf(buf+strlen(buf), m->mscale, fin) < 0) goto badxf; sprintf(buf+strlen(buf), " %s", m->objname); if (expand) { fflush(stdout); system(buf); } else printf("\n!%s\n", buf); } else { if ((n = buildxf(buf, m->mscale, fin)) < 0) goto badxf; printf("\n%s instance %s\n", m->modout==NULL?"void":m->modout, mark); printf("%d %s%s\n0\n0\n", n+1, m->objname, buf); } return; badxf: fprintf(stderr, "%s: (%s): bad arguments for marker \"%s\"\n", progname, fname, mark); exit(1); } edgecmp(e1, e2) /* compare two edges, descending order */ EDGE *e1, *e2; { if (e1->len2 > e2->len2) return(-1); if (e1->len2 < e2->len2) return(1); return(0); } int buildxf(xf, markscale, fin) /* build transform for marker */ char *xf; double markscale; FILE *fin; { static FVECT vlist[MAXVERT]; static EDGE elist[MAXVERT]; FVECT xvec, yvec, zvec; double xlen; int n; register int i; /* * Read and sort vectors: longest is hypotenuse, * second longest is x' axis, * third longest is y' axis (approximate), * other vectors are ignored. * It is an error if the x' and y' axes do * not share a common vertex (their origin). */ if (fscanf(fin, "%*d %*d %d", &n) != 1) return(-1); if (n%3 != 0) return(-1); n /= 3; if (n < 3 || n > MAXVERT) return(-1); /* sort edges in descending order */ for (i = 0; i < n; i++) { if (fscanf(fin, "%lf %lf %lf", &vlist[i][0], &vlist[i][1], &vlist[i][2]) != 3) return(-1); if (i) { elist[i].beg = i-1; elist[i].end = i; elist[i].len2 = dist2(vlist[i-1],vlist[i]); } } elist[0].beg = n-1; elist[0].end = 0; elist[0].len2 = dist2(vlist[n-1],vlist[0]); qsort(elist, n, sizeof(EDGE), edgecmp); /* find x' and y' */ if (elist[1].end == elist[2].beg || elist[1].end == elist[2].end) { i = elist[1].beg; elist[1].beg = elist[1].end; elist[1].end = i; } if (elist[2].end == elist[1].beg) { i = elist[2].beg; elist[2].beg = elist[2].end; elist[2].end = i; } if (elist[1].beg != elist[2].beg) return(-1); /* x' and y' not connected! */ for (i = 0; i < 3; i++) { xvec[i] = vlist[elist[1].end][i] - vlist[elist[1].beg][i]; yvec[i] = vlist[elist[2].end][i] - vlist[elist[2].beg][i]; } if ((xlen = normalize(xvec)) == 0.0) return(-1); fcross(zvec, xvec, yvec); if (normalize(zvec) == 0.0) return(-1); fcross(yvec, zvec, xvec); n = 0; /* start transformation... */ if (markscale > 0.0) { /* add scale factor */ sprintf(xf, " -s %f", xlen*markscale); n += 2; xf += strlen(xf); } /* add rotation */ n += addrot(xf, xvec, yvec, zvec); xf += strlen(xf); /* add translation */ n += 4; sprintf(xf, " -t %f %f %f", vlist[elist[1].beg][0], vlist[elist[1].beg][1], vlist[elist[1].beg][2]); return(n); /* all done */ } addrot(xf, xp, yp, zp) /* compute rotation (x,y,z) => (xp,yp,zp) */ char *xf; FVECT xp, yp, zp; { int n; double theta; n = 0; theta = atan2(yp[2], zp[2]); if (!FEQ(theta,0.0)) { sprintf(xf, " -rx %f", theta*(180./PI)); xf += strlen(xf); n += 2; } theta = asin(-xp[2]); if (!FEQ(theta,0.0)) { sprintf(xf, " -ry %f", theta*(180./PI)); xf += strlen(xf); n += 2; } theta = atan2(xp[1], xp[0]); if (!FEQ(theta,0.0)) { sprintf(xf, " -rz %f", theta*(180./PI)); /* xf += strlen(xf); */ n += 2; } return(n); }