/* 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:print.c 1.0 */ #include <assert.h> #include <ctype.h> #include <string.h> #include "picasso.h" #include "y.tab.h" extern int eqn_count; int flyback; int redo_gbox = 0; int objcount = 0; print_buf() { int n; obj *p; if (++objcount > objbuf) { p = objhead->o_next; if (p->o_type != BLOCK) print_obj(p->o_layer, p); else if (p->o_val[N_VAL].o == (obj *)0) return; else for (n = draftlayer; n <= top_layer; n++) print_obj(n,p); freenode(p); } } extern FILE *pipefp, *eqnfp; extern char psfname[]; print(c) /* show everything (above draft layers) */ int c; { int n; /* Added 10/15/90--DBK. Is there any reason NOT to do this? */ redo_gbox = 1; if (pipefp) { pclose(pipefp); pipefp = NULL; if ((eqnfp = fopen(psfname,"r")) == NULL) fatal("cannot read eqn output"); } flyback = (c == 'F'); if (c != 'N') for (n = draftlayer; n <= top_layer; ++n) print_layer(n); if (eqnfp) { fclose(eqnfp); eqnfp = NULL; eqn_count = 0; unlink(psfname); } } print_layer(n) /* show contents of a single layer (maybe a draft layer) */ int n; { obj *p; for (p = objhead->o_next; p!= objtail; p = p->o_next) p = print_obj(n, p); } print_bnd(p, q) /* show everything (non-draft) between given bounds */ obj *p, *q; { int n; for (n = draftlayer; n <= top_layer; ++n) print_layer_bnd(n, p, q); } print_layer_bnd(n, p, q) /* show objects in layer n from p to q */ int n; obj *p, *q; { obj *r; float x0, y0, x1, y1, bnd[4]; if (p->o_x < q->o_x) { x0 = p->o_x; x1 = q->o_x; } else { x0 = q->o_x; x1 = p->o_x; } if (p->o_y < q->o_y) { y0 = p->o_y; y1 = q->o_y; } else { y0 = q->o_y; y1 = p->o_y; } for (r = objhead->o_next; r!= objtail; r = r->o_next) if (r->o_x >= x0 && r->o_x <= x1 && r->o_y >= y0 && r->o_y <= y1) r = print_obj(n, r); } obj *print_obj(layer, p) int layer; obj *p; { double r, dx, dy, ox, oy, x0, y0, x1, y1; obj *q; int n; if (redo_gbox) { float bnd[4]; Gbox[2] = Gbox[3] = -(Gbox[0] = Gbox[1] = 32767); for (q = objhead->o_next; q != objtail; q = q->o_next) { get_bounds(q, bnd, 1); track_bounds (bnd[0], bnd[1], bnd[2], bnd[3]); if (q->o_type == BLOCK) q = q->o_val[N_VAL].o; } redo_gbox = 0; } openpl(""); if (p->o_type != BLOCK && p->o_layer != layer) return p; if (p->o_type <= TEXT && (p->o_mxx!=1 || p->o_myy!=1 || p->o_mxy!=0 || p->o_myx!=0 || p->o_mxt!=0 || p->o_myt!=0)) return print_xform(layer,p); ox = p->o_x; oy = p->o_y; if (p->o_type < TEXT && (p->o_attr & (FILLED | EDGED))) chk_attrs (p); switch (p->o_type) { case TROFF: n = p->o_nt1; if (text[n].t_type & EQNTXT) puteqn(ox, oy, text[n].t_type, atoi(text[n].t_val)); else troff(text[n].t_val); return p; case BLOCK: for (q = p->o_next; q != p->o_val[N_VAL].o; q = q->o_next) if (q->o_type <= TEXT || q->o_nt2 > q->o_nt1) q = print_obj(layer,q); p = q; break; case PSFILE: puteps(p); /* CAREFUL!! THIS FLOWS THROUGH INTO BOX!! */ case BOX: if (p->o_attr & (FILLED|EDGED)) { x0 = ox - p->o_wid/2; x1 = ox + p->o_wid/2; y0 = oy - p->o_ht/2; y1 = oy + p->o_ht/2; r = p->o_val[N_VAL].f; box(x0, y0, x1, y1, r); } break; case CIRCLE: case ELLIPSE: if (p->o_attr & (FILLED|EDGED)) ellipse(ox,oy,p->o_wid/2,0.,0.,p->o_ht/2,0.,2*M_PI,0); break; case SECTOR: case ARC: if (p->o_attr & (FILLED|EDGED)) { register double ang1, ang2; if (p->o_attr & HEAD12) { print_xform(layer, p); break; } r = p->o_val[N_VAL+0].f; x0 = p->o_val[N_VAL+2].f; /* starting point */ y0 = p->o_val[N_VAL+3].f; x1 = p->o_val[N_VAL+4].f; /* ending point */ y1 = p->o_val[N_VAL+5].f; ang1 = atan2(y0-oy, x0-ox); ang2 = atan2(y1-oy, x1-ox); ellipse(ox, oy, r, 0., 0., r, ang1, ang2, p->o_type); } break; case LINE: case ARROW: case SPLINE: if (p->o_attr & (FILLED|EDGED)) { int c, nxy; if (p->o_attr & HEAD12) { print_xform(layer, p); break; } r = p->o_val[N_VAL+0].f; nxy = p->o_val[N_VAL+3].f; /* segment count */ x0 = p->o_val[N_VAL+4].f; /* first point */ y0 = p->o_val[N_VAL+5].f; x1 = p->o_val[N_VAL+4+2*nxy].f; /* last point */ y1 = p->o_val[N_VAL+5+2*nxy].f; c = (x0 == x1 && y0 == y1); /* flags closure */ if (nxy == 1) line(x0, y0, x1, y1); else if (p->o_type == SPLINE) spline(nxy, c, &p->o_val[N_VAL+4]); else pline (nxy, c, &p->o_val[N_VAL+4], r); } break; } if (p->o_nt1 < p->o_nt2) objtext(ox, oy, p); return p; } obj *print_xform (layer,p) int layer; obj *p; { double r, ox, oy, dx, dy, x0, y0, x1, y1, M[4]; double b, tx0, ty0, tx1, ty1; valtype *X; obj *q; int n; if (p->o_type == BLOCK) { for (q = p->o_next; q != p->o_val[N_VAL].o; q = q->o_next) if (q->o_type <= TEXT || q->o_nt2 > q->o_nt1) q = print_xform(layer,q); p = q; } if (p->o_layer != layer && p->o_type != BLOCK) return p; #if 0 if (p->o_type == TEXT) { ox = Xformx(p->o_parent, 1, p->o_x, p->o_y); oy = Xformy(p->o_parent, 0, p->o_x, p->o_y); } else { #endif ox = Xformx(p, 1, p->o_x, p->o_y); oy = Xformy(p, 0, p->o_x, p->o_y); #if 0 } #endif X = (valtype *)0; if (p->o_type < TEXT && (p->o_attr & (FILLED | EDGED))) chk_attrs (p); switch (p->o_type) { case TROFF: n = p->o_nt1; if (text[n].t_type & EQNTXT) puteqn(ox, oy, text[n].t_type, atoi(text[n].t_val)); else troff(text[n].t_val); return p; case PSFILE: puteps(p); /* CAREFUL!! THIS FLOWS THROUGH INTO BOX!! */ case BOX: if (p->o_attr & (FILLED|EDGED)) { if ((X = (valtype *)malloc(10*sizeof(valtype))) == NULL) yyerror("out of room in print_xform"); r = p->o_val[N_VAL].f; X[6].f = X[0].f = -(X[2].f = X[4].f = p->o_wid/2); X[1].f = X[3].f = -(X[5].f = X[7].f = p->o_ht/2); for (n = 0; n < 8; n += 2) { x1 = ox + Linx(p, 0, X[n].f, X[n+1].f); X[n+1].f = oy + Liny(p, 0, X[n].f, X[n+1].f); X[n].f = x1; } X[n] = X[0]; X[++n] = X[1]; x1 = Linx(p, 0, r, 0.); r = Liny(p, 0, r, 0.); r = sqrt(x1 * x1 + r * r); pline(4, 1, X, r); } break; case CIRCLE: case ELLIPSE: if (p->o_attr & (FILLED|EDGED)) { get_matrix(&x0, &y0, &x1, &y1); x0 *= p->o_wid/2; y0 *= p->o_wid/2; x1 *= p->o_ht/2; y1 *= p->o_ht/2; ellipse(ox, oy, x0, y0, x1, y1, 0., 2*M_PI, 0); } break; case SECTOR: case ARC: if (p->o_attr & (FILLED|EDGED)) { register double ang1, ang2; double xa, ya; double dx0, dy0, dx1, dy1; r = p->o_val[N_VAL+0].f; x0 = p->o_val[N_VAL+2].f; /* starting point */ y0 = p->o_val[N_VAL+3].f; x1 = p->o_val[N_VAL+4].f; /* ending point */ y1 = p->o_val[N_VAL+5].f; get_matrix(M, M+1, M+2, M+3); /* * If there are arrowheads and non-zero line thickness, we * should adjust the end points so as to get nice arrowheads. */ if (p->o_attr & HEAD12) { dx0 = Xformx(p, 1, x0, y0); /* Remember */ dy0 = Xformy(p, 0, x0, y0); /* directions for */ dx1 = Xformx(p, 0, x1, y1); /* arrowheads */ dy1 = Xformy(p, 0, x1, y1); /* in here we need to change the points used to compute the angles. */ dx = p->o_val[N_VAL+8].f; dy = p->o_val[N_VAL+9].f; if (p->o_weight > 0.) { double linex, liney, a; b = p->o_weight / 2 / p->o_val[N_VAL+8].f; b *= sqrt(dx*dx + 4*dy*dy); if (p->o_attr & HEAD2) { linex = - (y1 - p->o_y); liney = (x1 - p->o_x); a = b / sqrt(linex*linex + liney*liney); x1 -= a * linex; y1 -= a * liney; } if (p->o_attr & HEAD1) { linex = (y0 - p->o_y); liney = - (x0 - p->o_x); a = b / sqrt(linex*linex + liney*liney); x0 -= a * linex; y0 -= a * liney; } } } tx0 = Xformx(p, 1, x0, y0); /* transformed starting point */ ty0 = Xformy(p, 0, x0, y0); tx1 = Xformx(p, 0, x1, y1); /* transformed ending point */ ty1 = Xformy(p, 0, x1, y1); ang1 = atan2(ty0 - oy, tx0 - ox); ang2 = atan2(ty1 - oy, tx1 - ox); dx = M[0] * M[3] - M[1] * M[2]; if (dx < 0) { /* reflection */ xa = ang1; ang1 = ang2; ang2 = xa; M[0] = -M[0]; M[2] = -M[2]; } ellipse(ox, oy, r*M[0], r*M[1], r*M[2], r*M[3], ang1, ang2, p->o_type); if (p->o_attr & (HEAD1 | HEAD2)) { ang1 = 0; if (dx < 0) { ang1 = M_PI; dx = -dx; } dy = dx = sqrt(dx); dx *= p->o_val[N_VAL+8].f; dy *= p->o_val[N_VAL+9].f; if (p->o_attr & HEAD1) arrow(tx0-(dy0-oy), ty0+(dx0-ox), tx0, ty0, dx, dy, dy/r/2 + ang1, p->o_attr); if (p->o_attr & HEAD2) arrow(tx1+(dy1-oy), ty1-(dx1-ox), tx1, ty1, dx, dy, -dy/r/2 + ang1, p->o_attr); } } break; case LINE: case ARROW: case SPLINE: if (p->o_attr & (FILLED|EDGED)) { int c, i, nxy; r = p->o_val[N_VAL+0].f; x1 = Linx(p, 0, r, 0.); r = Liny(p, 0, r, 0.); r = sqrt(x1 * x1 + r * r); nxy = p->o_val[N_VAL+3].f; /* segment count */ X = (valtype *)malloc((2*nxy+2)*sizeof(valtype)); if (X == NULL) yyerror("out of room in print_xform"); for (i = 0, n = N_VAL+4; i <= 2 * nxy; ) { register double xx = p->o_val[n++].f, yy = p->o_val[n++].f; X[i++].f = Xformx(p, 0, xx, yy); X[i++].f = Xformy(p, 0, xx, yy); } x0 = X[0].f; y0 = X[1].f; x1 = X[i-2].f; y1 = X[i-1].f; tx0 = ty0 = tx1 = ty1 = 0.; n = 2 * nxy - 2; if (p->o_attr & HEAD12) { get_matrix(M, M+1, M+2, M+3); /* DBK: I added the fabs to eliminate sqrt errors * and make it same as xprint.c. 9/20/90 */ dy = dx = sqrt(fabs(M[0]*M[3] - M[1]*M[2])); dx *= p->o_val[N_VAL+1].f; dy *= p->o_val[N_VAL+2].f; if (p->o_weight > 0.) { double linex, liney, a; b = p->o_weight / 2 / p->o_val[N_VAL+1].f; b *= sqrt(dx*dx + 4*dy*dy); if (p->o_attr & HEAD2) { linex = x1 - X[n].f; liney = y1 - X[n+1].f; a = b / sqrt(linex*linex + liney*liney); tx1 = -a * linex; ty1 = -a * liney; x1 = X[n+2].f += tx1; y1 = X[n+3].f += ty1; } if (p->o_attr & HEAD1) { linex = x0 - X[2].f; liney = y0 - X[3].f; a = b / sqrt(linex*linex + liney*liney); tx0 = -a * linex; ty0 = -a * liney; x0 = X[0].f += tx0; y0 = X[1].f += ty0; } } } /* The first two args are just to give a direction to * the second two. To make sure that the direction * isn't reversed, adjust the first two by the same * amount as we adjusted x1 and y1 above. */ c = (x0 == x1 && y0 == y1); /* flags closure */ if (nxy == 1) line(X[0].f, X[1].f, X[2].f, X[3].f); else if (p->o_type == SPLINE) spline(nxy, c, X); else pline (nxy, c, X, r); if (p->o_attr & HEAD2) { tx1 += X[n].f; ty1 += X[n+1].f; arrow(tx1, ty1, x1, y1, dx, dy, 0.0, p->o_attr); } if (p->o_attr & HEAD1) { tx0 += X[2].f; ty0 += X[3].f; arrow(tx0, ty0, x0, y0, dx, dy, 0.0, p->o_attr); } } break; case TEXT: tmp_xform(p); #if 0 dotext(ox, oy, p); #else dotext(p->o_x, p->o_y, p); #endif undo_tmpx(); return p; } if (X) free(X); if (p->o_nt1 < p->o_nt2) objtext(ox, oy, p); return p; } objtext(x, y, p) double x, y; obj *p; { double *bnd; int i, t; t = text[p->o_nt1].t_type; for (i = p->o_nt1; i < p->o_nt2; i++) if (text[i].t_type != t) break; if (i >= p->o_nt2 && p->o_type != TEXT) { /* all strings same type */ bnd = text_bounds(p); if (t & RJUST) x += (bnd[2] - bnd[0]) / 2; if (t & LJUST) x -= (bnd[2] - bnd[0]) / 2; } dotext(x, y, p); } dotext(x, y, p) /* print text strings of p in proper vertical spacing */ double x, y; obj *p; { double h, v, w, dely; int i, j, n, t; i = p->o_nt1; j = text[i].t_line; /* sequence # of first line */ n = text[p->o_nt2-1].t_line - j; /* total number of lines (-1) */ v = abs(text[i].t_size) / (2 * pgscale); dely = abs(text[i].t_space) / (2 * pgscale); v = n * dely - v/2; new_color(p->o_text); for (h = w = 0; i < p->o_nt2; ++j, v -= 2*dely, h = w = 0) { t = text[i].t_type; if (t & ABOVE) v += dely; else if (t & BELOW) v -= dely; for (n = i; text[n].t_line == j; n++) w += text[n].t_width*72/pgscale; if (t & RJUST) h = w; else if (t & CENTER) h = w/2; newlabel(t, text[i].t_val, abs(text[i].t_font), x-h, y+v, text[i].t_size / pgscale, text[i].t_width * 72 / pgscale); while (++i < n) addlabel(text[i].t_type, text[i].t_val, text[i].t_font, text[i].t_size / pgscale, text[i].t_width * 72 / pgscale); } }