/* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */ /* The copyright notice above does not evidence any */ /* actual or intended publication of such source code. */ /* @(#)picasso:misc.c 1.0 */ #include "picasso.h" #include "y.tab.h" extern int pic_compat; extern int batch; double getcomp(p, t) /* return component of a position; these must now be */ obj *p; /* transformed as there is no later chance to do so. */ int t; { float bnd[4]; switch (t) { case DOTX: return Xformx(p, 1, p->o_x, p->o_y); case DOTY: return Xformy(p, 1, p->o_x, p->o_y); case DOTRAD: switch (p->o_type) { case SECTOR: case ARC: case BOX: case ARROW: case LINE: return p->o_val[N_VAL].f; case CIRCLE: case ELLIPSE: break; /* fall through to DOTWID case */ } case DOTHT: case DOTWID: if (p->o_type <= TEXT) { get_bounds(p, bnd, 1); if (t == DOTHT) return (bnd[3] - bnd[1]); else return (bnd[2] - bnd[0]); } } yyerror("can't happen getcomp"); } exprsave(f) double f; { if (nexpr >= nexprlist) exprlist = (float *) grow((char *)exprlist, "exprlist", nexprlist += 256, sizeof(float)); exprlist[nexpr] = f; return ++nexpr; } char *sprintgen(fmt) char *fmt; { char buf[1000]; sprintf (buf, fmt, exprlist[0], exprlist[1], exprlist[2], exprlist[3], exprlist[4]); nexpr = 0; free(fmt); return tostring(buf); } printexpr(f) /* print expression for debugging */ double f; { fprintf(stderr, "%g\n", f); } printpos(p) /* print position for debugging */ obj *p; { double x, y; x = Xformx(p, 1, p->o_x, p->o_y); y = Xformy(p, 0, p->o_x, p->o_y); fprintf(stderr, "%g, %g\n", x, y); } char *tostring(s) register char *s; { register char *p; p = malloc(strlen(s)+1); if (p == NULL) { yyerror("out of space in tostring on %s", s); exit(1); } strcpy(p, s); return(p); } obj *makepos(x, y, corner, q) /* make a position cell */ double x, y; int corner; obj *q; { obj *p; p = makenode(PLACE, 1, 0); if (q) p->o_parent = q; p->o_x = x; p->o_y = y; p->o_val[0].f = corner; return(p); } obj *makebetween(f, p1, p2) /* make position between p1 and p2 */ double f; /* again, transforms must be applied */ obj *p1, *p2; { obj *p; double x1, y1, x2, y2; p = makenode(PLACE, 3, 0); x1 = Xformx(p1, 1, p1->o_x, p1->o_y); y1 = Xformy(p1, 0, p1->o_x, p1->o_y); x2 = Xformx(p2, 1, p2->o_x, p2->o_y); y2 = Xformy(p2, 0, p2->o_x, p2->o_y); p->o_x = x1 + f * (x2 - x1); p->o_y = y1 + f * (y2 - y1); p->o_val[0].f = f; p->o_val[1].o = p1; p->o_val[2].o = p2; return(p); } int xdelta[8] = {1,1,1,0,-1,-1,-1,0}, ydelta[8] = {-1,0,1,1,1,0,-1,-1}; obj *getnth(p, nth) /* find nth point of an object */ obj *p; int nth; { float x, y; int n = nth; switch (p->o_type) { default: if (n != 1) yyerror("object has only 1 point defined"); return p; case ARC: if (n > 2) { yyerror("arcs have only 2 points defined"); return p; } /* else fall through to SECTOR case */ case SECTOR: if ((n %= 3) == 0) return p; else if (n == 1) { x = p->o_val[N_VAL+2].f; y = p->o_val[N_VAL+3].f; } else { x = p->o_val[N_VAL+4].f; y = p->o_val[N_VAL+5].f; } break; case BLOCK: while (n--) { p = p->o_next; if (p->o_type <= TEXT) continue; else if (p->o_type == BLOCKEND) { yyerror("[] has less than %d objects", nth); p = p->o_parent; } } return p; case BOX: n %= 8; x = p->o_x + xdelta[n] * p->o_wid / 2; y = p->o_y + ydelta[n] * p->o_ht / 2; break; case ARROW: case LINE: case SPLINE: if (--n > p->o_val[N_VAL+3].f) { yyerror("line has less than %d points", nth); return p; } x = p->o_val[N_VAL + 4 + 2 * n].f; y = p->o_val[N_VAL + 5 + 2 * n].f; break; case CIRCLE: case ELLIPSE: n %= 8; x = xdelta[n] * p->o_wid / 2; y = ydelta[n] * p->o_ht / 2; if (n % 2 == 0) { x *= M_SQRT1_2; y *= M_SQRT1_2; } x += p->o_x; y += p->o_y; break; } /* DBK--Here also there is a question of whether x and y should be transformed */ return makepos(x, y, nth, p); } obj *getpos(p, corner) /* find position of point */ obj *p; int corner; { float x, y; if (pic_compat && (p->o_type == CIRCLE || p->o_type == ELLIPSE) && (corner == NE || corner == NW || corner == SW || corner == SE)) return getnth(p, corner == NE ? 2 : corner == NW ? 4 : corner == SW ? 6 : 8); if (corner == -1 ) if (pic_compat && (p->o_type == LINE || p->o_type == ARROW || p->o_type == SPLINE)) corner = START; else return p; whatpos(p, corner, &x, &y); return makepos(x,y,corner,(corner < EAST || corner > SW)? p: (obj *)0); } whatpos(p, corner, px, py) /* what is the position (no side effect) */ obj *p; int corner; float *px, *py; { float x, y, bnd[4]; if (corner >= EAST && corner <= SW) { get_bounds(p, bnd, 1); switch (corner) { case NE: x = bnd[2]; y = bnd[3]; break; case SW: x = bnd[0]; y = bnd[1]; break; case SE: x = bnd[2]; y = bnd[1]; break; case NW: x = bnd[0]; y = bnd[3]; break; case NORTH: x = (bnd[0]+bnd[2])/2; y = bnd[3]; break; case SOUTH: x = (bnd[0]+bnd[2])/2; y = bnd[1]; break; case EAST: x = bnd[2]; y = (bnd[1]+bnd[3])/2; break; case WEST: x = bnd[0]; y = (bnd[1]+bnd[3])/2; break; } } else { /* DBK--note that get_bounds returns the transformed position, but the following calculations do not!! */ x = p->o_x; y = p->o_y; /* futz around for special cases: */ switch (p->o_type) { case BLOCK: if (corner == START) whatpos(p->o_next, START, &x, &y); else if (corner == END) whatpos(p->o_val[N_VAL+1].o->o_prev,END,&x,&y); break; case ARC: if (corner == START) { x = p->o_val[N_VAL+2].f; y = p->o_val[N_VAL+3].f; } else if (corner == END) { x = p->o_val[N_VAL+4].f; y = p->o_val[N_VAL+5].f; } break; case LINE: case SPLINE: case ARROW: switch (corner) { int n; case START: x = p->o_val[N_VAL+4].f; y = p->o_val[N_VAL+5].f; break; case END: n = N_VAL + 4 + 2*p->o_val[N_VAL+3].f; x = p->o_val[n].f; y = p->o_val[n+1].f; break; } break; } } *px = x; *py = y; return 1; } obj *gethere() /* make a place for curx,cury */ { return(makepos(curx, cury, 0, (obj *)0)); } obj *getlast(n, t) /* find n-th previous occurrence of type t */ int n, t; { int k; obj *p; k = n; if (t == TEXTOBJ) /* for purely syntactical reasons */ t = TEXT; for (p = objtail->o_prev; p != objhead; p = p->o_prev) { if (p->o_type == BLOCKEND) { p = p->o_parent; if (t != BLOCK && t != OBJECT) continue; } if (t == OBJECT && p->o_type > TEXT) continue; if (t != OBJECT && p->o_type != t) continue; if (--k > 0) continue; /* not there yet */ return(p); } yyerror("there is no %dth last", n); return(NULL); } obj *getfirst(n, t) /* find n-th occurrence of type t */ int n, t; { int k; obj *p; k = n; if (t == TEXTOBJ) t = TEXT; for (p = objhead->o_next; p != objtail; p = p->o_next) { if (p->o_type == BLOCK && t != BLOCK && t != OBJECT) { /* skip block, */ if (p->o_val[N_VAL].o != NULL) /* unless it's */ p = p->o_val[N_VAL].o; /* still active */ continue; } if (t == OBJECT && p->o_type > TEXT) continue; if (t != OBJECT && p->o_type != t) continue; if (--k > 0) continue; /* not there yet */ return(p); } yyerror("there is no %dth", n); return(NULL); } double getblkvar(p, s) /* find variable s2 in block p */ obj *p; char *s; { YYSTYPE y, getblk(); y = getblk(p, s); free(s); return y.f; } obj *getblock(p, s) /* find variable s in block p */ obj *p; char *s; { YYSTYPE y, getblk(); y = getblk(p, s); free(s); return y.o; } YYSTYPE getblk(p, s) /* find union type for s in p */ obj *p; char *s; { static YYSTYPE bug; struct symtab *stp; if (p->o_type != BLOCK) { yyerror(".%s is not in that block", s); return(bug); } for (stp = p->o_val[N_VAL+1].s; stp != NULL; stp = stp->s_next) if (strcmp(s, stp->s_name) == 0) return(stp->s_val); yyerror("there is no .%s in that []", s); return(bug); } obj *fixpos(p, x, y) /* this, addpos & subpos SHOULD be altered to give */ obj *p; /* o_x,o_y as offset from position of p, with p as */ double x, y; /* o_parent, but I haven't yet worked out the xform. */ { #if 1 /* DBK: 3/21/90 -- comment out the following if clause. It has the effect of changing A in the expression A + x,y !!! if (p->o_type == PLACE) { p->o_x += x; p->o_y += y; return p; } end of commented out code *************/ x += Xformx(p, 1, p->o_x, p->o_y); y += Xformy(p, 0, p->o_x, p->o_y); #else if (p->o_type == PLACE) { x += p->o_x; y += p->o_y; } else { x += Xformx(p, 1, p->o_x, p->o_y); y += Xformy(p, 0, p->o_x, p->o_y); } #endif return makepos(x, y, 0, (obj *)0); } obj *addpos(p, q) obj *p, *q; { double x, y; x = Xformx(q, 1, q->o_x, q->o_y); y = Xformy(q, 0, q->o_x, q->o_y); /* DBK: see above if (p->o_type == PLACE) { p->o_x += x; p->o_y += y; return p; } */ x += Xformx(p, 1, p->o_x, p->o_y); y += Xformy(p, 0, p->o_x, p->o_y); return makepos(x, y, 0, (obj *)0); } obj *subpos(p, q) obj *p, *q; { double x, y; x = Xformx(q, 1, q->o_x, q->o_y); y = Xformy(q, 0, q->o_x, q->o_y); /* DBK: see above if (p->o_type == PLACE) { p->o_x -= x; p->o_y -= y; return p; } */ x -= Xformx(p, 1, p->o_x, p->o_y); y -= Xformy(p, 0, p->o_x, p->o_y); return makepos(x, y, 0, (obj *)0); } obj *makenode(type, n, layer) int type, n, layer; { obj *p; if (objbuf && batch) print_buf(); p = (obj *) calloc(1, sizeof(obj) + (n-1)*sizeof(YYSTYPE)); if (p == NULL) { yyerror("out of space in makenode"); exit(1); } if (n > 65535) yyerror("making excessively large object"); p->o_next = objtail; p->o_prev = objtail->o_prev; p->o_prev->o_next = objtail->o_prev = p; p->o_parent = cur_block; p->o_x = curx; p->o_y = cury; p->o_nt1 = ntext1; p->o_nt2 = ntext; p->o_text = -1; #if 1 /* force all strings in object to have same justification */ { int jflags, lastf; jflags = RJUST|LJUST|CENTER|ABOVE|BELOW; lastf = text[ntext-1].t_type & jflags; for ( ; ntext1 < ntext; ntext1++) text[ntext1].t_type = text[ntext1].t_type & ~ jflags | lastf; } #endif ntext1 = ntext; /* ready for next caller */ if (layer < -128) layer = -128; else if (layer > 127) layer = 127; if ((p->o_layer = layer) > 0 && layer > top_layer) top_layer = layer; if ((p->o_type = type) <= TEXT) { p->o_mxx = p->o_myy = 1.0; /* initialize xform matrix */ p->o_size = n; /* keep count, for copies */ } return(p); } freenode (p) /* free space occupied by object p */ obj *p; { obj *q, *q1; if (p->o_type == BLOCK) { /* I think there's */ freesymtab(p->o_val[N_VAL+1].s); /* a bug here, for */ q = p->o_val[N_VAL].o; /* nested blocks. */ p->o_prev->o_next = q->o_next; q->o_next->o_prev = p->o_prev; q->o_next = (obj *)NULL; for (q = p->o_next; q != NULL; ) { if (q->o_type == BLOCK) freesymtab(q->o_val[N_VAL+1].s); q1 = q; q = q->o_next; free(q1); } } else { p->o_prev->o_next = p->o_next; p->o_next->o_prev = p->o_prev; } free (p); if (!objbuf) redo_gbox = 1; /* page boundaries are now suspect */ } extreme(x, y, bbox) /* record max and min x and y values */ double x, y; float *bbox; { if ((float)x < bbox[0]) bbox[0] = x; if ((float)y < bbox[1]) bbox[1] = y; if ((float)x > bbox[2]) bbox[2] = x; if ((float)y > bbox[3]) bbox[3] = y; } track_bounds(x0, y0, x1, y1) /* insert a bounding box into the global box */ double x0, y0, x1, y1; { if (x0 < Gbox[0]) Gbox[0] = x0; if (y0 < Gbox[1]) Gbox[1] = y0; if (x1 > Gbox[2]) Gbox[2] = x1; if (y1 > Gbox[3]) Gbox[3] = y1; } get_bounds(p, bbox, flag) /* reconstruct bounding box from center/basis/xform */ obj *p; float *bbox; int flag; { static obj *lastp = (obj *)0; static double x0, y0, x1, y1; double w, h, wm, hm, x, y; double owid, oht; if (flag && p == lastp) goto done; x = Xformx(p, 1, p->o_x, p->o_y); y = Xformy(p, 0, p->o_x, p->o_y); if (p->o_type > TEXT) { x0 = x1 = x; y0 = y1 = y; } else { if (p->o_type == TEXT) { x += Linx(p,0,p->o_val[N_VAL-2].f,p->o_val[N_VAL-1].f); y += Liny(p,0,p->o_val[N_VAL-2].f,p->o_val[N_VAL-1].f); } else if (p->o_type == ARC || p->o_type == SECTOR) { x -= Linx(p,0,p->o_val[N_VAL+6].f,p->o_val[N_VAL+7].f); y -= Liny(p,0,p->o_val[N_VAL+6].f,p->o_val[N_VAL+7].f); } owid = p->o_wid + p->o_weight; oht = p->o_ht + p->o_weight; if ( ( p->o_type == ARROW || p->o_type == LINE || p->o_type == SPLINE || p->o_type == ARC) && (p->o_attr & HEAD12)) { w = p->o_val[N_VAL+(p->o_type == ARC ? 8 : 1)].f; owid += w; /* account for width of arrowheads */ oht += w; } w = Linx(p, 0, owid, oht) / 2; /* transform main diagonal */ h = Liny(p, 0, owid, oht) / 2; wm = Linx(p, 0, -owid, oht) / 2; /* transform other diagonal */ hm = Liny(p, 0, -owid, oht) / 2; if (w < 0) w = -w; if (h < 0) h = -h; if (wm < 0) wm = -wm; if (hm < 0) hm = -hm; if (w < wm) w = wm; if (h < hm) h = hm; x0 = x - w; x1 = x + w; y0 = y - h; y1 = y + h; } lastp = p; done: bbox[0] = x0; bbox[1] = y0; bbox[2] = x1; bbox[3] = y1; }