1 #ifndef lint
2 static char sccsid[] = "@(#)linegen.c	3.1 (CWI) 85/07/30";
3 #endif lint
4 
5 #include	<stdio.h>
6 #include	"pic.h"
7 #include	"y.tab.h"
8 
9 obj *linegen(type)
10 {
11 	static float prevdx = HT;
12 	static float prevdy = 0;
13 	static float prevw = HT10;
14 	static float prevh = HT5;
15 	int i, j, some, head, ddtype, invis, chop;
16 	float ddval, chop1, chop2, x0, y0, x1, y1;
17 	double sin(), cos(), atan2(), theta;
18 	float defx, defy;
19 	obj *p, *ppos;
20 	static int xtab[] = { 1, 0, -1, 0 };	/* R=0, U=1, L=2, D=3 */
21 	static int ytab[] = { 0, 1, 0, -1 };
22 	float dx[50], dy[50];
23 	int ndxy;
24 	float nx, ny;
25 	Attr *ap;
26 
27 	nx = curx;
28 	ny = cury;
29 	defx = getfval("linewid");
30 	defy = getfval("lineht");
31 	prevh = getfval("arrowht");
32 	prevw = getfval("arrowwid");
33 	dx[0] = dy[0] = ndxy = some = head = invis = 0;
34 	chop = chop1 = chop2 = 0;
35 	ddtype = ddval = 0;
36 	for (i = 0; i < nattr; i++) {
37 		ap = &attr[i];
38 		switch (ap->a_type) {
39 		case TEXTATTR:
40 			savetext(ap->a_sub, ap->a_val.p);
41 			break;
42 		case HEAD:
43 			head += ap->a_val.i;
44 			break;
45 		case INVIS:
46 			invis = INVIS;
47 			break;
48 		case CHOP:
49 			if (chop++ == 0)
50 				chop1 = chop2 = ap->a_val.f;
51 			else
52 				chop2 = ap->a_val.f;
53 			break;
54 		case DOT:
55 		case DASH:
56 			ddtype = ap->a_type==DOT ? DOTBIT : DASHBIT;
57 			if (ap->a_sub == DEFAULT)
58 				ddval = getfval("dashwid");
59 			else
60 				ddval = ap->a_val.f;
61 			break;
62 		case SAME:
63 			dx[ndxy] = prevdx;
64 			dy[ndxy] = prevdy;
65 			some++;
66 			break;
67 		case LEFT:
68 			dx[ndxy] -= (ap->a_sub==DEFAULT) ? defx : ap->a_val.f;
69 			some++;
70 			hvmode = L_DIR;
71 			break;
72 		case RIGHT:
73 			dx[ndxy] += (ap->a_sub==DEFAULT) ? defx : ap->a_val.f;
74 			some++;
75 			hvmode = R_DIR;
76 			break;
77 		case UP:
78 			dy[ndxy] += (ap->a_sub==DEFAULT) ? defy : ap->a_val.f;
79 			some++;
80 			hvmode = U_DIR;
81 			break;
82 		case DOWN:
83 			dy[ndxy] -= (ap->a_sub==DEFAULT) ? defy : ap->a_val.f;
84 			some++;
85 			hvmode = D_DIR;
86 			break;
87 		case HEIGHT:	/* length of arrowhead */
88 			prevh = ap->a_val.f;
89 			break;
90 		case WIDTH:	/* width of arrowhead */
91 			prevw = ap->a_val.f;
92 			break;
93 		case TO:
94 			if (some) {
95 				nx += dx[ndxy];
96 				ny += dy[ndxy];
97 				ndxy++;
98 				dx[ndxy] = dy[ndxy] = some = 0;
99 			}
100 			ppos = attr[i].a_val.o;
101 			dx[ndxy] = ppos->o_x - nx;
102 			dy[ndxy] = ppos->o_y - ny;
103 			some++;
104 			break;
105 		case BY:
106 			if (some) {
107 				nx += dx[ndxy];
108 				ny += dy[ndxy];
109 				ndxy++;
110 				dx[ndxy] = dy[ndxy] = some = 0;
111 			}
112 			ppos = ap->a_val.o;
113 			dx[ndxy] = ppos->o_x;
114 			dy[ndxy] = ppos->o_y;
115 			some++;
116 			break;
117 		case THEN:	/* turn off any previous accumulation */
118 			if (some) {
119 				nx += dx[ndxy];
120 				ny += dy[ndxy];
121 				ndxy++;
122 				dx[ndxy] = dy[ndxy] = some = 0;
123 			}
124 			break;
125 		case FROM:
126 		case AT:
127 			ppos = ap->a_val.o;
128 			nx = curx = ppos->o_x;
129 			ny = cury = ppos->o_y;
130 			break;
131 		}
132 	}
133 	if (some) {
134 		nx += dx[ndxy];
135 		ny += dy[ndxy];
136 		ndxy++;
137 		defx = dx[ndxy-1];
138 		defy = dy[ndxy-1];
139 	} else {
140 		defx *= xtab[hvmode];
141 		defy *= ytab[hvmode];
142 		dx[ndxy] = defx;
143 		dy[ndxy] = defy;
144 		ndxy++;
145 		nx += defx;
146 		ny += defy;
147 	}
148 	prevdx = defx;
149 	prevdy = defy;
150 	if (chop) {
151 		if (chop == 1 && chop1 == 0)	/* just said "chop", so use default */
152 			chop1 = chop2 = getfval("circlerad");
153 		theta = atan2(dy[0], dx[0]);
154 		x0 = chop1 * cos(theta);
155 		y0 = chop1 * sin(theta);
156 		curx += x0;
157 		cury += y0;
158 		dx[0] -= x0;
159 		dy[0] -= y0;
160 
161 		theta = atan2(dy[ndxy-1], dx[ndxy-1]);
162 		x1 = chop2 * cos(theta);
163 		y1 = chop2 * sin(theta);
164 		nx -= x1;
165 		ny -= y1;
166 		dx[ndxy-1] -= x1;
167 		dy[ndxy-1] -= y1;
168 		dprintf("chopping %g %g %g %g; cur=%g,%g end=%g,%g\n",
169 			x0, y0, x1, y1, curx, cury, nx, ny);
170 	}
171 	p = makenode(type, 5 + 2 * ndxy);
172 	curx = p->o_val[0] = nx;
173 	cury = p->o_val[1] = ny;
174 	if (head || type == ARROW) {
175 		p->o_nhead = getfval("arrowhead");
176 		p->o_val[2] = prevw;
177 		p->o_val[3] = prevh;
178 		if (head == 0)
179 			head = HEAD2;	/* default arrow head */
180 	}
181 	p->o_attr = head | invis | ddtype;
182 	p->o_val[4] = ndxy;
183 	nx = p->o_x;
184 	ny = p->o_y;
185 	for (i = 0, j = 5; i < ndxy; i++, j += 2) {
186 		p->o_val[j] = dx[i];
187 		p->o_val[j+1] = dy[i];
188 		if (type == LINE)
189 			extreme(nx += dx[i], ny += dy[i]);
190 		else if (type == SPLINE && i < ndxy-1) {
191 			/* to compute approx extreme of spline at p,
192 			/* compute midway between p-1 and p+1,
193 			/* then go 3/4 from there to p */
194 			float ex, ey, xi, yi, xi1, yi1;
195 			xi = nx + dx[i]; yi = ny + dy[i];	/* p */
196 			xi1 = xi + dx[i+1]; yi1 = yi + dy[i+1];	/* p+1 */
197 			ex = (nx+xi1)/2; ey = (ny+yi1)/2;	/* midway */
198 			ex += 0.75*(xi-ex); ey += 0.75*(yi-ey);
199 			extreme(ex, ey);
200 			nx = xi; ny = yi;
201 		}
202 
203 	}
204 	p->o_ddval = ddval;
205 	if (dbg) {
206 		printf("S or L from %g %g to %g %g with %d elements:\n", p->o_x, p->o_y, curx, cury, ndxy);
207 		for (i = 0, j = 5; i < ndxy; i++, j += 2)
208 			printf("%g %g\n", p->o_val[j], p->o_val[j+1]);
209 	}
210 	extreme(p->o_x, p->o_y);
211 	extreme(curx, cury);
212 	return(p);
213 }
214