V10/cmd/picasso/misc.c
/* 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;
}