aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/pic/linegen.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/pic/linegen.c')
-rw-r--r--src/cmd/pic/linegen.c240
1 files changed, 240 insertions, 0 deletions
diff --git a/src/cmd/pic/linegen.c b/src/cmd/pic/linegen.c
new file mode 100644
index 00000000..eab268f5
--- /dev/null
+++ b/src/cmd/pic/linegen.c
@@ -0,0 +1,240 @@
+#include <stdio.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;
+ 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;
+ 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;
+ 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);
+}