| #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); | 
 | } |