#ifndef lint static const char RCSid[] = "$Id: arch2rad.c,v 2.3 2003/11/15 17:54:06 schorsch Exp $"; #endif /* * Convert Architrion file to Radiance * * Greg Ward */ #include #include #include #include "rtio.h" #include "trans.h" #define DEFMAPFILE "/usr/local/lib/ray/lib/arch.map" /* qualifiers */ #define Q_COL 0 #define Q_FAC 1 #define Q_LAY 2 #define Q_REF 3 #define NQUALS 4 char *qname[NQUALS] = { "Color", "Face", "Layer", "RefId", }; QLIST qlist = {NQUALS, qname}; /* face ids */ #define F_BOT 0 #define F_END 1 #define F_OPP 2 #define F_REF 3 #define F_SIL 4 #define F_TOP 5 #define NFACES 6 ID faceId[NFACES] = { {"bottom"},{"end"},{"opposite"},{"reference"},{"sill"},{"top"} }; /* valid qualifier ids */ IDLIST qual[NQUALS] = { { 0, NULL }, { NFACES, faceId }, { 0, NULL }, { 0, NULL }, }; /* mapping rules */ RULEHD *ourmap = NULL; /* file header */ struct header { char *filename; char *layer[9]; char length_u[16], area_u[16]; double length_f, area_f; int nblocks, nopenings; } fhead; /* block or opening geometry */ typedef struct { int x[4], y[4], z[4], h[4]; } PRISM; /* macros for x,y,z */ #define p_x(p,i) ((p)->x[(i)&3]) #define p_y(p,i) ((p)->y[(i)&3]) #define p_z(p,i) ((i)&4 ? (p)->h[(i)&3] : (p)->z[i]) /* opening */ typedef struct { PRISM p; int corner; int depth; ID frame; } OPNG; /* block */ typedef struct { short layer; short color; ID refid; PRISM p; int nopenings; OPNG *opening; } BLOCK; /* point format */ char ptfmt[] = "\t%12.9g %12.9g %12.9g\n"; /* antimatter modifier id for openings */ char openmod[] = "opening"; /* return flags for checkface() */ #define T1_OK 1 #define T2_OK 2 #define QL_OK 4 char *progname; /* argv[0] */ void arch2rad(FILE *inp, FILE *out); void arch2names(FILE *inp); int hasmatch(BLOCK *bp, RULEHD *mp); void getfhead(FILE *fp); void puthead(FILE *fp); int getblock(BLOCK *bp, FILE *fp); void putblock(BLOCK *bp, FILE *fp); void doneblock(BLOCK *bp); int getopening(OPNG *op, FILE *fp); void add2quals(BLOCK *bp); int matchrule(BLOCK *bp, RULEHD *rp); void putopenmod(char *sm, char *ml[], int nm, FILE *fp); void putface(char *m, char *bn, char *fn, PRISM *p, int a, int b, int c, int d, FILE *fp); void putfaces(char *m, BLOCK *bp, int ff, FILE *fp); void putpoint(PRISM *p, int n, FILE *fp); void putopening(OPNG *op, FILE *fp); int checkface(PRISM *p, int a, int b, int c, int d); void lcross(long vr[3], long v1[3], long v2[3]); int main( /* translate Architrion file */ int argc, char *argv[] ) { int donames = 0; /* -n flag, produce namelist */ int i; progname = argv[0]; for (i = 1; i < argc && argv[i][0] == '-'; i++) switch (argv[i][1]) { case 'n': /* just produce name list */ donames++; break; case 'm': /* use custom mapfile */ ourmap = getmapping(argv[++i], &qlist); break; default: goto userr; } if (i < argc-1) goto userr; if (i == argc-1) if (freopen(argv[i], "r", stdin) == NULL) { fprintf(stderr, "%s: cannot open\n", argv[i]); exit(1); } getfhead(stdin); /* get Architrion header */ if (donames) { /* scan for ids */ arch2names(stdin); printf("filename \"%s\"\n", fhead.filename); printf("filetype \"Architrion\"\n"); write_quals(&qlist, qual, stdout); } else { /* translate file */ if (ourmap == NULL) ourmap = getmapping(DEFMAPFILE, &qlist); arch2rad(stdin, stdout); } return(0); userr: fprintf(stderr, "Usage: %s [-n][-m mapfile] [input]\n", argv[0]); exit(1); } void arch2rad( /* translate Architrion file to Radiance */ FILE *inp, FILE *out ) { int nbs, nos; BLOCK blk; puthead(out); nbs = nos = 0; while (getblock(&blk, inp) != EOF) { putblock(&blk, out); nbs++; nos += blk.nopenings; doneblock(&blk); } if (nbs != fhead.nblocks) fprintf(stderr, "%s: warning -- block count incorrect (%d != %d)\n", progname, nbs, fhead.nblocks); if (nos != fhead.nopenings) fprintf(stderr, "%s: warning -- opening count incorrect (%d != %d)\n", progname, nos, fhead.nopenings); } void arch2names( /* get name list from an Architrion file */ FILE *inp ) { BLOCK blk; while (getblock(&blk, inp) != EOF) { if (ourmap == NULL || hasmatch(&blk, ourmap)) add2quals(&blk); doneblock(&blk); } } int hasmatch( /* check for any match in rule list */ BLOCK *bp, RULEHD *mp ) { if (mp == NULL) return(0); if (hasmatch(bp, mp->next)) /* check in order -- more likely */ return(1); return(matchrule(bp, mp)); } void getfhead( /* get file header */ FILE *fp ) { char buf[MAXSTR]; int i, n; register int c; /* get file name */ if (fgets(buf, MAXSTR, fp) == NULL) goto readerr; buf[strlen(buf)-1] = '\0'; fhead.filename = savestr(buf); /* get layers */ fhead.layer[0] = "Worksheet"; for (i = 1; i <= 8; i++) { if (fscanf(fp, "L%*[^0-8]%d", &n) != 1 || n != i) goto readerr; while ((c = getc(fp)) != EOF && (c == ' ' || c == '\t')) ; if (c == EOF) goto readerr; ungetc(c, fp); if (fgets(buf, MAXSTR, fp) == NULL) goto readerr; buf[strlen(buf)-1] = '\0'; if (buf[0]) fhead.layer[i] = savestr(buf); else fhead.layer[i] = NULL; } /* get units */ if (fgets(buf, MAXSTR, fp) == NULL) goto readerr; if (sscanf(buf, "0 %*f %s %*f %s\n", fhead.length_u, fhead.area_u) != 2) { fhead.length_u[0] = '\0'; fhead.area_u[0] = '\0'; } if (fgets(buf, MAXSTR, fp) == NULL || sscanf(buf, "0 %lf\n", &fhead.length_f) != 1) goto readerr; if (fgets(buf, MAXSTR, fp) == NULL || sscanf(buf, "0 %lf\n", &fhead.area_f) != 1) goto readerr; /* get number of blocks and openings */ if (fgets(buf, MAXSTR, fp) == NULL || sscanf(buf, "0 %d %d\n", &fhead.nblocks, &fhead.nopenings) != 2) goto readerr; return; readerr: fprintf(stderr, "%s: error reading Architrion header\n", progname); exit(1); } void puthead( /* put out header information */ FILE *fp ) { register int i; fprintf(fp, "# File created by: %s\n", progname); fprintf(fp, "# Input file: %s\n", fhead.filename); fprintf(fp, "# Input units: %s\n", fhead.length_u); fprintf(fp, "# Output units: meters\n"); fprintf(fp, "# Named layers:\n"); for (i = 0; i < 8; i++) if (fhead.layer[i] != NULL) fprintf(fp, "#\tLayer No. %d\t%s\n", i, fhead.layer[i]); } int getblock( /* get an Architrion block */ register BLOCK *bp, FILE *fp ) { char word[32]; int i; if (fgets(word, sizeof(word), fp) == NULL) return(EOF); if (strncmp(word, "Block", 5)) return(EOF); if (fscanf(fp, "1 %hd %hd %d", &bp->layer, &bp->color, &bp->nopenings) != 3) return(EOF); if (fgetid(&bp->refid, "\n", fp) == EOF) return(EOF); if (fscanf(fp, "1 %d %d %d %d %d %d %d %d\n", &bp->p.x[0], &bp->p.y[0], &bp->p.z[0], &bp->p.h[0], &bp->p.x[1], &bp->p.y[1], &bp->p.z[1], &bp->p.h[1]) != 8) return(EOF); if (fscanf(fp, "1 %d %d %d %d %d %d %d %d\n", &bp->p.x[2], &bp->p.y[2], &bp->p.z[2], &bp->p.h[2], &bp->p.x[3], &bp->p.y[3], &bp->p.z[3], &bp->p.h[3]) != 8) return(EOF); if (bp->nopenings == 0) { bp->opening = NULL; return(0); } bp->opening = (OPNG *)malloc(bp->nopenings*sizeof(OPNG)); if (bp->opening == NULL) goto memerr; for (i = 0; i < bp->nopenings; i++) if (getopening(&bp->opening[i], fp) < 0) return(EOF); return(0); memerr: fprintf(stderr, "%s: out of memory in getblock\n", progname); exit(1); } int getopening( /* read in opening from fp */ register OPNG *op, FILE *fp ) { register int c; char word[32]; if (fgets(word, sizeof(word), fp) == NULL) return(EOF); if (strncmp(word, "Opening", 7)) return(EOF); if (fscanf(fp, "2 %d %d %d %d %d %d %d %d\n", &op->p.x[0], &op->p.y[0], &op->p.z[0], &op->p.h[0], &op->p.x[1], &op->p.y[1], &op->p.z[1], &op->p.h[1]) != 8) return(EOF); if (fscanf(fp, "2 %d %d %d %d %d %d %d %d\n", &op->p.x[2], &op->p.y[2], &op->p.z[2], &op->p.h[2], &op->p.x[3], &op->p.y[3], &op->p.z[3], &op->p.h[3]) != 8) return(EOF); c = getc(fp); if (c == '3') { if (fscanf(fp, "%d %d", &op->corner, &op->depth) != 2) return(EOF); if (fgetid(&op->frame, "\n", fp) == EOF) return(EOF); } else { op->corner = -1; op->frame.name = NULL; if (c != EOF) ungetc(c, fp); } return(0); } void doneblock( /* free data associated with bp */ register BLOCK *bp ) { register int i; if (bp->nopenings > 0) { for (i = 0; i < bp->nopenings; i++) doneid(&bp->opening[i].frame); free((void *)bp->opening); } doneid(&bp->refid); } void add2quals( /* add to qualifier lists */ register BLOCK *bp ) { ID tmpid; if (fhead.layer[bp->layer] == NULL) { tmpid.name = NULL; tmpid.number = bp->layer; } else { tmpid.name = fhead.layer[bp->layer]; tmpid.number = 0; } findid(&qual[Q_LAY], &tmpid, 1); tmpid.name = NULL; tmpid.number = bp->color; findid(&qual[Q_COL], &tmpid, 1); findid(&qual[Q_REF], &bp->refid, 1); } void putblock( /* put out a block */ BLOCK *bp, FILE *fp ) { RULEHD *rp; char *mod[NFACES], *sillmod; int nmods, i; int donematch, newmatch; nmods = 0; sillmod = NULL; donematch = 0; for (rp = ourmap; rp != NULL; rp = rp->next) { newmatch = matchrule(bp, rp); /* test this rule */ newmatch &= ~donematch; /* don't repeat */ if (newmatch == 0) continue; mod[nmods++] = rp->mnam; if (sillmod == NULL && newmatch&F_SIL) sillmod = rp->mnam; putfaces(rp->mnam, bp, newmatch, fp); /* put out new faces */ donematch |= newmatch; if (donematch == (1<nopenings > 0) { putopenmod(sillmod, mod, nmods, fp); for (i = 0; i < bp->nopenings; i++) putopening(&bp->opening[i], fp); } if (ferror(fp)) { fprintf(stderr, "%s: write error in putblock\n", progname); exit(1); } } void putopenmod( /* put out opening modifier */ char *sm, char *ml[], int nm, FILE *fp ) { int rept, nrepts; register int i, j; if (sm == NULL) { /* if no sill modifier, use list */ sm = *ml++; nm--; } /* check for repeats */ rept = 0; nrepts = 0; for (i = 0; i < nm; i++) { if (ml[i] == sm || !strcmp(ml[i], VOIDID)) { rept |= 1<p; PRISM newp; register int i; /* copy original prism */ for (i = 0; i < 4; i++) { newp.x[i] = p->x[i]; newp.y[i] = p->y[i]; newp.z[i] = p->z[i]; newp.h[i] = p->h[i]; } /* spread reference and opposite */ if (p->x[2] > p->x[0]) { newp.x[0] -= 2; newp.x[1] -= 2; newp.x[2] += 2; newp.x[3] += 2; } else if (p->x[0] > p->x[2]) { newp.x[0] += 2; newp.x[1] += 2; newp.x[2] -= 2; newp.x[3] -= 2; } if (p->y[2] > p->y[0]) { newp.y[0] -= 2; newp.y[1] -= 2; newp.y[2] += 2; newp.y[3] += 2; } else if (p->y[0] > p->y[2]) { newp.y[0] += 2; newp.y[1] += 2; newp.y[2] -= 2; newp.y[3] -= 2; } /* put out faces */ sprintf(buf, "op%d", ++nopens); putface(openmod, buf, "ref", &newp, 4, 5, 1, 0, fp); putface(openmod, buf, "opp", &newp, 2, 6, 7, 3, fp); putface(openmod, buf, "end1", &newp, 5, 6, 2, 1, fp); putface(openmod, buf, "end2", &newp, 3, 7, 4, 0, fp); putface(openmod, buf, "bot", &newp, 1, 2, 3, 0, fp); putface(openmod, buf, "top", &newp, 7, 6, 5, 4, fp); } int matchrule( /* see if block matches this rule */ register BLOCK *bp, register RULEHD *rp ) { register int i; ID tmpid; if (rp->qflg & FL(Q_LAY)) { /* check layer */ tmpid.name = fhead.layer[bp->layer]; tmpid.number = bp->layer; if (!matchid(&tmpid, &idm(rp)[Q_LAY])) return(0); } if (rp->qflg & FL(Q_COL)) { /* check color */ tmpid.name = NULL; tmpid.number = bp->color; if (!matchid(&tmpid, &idm(rp)[Q_COL])) return(0); } if (rp->qflg & FL(Q_REF)) { /* check reference id */ if (!matchid(&bp->refid, &idm(rp)[Q_REF])) return(0); } if (rp->qflg & FL(Q_FAC)) { /* check faces */ for (i = 0; i < NFACES; i++) if (matchid(&faceId[i], &idm(rp)[Q_FAC])) return(1<p, 4, 5, 1, 0, fp); if (ff & 1<p, 2, 6, 7, 3, fp); if (ff & 1<p, 5, 6, 2, 1, fp); putface(m, bn, "end2", &bp->p, 3, 7, 4, 0, fp); } if (ff & 1<p, 1, 2, 3, 0, fp); if (ff & 1<p, 7, 6, 5, 4, fp); } char * blkname( /* think up a good name for this block */ register BLOCK *bp ) { static char nambuf[32]; static int blkcnt = 0; register char *nam; register int i, j; sprintf(nambuf, "l%d.", bp->layer); i = strlen(nambuf); nam = bp->refid.name; if (nam == NULL) { nam = fhead.layer[bp->layer]; if (nam != NULL) i = 0; } if (nam != NULL) { for (j = 0; j < 12 && nam[j]; j++) { if (nam[j] == ' ' || nam[j] == '\t') nambuf[i++] = '_'; else nambuf[i++] = nam[j]; } nambuf[i++] = '.'; } if (bp->refid.number != 0) { sprintf(nambuf+i, "r%d.", bp->refid.number); i = strlen(nambuf); } sprintf(nambuf+i, "b%d", ++blkcnt); return(nambuf); } void putface( /* put out a face */ char *m, char *bn, char *fn, PRISM *p, int a, int b, int c, int d, FILE *fp ) { int cf; cf = checkface(p, a, b, c, d); if (cf & QL_OK) { fprintf(fp, "\n%s polygon %s.%s\n", m, bn, fn); fprintf(fp, "0\n0\n12\n"); putpoint(p, a, fp); putpoint(p, b, fp); putpoint(p, c, fp); putpoint(p, d, fp); return; } if (cf & T1_OK) { fprintf(fp, "\n%s polygon %s.%sA\n", m, bn, fn); fprintf(fp, "0\n0\n9\n"); putpoint(p, d, fp); putpoint(p, a, fp); putpoint(p, b, fp); } if (cf & T2_OK) { fprintf(fp, "\n%s polygon %s.%sB\n", m, bn, fn); fprintf(fp, "0\n0\n9\n"); putpoint(p, b, fp); putpoint(p, c, fp); putpoint(p, d, fp); } } #define ldot(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]) void lcross( /* compute cross product */ register long vr[3], register long v1[3], register long v2[3] ) { vr[0] = v1[1]*v2[2] - v1[2]*v2[1]; vr[1] = v1[2]*v2[0] - v1[0]*v2[2]; vr[2] = v1[0]*v2[1] - v1[1]*v2[0]; } #define labs(a) ((a)>0 ? (a) : -(a)) int checkface( /* check a face for validity */ register PRISM *p, int a, int b, int c, int d ) { int rval = 0; long lt; long vc1[3], vc2[3], vt1[3], vt2[3]; long vc1l, vc2l, vc1vc2; /* check first triangle */ vt1[0] = p_x(p,b) - p_x(p,a); vt1[1] = p_y(p,b) - p_y(p,a); vt1[2] = p_z(p,b) - p_z(p,a); vt2[0] = p_x(p,d) - p_x(p,a); vt2[1] = p_y(p,d) - p_y(p,a); vt2[2] = p_z(p,d) - p_z(p,a); lcross(vc1, vt1, vt2); lt = labs(vc1[0]) + labs(vc1[1]) + labs(vc1[2]); if (lt > 1L<<18) lt = 16; else if (lt > 1L<<12) lt = 8; else lt = 0; if (lt) { vc1[0] >>= lt; vc1[1] >>= lt; vc1[2] >>= lt; } vc1l = ldot(vc1,vc1); if (vc1l > 4) rval |= T1_OK; /* check second triangle */ vt1[0] = p_x(p,d) - p_x(p,c); vt1[1] = p_y(p,d) - p_y(p,c); vt1[2] = p_z(p,d) - p_z(p,c); vt2[0] = p_x(p,b) - p_x(p,c); vt2[1] = p_y(p,b) - p_y(p,c); vt2[2] = p_z(p,b) - p_z(p,c); lcross(vc2, vt1, vt2); lt = labs(vc2[0]) + labs(vc2[1]) + labs(vc2[2]); if (lt > 1L<<18) lt = 16; else if (lt > 1L<<12) lt = 8; else lt = 0; if (lt) { vc2[0] >>= lt; vc2[1] >>= lt; vc2[2] >>= lt; } vc2l = ldot(vc2,vc2); if (vc2l > 4) rval |= T2_OK; /* check quadrilateral */ if (rval == (T1_OK|T2_OK)) { vc1vc2 = ldot(vc1,vc2); if (vc1vc2*vc1vc2 >= vc1l*vc2l-8) rval |= QL_OK; } return(rval); } void putpoint( /* put out a point */ register PRISM *p, int n, FILE *fp ) { register int i = n&3; fprintf(fp, ptfmt, p->x[i]*fhead.length_f, p->y[i]*fhead.length_f, (n&4 ? p->h[i] : p->z[i])*fhead.length_f); } void eputs( char *s ) { fputs(s, stderr); } void quit( int code ) { exit(code); }