ref: 61cc0694649a4d4b109d168032f431751f57f083
dir: /sys/src/cmd/pic/linegen.c/
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include "pic.h" #include "y.tab.h" obj *linegen(int type) { static double prevdx = HT; static double prevdy = 0; static double prevw = HT10; static double prevh = HT5; int i, j, some, head, ddtype, invis, chop, battr, with; double ddval, chop1, chop2, x0, y0, x1, y1; double fillval = 0; double theta; double defx, defy, xwith, ywith; obj *p, *ppos; static int xtab[] = { 1, 0, -1, 0 }; /* R=0, U=1, L=2, D=3 */ static int ytab[] = { 0, 1, 0, -1 }; double dx[500], dy[500]; int ndxy; double nx, ny; Attr *ap, *chop_ap[4]; nx = curx; ny = cury; defx = getfval("linewid"); defy = getfval("lineht"); prevh = getfval("arrowht"); prevw = getfval("arrowwid"); dx[0] = dy[0] = ndxy = some = head = invis = battr = with = 0; chop = chop1 = chop2 = 0; ddtype = ddval = xwith = ywith = 0; for (i = 0; i < nattr; i++) { ap = &attr[i]; switch (ap->a_type) { case TEXTATTR: savetext(ap->a_sub, ap->a_val.p); break; case HEAD: head += ap->a_val.i; break; case INVIS: invis = INVIS; break; case NOEDGE: battr |= NOEDGEBIT; break; case DOT: case DASH: ddtype = ap->a_type==DOT ? DOTBIT : DASHBIT; if (ap->a_sub == DEFAULT) ddval = getfval("dashwid"); else ddval = ap->a_val.f; break; case SAME: dx[ndxy] = prevdx; dy[ndxy] = prevdy; some++; break; case LEFT: dx[ndxy] -= (ap->a_sub==DEFAULT) ? defx : ap->a_val.f; some++; hvmode = L_DIR; break; case RIGHT: dx[ndxy] += (ap->a_sub==DEFAULT) ? defx : ap->a_val.f; some++; hvmode = R_DIR; break; case UP: dy[ndxy] += (ap->a_sub==DEFAULT) ? defy : ap->a_val.f; some++; hvmode = U_DIR; break; case DOWN: dy[ndxy] -= (ap->a_sub==DEFAULT) ? defy : ap->a_val.f; some++; hvmode = D_DIR; break; case HEIGHT: /* length of arrowhead */ prevh = ap->a_val.f; break; case WIDTH: /* width of arrowhead */ prevw = ap->a_val.f; break; case TO: if (some) { nx += dx[ndxy]; ny += dy[ndxy]; ndxy++; dx[ndxy] = dy[ndxy] = some = 0; } ppos = attr[i].a_val.o; if (ppos == NULL) ERROR "no tag defined for `to'" FATAL; dx[ndxy] = ppos->o_x - nx; dy[ndxy] = ppos->o_y - ny; some++; break; case BY: if (some) { nx += dx[ndxy]; ny += dy[ndxy]; ndxy++; dx[ndxy] = dy[ndxy] = some = 0; } ppos = ap->a_val.o; if (ppos == NULL) ERROR "no tag defined for `by'" FATAL; dx[ndxy] = ppos->o_x; dy[ndxy] = ppos->o_y; some++; break; case THEN: /* turn off any previous accumulation */ if (some) { nx += dx[ndxy]; ny += dy[ndxy]; ndxy++; dx[ndxy] = dy[ndxy] = some = 0; } break; case FROM: case AT: ppos = ap->a_val.o; if (ppos == NULL) ERROR "no tag defined for `from' or `at'" FATAL; nx = curx = ppos->o_x; ny = cury = ppos->o_y; break; case WITH: with = ap->a_val.i; break; case CHOP: if (ap->a_sub != PLACENAME) { if( chop == 0) chop1 = chop2 = ap->a_val.f; else chop2 = ap->a_val.f; } chop_ap[chop++] = ap; break; case FILL: battr |= FILLBIT; if (ap->a_sub == DEFAULT) fillval = getfval("fillval"); else fillval = ap->a_val.f; break; } } if (with) { /* this doesn't work at all */ switch (with) { case CENTER: xwith = (dx[1] - dx[0]) / 2; ywith = (dy[1] - dy[0]) / 2; break; } for (i = 0; i < ndxy; i++) { dx[i] -= xwith; dy[i] -= ywith; } curx += xwith; cury += ywith; } if (some) { nx += dx[ndxy]; ny += dy[ndxy]; ndxy++; defx = dx[ndxy-1]; defy = dy[ndxy-1]; } else { defx *= xtab[hvmode]; defy *= ytab[hvmode]; dx[ndxy] = defx; dy[ndxy] = defy; ndxy++; nx += defx; ny += defy; } prevdx = defx; prevdy = defy; if (chop) { if (chop == 1 && chop1 == 0) /* just said "chop", so use default */ chop1 = chop2 = getfval("circlerad"); theta = atan2(dy[0], dx[0]); x0 = chop1 * cos(theta); y0 = chop1 * sin(theta); curx += x0; cury += y0; dx[0] -= x0; dy[0] -= y0; theta = atan2(dy[ndxy-1], dx[ndxy-1]); x1 = chop2 * cos(theta); y1 = chop2 * sin(theta); nx -= x1; ny -= y1; dx[ndxy-1] -= x1; dy[ndxy-1] -= y1; dprintf("chopping %g %g %g %g; cur=%g,%g end=%g,%g\n", x0, y0, x1, y1, curx, cury, nx, ny); } p = makenode(type, 5 + 2 * ndxy); curx = p->o_val[0] = nx; cury = p->o_val[1] = ny; if (head || type == ARROW) { p->o_nhead = getfval("arrowhead"); p->o_val[2] = prevw; p->o_val[3] = prevh; if (head == 0) head = HEAD2; /* default arrow head */ } p->o_attr = head | invis | ddtype | battr; p->o_fillval = fillval; p->o_val[4] = ndxy; nx = p->o_x; ny = p->o_y; for (i = 0, j = 5; i < ndxy; i++, j += 2) { p->o_val[j] = dx[i]; p->o_val[j+1] = dy[i]; if (type == LINE || type == ARROW) extreme(nx += dx[i], ny += dy[i]); else if (type == SPLINE && i < ndxy-1) { /* to compute approx extreme of spline at p, /* compute midway between p-1 and p+1, /* then go 3/4 from there to p */ double ex, ey, xi, yi, xi1, yi1; xi = nx + dx[i]; yi = ny + dy[i]; /* p */ xi1 = xi + dx[i+1]; yi1 = yi + dy[i+1]; /* p+1 */ ex = (nx+xi1)/2; ey = (ny+yi1)/2; /* midway */ ex += 0.75*(xi-ex); ey += 0.75*(yi-ey); extreme(ex, ey); nx = xi; ny = yi; } } p->o_ddval = ddval; if (dbg) { printf("S or L from %g %g to %g %g with %d elements:\n", p->o_x, p->o_y, curx, cury, ndxy); for (i = 0, j = 5; i < ndxy; i++, j += 2) printf("%g %g\n", p->o_val[j], p->o_val[j+1]); } extreme(p->o_x, p->o_y); extreme(curx, cury); return(p); }