xref: /plan9/sys/src/cmd/pic/linegen.c (revision 392dc26962a4986819d746514f28dfe13b47a3d3)
13e12c5d1SDavid du Colombier #include <stdio.h>
2*392dc269SDavid du Colombier #include <string.h>
3*392dc269SDavid du Colombier #include <stdlib.h>
43e12c5d1SDavid du Colombier #include <math.h>
53e12c5d1SDavid du Colombier #include "pic.h"
63e12c5d1SDavid du Colombier #include "y.tab.h"
73e12c5d1SDavid du Colombier 
linegen(int type)83e12c5d1SDavid du Colombier obj *linegen(int type)
93e12c5d1SDavid du Colombier {
103e12c5d1SDavid du Colombier 	static double prevdx = HT;
113e12c5d1SDavid du Colombier 	static double prevdy = 0;
123e12c5d1SDavid du Colombier 	static double prevw = HT10;
133e12c5d1SDavid du Colombier 	static double prevh = HT5;
147dd7cddfSDavid du Colombier 	int i, j, some, head, ddtype, invis, chop, battr, with;
153e12c5d1SDavid du Colombier 	double ddval, chop1, chop2, x0, y0, x1, y1;
167dd7cddfSDavid du Colombier 	double fillval = 0;
173e12c5d1SDavid du Colombier 	double theta;
187dd7cddfSDavid du Colombier 	double defx, defy, xwith, ywith;
193e12c5d1SDavid du Colombier 	obj *p, *ppos;
203e12c5d1SDavid du Colombier 	static int xtab[] = { 1, 0, -1, 0 };	/* R=0, U=1, L=2, D=3 */
213e12c5d1SDavid du Colombier 	static int ytab[] = { 0, 1, 0, -1 };
223e12c5d1SDavid du Colombier 	double dx[500], dy[500];
233e12c5d1SDavid du Colombier 	int ndxy;
243e12c5d1SDavid du Colombier 	double nx, ny;
257dd7cddfSDavid du Colombier 	Attr *ap, *chop_ap[4];
263e12c5d1SDavid du Colombier 
273e12c5d1SDavid du Colombier 	nx = curx;
283e12c5d1SDavid du Colombier 	ny = cury;
293e12c5d1SDavid du Colombier 	defx = getfval("linewid");
303e12c5d1SDavid du Colombier 	defy = getfval("lineht");
313e12c5d1SDavid du Colombier 	prevh = getfval("arrowht");
323e12c5d1SDavid du Colombier 	prevw = getfval("arrowwid");
337dd7cddfSDavid du Colombier 	dx[0] = dy[0] = ndxy = some = head = invis = battr = with = 0;
343e12c5d1SDavid du Colombier 	chop = chop1 = chop2 = 0;
357dd7cddfSDavid du Colombier 	ddtype = ddval = xwith = ywith = 0;
363e12c5d1SDavid du Colombier 	for (i = 0; i < nattr; i++) {
373e12c5d1SDavid du Colombier 		ap = &attr[i];
383e12c5d1SDavid du Colombier 		switch (ap->a_type) {
393e12c5d1SDavid du Colombier 		case TEXTATTR:
403e12c5d1SDavid du Colombier 			savetext(ap->a_sub, ap->a_val.p);
413e12c5d1SDavid du Colombier 			break;
423e12c5d1SDavid du Colombier 		case HEAD:
433e12c5d1SDavid du Colombier 			head += ap->a_val.i;
443e12c5d1SDavid du Colombier 			break;
453e12c5d1SDavid du Colombier 		case INVIS:
463e12c5d1SDavid du Colombier 			invis = INVIS;
473e12c5d1SDavid du Colombier 			break;
487dd7cddfSDavid du Colombier 		case NOEDGE:
497dd7cddfSDavid du Colombier 			battr |= NOEDGEBIT;
503e12c5d1SDavid du Colombier 			break;
513e12c5d1SDavid du Colombier 		case DOT:
523e12c5d1SDavid du Colombier 		case DASH:
533e12c5d1SDavid du Colombier 			ddtype = ap->a_type==DOT ? DOTBIT : DASHBIT;
543e12c5d1SDavid du Colombier 			if (ap->a_sub == DEFAULT)
553e12c5d1SDavid du Colombier 				ddval = getfval("dashwid");
563e12c5d1SDavid du Colombier 			else
573e12c5d1SDavid du Colombier 				ddval = ap->a_val.f;
583e12c5d1SDavid du Colombier 			break;
593e12c5d1SDavid du Colombier 		case SAME:
603e12c5d1SDavid du Colombier 			dx[ndxy] = prevdx;
613e12c5d1SDavid du Colombier 			dy[ndxy] = prevdy;
623e12c5d1SDavid du Colombier 			some++;
633e12c5d1SDavid du Colombier 			break;
643e12c5d1SDavid du Colombier 		case LEFT:
653e12c5d1SDavid du Colombier 			dx[ndxy] -= (ap->a_sub==DEFAULT) ? defx : ap->a_val.f;
663e12c5d1SDavid du Colombier 			some++;
673e12c5d1SDavid du Colombier 			hvmode = L_DIR;
683e12c5d1SDavid du Colombier 			break;
693e12c5d1SDavid du Colombier 		case RIGHT:
703e12c5d1SDavid du Colombier 			dx[ndxy] += (ap->a_sub==DEFAULT) ? defx : ap->a_val.f;
713e12c5d1SDavid du Colombier 			some++;
723e12c5d1SDavid du Colombier 			hvmode = R_DIR;
733e12c5d1SDavid du Colombier 			break;
743e12c5d1SDavid du Colombier 		case UP:
753e12c5d1SDavid du Colombier 			dy[ndxy] += (ap->a_sub==DEFAULT) ? defy : ap->a_val.f;
763e12c5d1SDavid du Colombier 			some++;
773e12c5d1SDavid du Colombier 			hvmode = U_DIR;
783e12c5d1SDavid du Colombier 			break;
793e12c5d1SDavid du Colombier 		case DOWN:
803e12c5d1SDavid du Colombier 			dy[ndxy] -= (ap->a_sub==DEFAULT) ? defy : ap->a_val.f;
813e12c5d1SDavid du Colombier 			some++;
823e12c5d1SDavid du Colombier 			hvmode = D_DIR;
833e12c5d1SDavid du Colombier 			break;
843e12c5d1SDavid du Colombier 		case HEIGHT:	/* length of arrowhead */
853e12c5d1SDavid du Colombier 			prevh = ap->a_val.f;
863e12c5d1SDavid du Colombier 			break;
873e12c5d1SDavid du Colombier 		case WIDTH:	/* width of arrowhead */
883e12c5d1SDavid du Colombier 			prevw = ap->a_val.f;
893e12c5d1SDavid du Colombier 			break;
903e12c5d1SDavid du Colombier 		case TO:
913e12c5d1SDavid du Colombier 			if (some) {
923e12c5d1SDavid du Colombier 				nx += dx[ndxy];
933e12c5d1SDavid du Colombier 				ny += dy[ndxy];
943e12c5d1SDavid du Colombier 				ndxy++;
953e12c5d1SDavid du Colombier 				dx[ndxy] = dy[ndxy] = some = 0;
963e12c5d1SDavid du Colombier 			}
973e12c5d1SDavid du Colombier 			ppos = attr[i].a_val.o;
98*392dc269SDavid du Colombier 			if (ppos == NULL)
99*392dc269SDavid du Colombier 				ERROR "no tag defined for `to'" FATAL;
1003e12c5d1SDavid du Colombier 			dx[ndxy] = ppos->o_x - nx;
1013e12c5d1SDavid du Colombier 			dy[ndxy] = ppos->o_y - ny;
1023e12c5d1SDavid du Colombier 			some++;
1033e12c5d1SDavid du Colombier 			break;
1043e12c5d1SDavid du Colombier 		case BY:
1053e12c5d1SDavid du Colombier 			if (some) {
1063e12c5d1SDavid du Colombier 				nx += dx[ndxy];
1073e12c5d1SDavid du Colombier 				ny += dy[ndxy];
1083e12c5d1SDavid du Colombier 				ndxy++;
1093e12c5d1SDavid du Colombier 				dx[ndxy] = dy[ndxy] = some = 0;
1103e12c5d1SDavid du Colombier 			}
1113e12c5d1SDavid du Colombier 			ppos = ap->a_val.o;
112*392dc269SDavid du Colombier 			if (ppos == NULL)
113*392dc269SDavid du Colombier 				ERROR "no tag defined for `by'" FATAL;
1143e12c5d1SDavid du Colombier 			dx[ndxy] = ppos->o_x;
1153e12c5d1SDavid du Colombier 			dy[ndxy] = ppos->o_y;
1163e12c5d1SDavid du Colombier 			some++;
1173e12c5d1SDavid du Colombier 			break;
1183e12c5d1SDavid du Colombier 		case THEN:	/* turn off any previous accumulation */
1193e12c5d1SDavid du Colombier 			if (some) {
1203e12c5d1SDavid du Colombier 				nx += dx[ndxy];
1213e12c5d1SDavid du Colombier 				ny += dy[ndxy];
1223e12c5d1SDavid du Colombier 				ndxy++;
1233e12c5d1SDavid du Colombier 				dx[ndxy] = dy[ndxy] = some = 0;
1243e12c5d1SDavid du Colombier 			}
1253e12c5d1SDavid du Colombier 			break;
1263e12c5d1SDavid du Colombier 		case FROM:
1273e12c5d1SDavid du Colombier 		case AT:
1283e12c5d1SDavid du Colombier 			ppos = ap->a_val.o;
129*392dc269SDavid du Colombier 			if (ppos == NULL)
130*392dc269SDavid du Colombier 				ERROR "no tag defined for `from' or `at'" FATAL;
1313e12c5d1SDavid du Colombier 			nx = curx = ppos->o_x;
1323e12c5d1SDavid du Colombier 			ny = cury = ppos->o_y;
1333e12c5d1SDavid du Colombier 			break;
1347dd7cddfSDavid du Colombier 		case WITH:
1357dd7cddfSDavid du Colombier 			with = ap->a_val.i;
1367dd7cddfSDavid du Colombier 			break;
1377dd7cddfSDavid du Colombier 		case CHOP:
1387dd7cddfSDavid du Colombier 			if (ap->a_sub != PLACENAME) {
1397dd7cddfSDavid du Colombier 				if( chop == 0)
1407dd7cddfSDavid du Colombier 					chop1 = chop2 = ap->a_val.f;
1417dd7cddfSDavid du Colombier 				else
1427dd7cddfSDavid du Colombier 					chop2 = ap->a_val.f;
1433e12c5d1SDavid du Colombier 			}
1447dd7cddfSDavid du Colombier 			chop_ap[chop++] = ap;
1457dd7cddfSDavid du Colombier 			break;
1467dd7cddfSDavid du Colombier 		case FILL:
1477dd7cddfSDavid du Colombier 			battr |= FILLBIT;
1487dd7cddfSDavid du Colombier 			if (ap->a_sub == DEFAULT)
1497dd7cddfSDavid du Colombier 				fillval = getfval("fillval");
1507dd7cddfSDavid du Colombier 			else
1517dd7cddfSDavid du Colombier 				fillval = ap->a_val.f;
1527dd7cddfSDavid du Colombier 			break;
1537dd7cddfSDavid du Colombier 		}
1547dd7cddfSDavid du Colombier 	}
1557dd7cddfSDavid du Colombier 	if (with) {	/* this doesn't work at all */
1567dd7cddfSDavid du Colombier 		switch (with) {
1577dd7cddfSDavid du Colombier 		case CENTER:
1587dd7cddfSDavid du Colombier 			xwith = (dx[1] - dx[0]) / 2; ywith = (dy[1] - dy[0]) / 2; break;
1597dd7cddfSDavid du Colombier 		}
1607dd7cddfSDavid du Colombier 		for (i = 0; i < ndxy; i++) {
1617dd7cddfSDavid du Colombier 			dx[i] -= xwith;
1627dd7cddfSDavid du Colombier 			dy[i] -= ywith;
1637dd7cddfSDavid du Colombier 		}
1647dd7cddfSDavid du Colombier 		curx += xwith;
1657dd7cddfSDavid du Colombier 		cury += ywith;
1663e12c5d1SDavid du Colombier 	}
1673e12c5d1SDavid du Colombier 	if (some) {
1683e12c5d1SDavid du Colombier 		nx += dx[ndxy];
1693e12c5d1SDavid du Colombier 		ny += dy[ndxy];
1703e12c5d1SDavid du Colombier 		ndxy++;
1713e12c5d1SDavid du Colombier 		defx = dx[ndxy-1];
1723e12c5d1SDavid du Colombier 		defy = dy[ndxy-1];
1733e12c5d1SDavid du Colombier 	} else {
1743e12c5d1SDavid du Colombier 		defx *= xtab[hvmode];
1753e12c5d1SDavid du Colombier 		defy *= ytab[hvmode];
1763e12c5d1SDavid du Colombier 		dx[ndxy] = defx;
1773e12c5d1SDavid du Colombier 		dy[ndxy] = defy;
1783e12c5d1SDavid du Colombier 		ndxy++;
1793e12c5d1SDavid du Colombier 		nx += defx;
1803e12c5d1SDavid du Colombier 		ny += defy;
1813e12c5d1SDavid du Colombier 	}
1823e12c5d1SDavid du Colombier 	prevdx = defx;
1833e12c5d1SDavid du Colombier 	prevdy = defy;
1843e12c5d1SDavid du Colombier 	if (chop) {
1853e12c5d1SDavid du Colombier 		if (chop == 1 && chop1 == 0)	/* just said "chop", so use default */
1863e12c5d1SDavid du Colombier 			chop1 = chop2 = getfval("circlerad");
1873e12c5d1SDavid du Colombier 		theta = atan2(dy[0], dx[0]);
1883e12c5d1SDavid du Colombier 		x0 = chop1 * cos(theta);
1893e12c5d1SDavid du Colombier 		y0 = chop1 * sin(theta);
1903e12c5d1SDavid du Colombier 		curx += x0;
1913e12c5d1SDavid du Colombier 		cury += y0;
1923e12c5d1SDavid du Colombier 		dx[0] -= x0;
1933e12c5d1SDavid du Colombier 		dy[0] -= y0;
1943e12c5d1SDavid du Colombier 
1953e12c5d1SDavid du Colombier 		theta = atan2(dy[ndxy-1], dx[ndxy-1]);
1963e12c5d1SDavid du Colombier 		x1 = chop2 * cos(theta);
1973e12c5d1SDavid du Colombier 		y1 = chop2 * sin(theta);
1983e12c5d1SDavid du Colombier 		nx -= x1;
1993e12c5d1SDavid du Colombier 		ny -= y1;
2003e12c5d1SDavid du Colombier 		dx[ndxy-1] -= x1;
2013e12c5d1SDavid du Colombier 		dy[ndxy-1] -= y1;
2023e12c5d1SDavid du Colombier 		dprintf("chopping %g %g %g %g; cur=%g,%g end=%g,%g\n",
2033e12c5d1SDavid du Colombier 			x0, y0, x1, y1, curx, cury, nx, ny);
2043e12c5d1SDavid du Colombier 	}
2053e12c5d1SDavid du Colombier 	p = makenode(type, 5 + 2 * ndxy);
2063e12c5d1SDavid du Colombier 	curx = p->o_val[0] = nx;
2073e12c5d1SDavid du Colombier 	cury = p->o_val[1] = ny;
2083e12c5d1SDavid du Colombier 	if (head || type == ARROW) {
2093e12c5d1SDavid du Colombier 		p->o_nhead = getfval("arrowhead");
2103e12c5d1SDavid du Colombier 		p->o_val[2] = prevw;
2113e12c5d1SDavid du Colombier 		p->o_val[3] = prevh;
2123e12c5d1SDavid du Colombier 		if (head == 0)
2133e12c5d1SDavid du Colombier 			head = HEAD2;	/* default arrow head */
2143e12c5d1SDavid du Colombier 	}
2157dd7cddfSDavid du Colombier 	p->o_attr = head | invis | ddtype | battr;
2167dd7cddfSDavid du Colombier 	p->o_fillval = fillval;
2173e12c5d1SDavid du Colombier 	p->o_val[4] = ndxy;
2183e12c5d1SDavid du Colombier 	nx = p->o_x;
2193e12c5d1SDavid du Colombier 	ny = p->o_y;
2203e12c5d1SDavid du Colombier 	for (i = 0, j = 5; i < ndxy; i++, j += 2) {
2213e12c5d1SDavid du Colombier 		p->o_val[j] = dx[i];
2223e12c5d1SDavid du Colombier 		p->o_val[j+1] = dy[i];
2233e12c5d1SDavid du Colombier 		if (type == LINE || type == ARROW)
2243e12c5d1SDavid du Colombier 			extreme(nx += dx[i], ny += dy[i]);
2253e12c5d1SDavid du Colombier 		else if (type == SPLINE && i < ndxy-1) {
2263e12c5d1SDavid du Colombier 			/* to compute approx extreme of spline at p,
2273e12c5d1SDavid du Colombier 			/* compute midway between p-1 and p+1,
2283e12c5d1SDavid du Colombier 			/* then go 3/4 from there to p */
2293e12c5d1SDavid du Colombier 			double ex, ey, xi, yi, xi1, yi1;
2303e12c5d1SDavid du Colombier 			xi = nx + dx[i]; yi = ny + dy[i];	/* p */
2313e12c5d1SDavid du Colombier 			xi1 = xi + dx[i+1]; yi1 = yi + dy[i+1];	/* p+1 */
2323e12c5d1SDavid du Colombier 			ex = (nx+xi1)/2; ey = (ny+yi1)/2;	/* midway */
2333e12c5d1SDavid du Colombier 			ex += 0.75*(xi-ex); ey += 0.75*(yi-ey);
2343e12c5d1SDavid du Colombier 			extreme(ex, ey);
2353e12c5d1SDavid du Colombier 			nx = xi; ny = yi;
2363e12c5d1SDavid du Colombier 		}
2373e12c5d1SDavid du Colombier 
2383e12c5d1SDavid du Colombier 	}
2393e12c5d1SDavid du Colombier 	p->o_ddval = ddval;
2403e12c5d1SDavid du Colombier 	if (dbg) {
2413e12c5d1SDavid du Colombier 		printf("S or L from %g %g to %g %g with %d elements:\n", p->o_x, p->o_y, curx, cury, ndxy);
2423e12c5d1SDavid du Colombier 		for (i = 0, j = 5; i < ndxy; i++, j += 2)
2433e12c5d1SDavid du Colombier 			printf("%g %g\n", p->o_val[j], p->o_val[j+1]);
2443e12c5d1SDavid du Colombier 	}
2453e12c5d1SDavid du Colombier 	extreme(p->o_x, p->o_y);
2463e12c5d1SDavid du Colombier 	extreme(curx, cury);
2473e12c5d1SDavid du Colombier 	return(p);
2483e12c5d1SDavid du Colombier }
249