initial port of plan9 troff to linux
[troff.git] / pic / linegen.c
blob0d457411668f53bc9e653ee09194822ece68c3e2
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <math.h>
5 #include "pic.h"
6 #include "y.tab.h"
8 obj *linegen(int type)
10 static double prevdx = HT;
11 static double prevdy = 0;
12 static double prevw = HT10;
13 static double prevh = HT5;
14 int i, j, some, head, ddtype, invis, chop, battr, with;
15 double ddval, chop1, chop2, x0, y0, x1, y1;
16 double fillval = 0;
17 double theta;
18 double defx, defy, xwith, ywith;
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 double dx[500], dy[500];
23 int ndxy;
24 double nx, ny;
25 Attr *ap, *chop_ap[4];
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 = battr = with = 0;
34 chop = chop1 = chop2 = 0;
35 ddtype = ddval = xwith = ywith = 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 NOEDGE:
49 battr |= NOEDGEBIT;
50 break;
51 case DOT:
52 case DASH:
53 ddtype = ap->a_type==DOT ? DOTBIT : DASHBIT;
54 if (ap->a_sub == DEFAULT)
55 ddval = getfval("dashwid");
56 else
57 ddval = ap->a_val.f;
58 break;
59 case SAME:
60 dx[ndxy] = prevdx;
61 dy[ndxy] = prevdy;
62 some++;
63 break;
64 case LEFT:
65 dx[ndxy] -= (ap->a_sub==DEFAULT) ? defx : ap->a_val.f;
66 some++;
67 hvmode = L_DIR;
68 break;
69 case RIGHT:
70 dx[ndxy] += (ap->a_sub==DEFAULT) ? defx : ap->a_val.f;
71 some++;
72 hvmode = R_DIR;
73 break;
74 case UP:
75 dy[ndxy] += (ap->a_sub==DEFAULT) ? defy : ap->a_val.f;
76 some++;
77 hvmode = U_DIR;
78 break;
79 case DOWN:
80 dy[ndxy] -= (ap->a_sub==DEFAULT) ? defy : ap->a_val.f;
81 some++;
82 hvmode = D_DIR;
83 break;
84 case HEIGHT: /* length of arrowhead */
85 prevh = ap->a_val.f;
86 break;
87 case WIDTH: /* width of arrowhead */
88 prevw = ap->a_val.f;
89 break;
90 case TO:
91 if (some) {
92 nx += dx[ndxy];
93 ny += dy[ndxy];
94 ndxy++;
95 dx[ndxy] = dy[ndxy] = some = 0;
97 ppos = attr[i].a_val.o;
98 if (ppos == NULL)
99 ERROR "no tag defined for `to'" FATAL;
100 dx[ndxy] = ppos->o_x - nx;
101 dy[ndxy] = ppos->o_y - ny;
102 some++;
103 break;
104 case BY:
105 if (some) {
106 nx += dx[ndxy];
107 ny += dy[ndxy];
108 ndxy++;
109 dx[ndxy] = dy[ndxy] = some = 0;
111 ppos = ap->a_val.o;
112 if (ppos == NULL)
113 ERROR "no tag defined for `by'" FATAL;
114 dx[ndxy] = ppos->o_x;
115 dy[ndxy] = ppos->o_y;
116 some++;
117 break;
118 case THEN: /* turn off any previous accumulation */
119 if (some) {
120 nx += dx[ndxy];
121 ny += dy[ndxy];
122 ndxy++;
123 dx[ndxy] = dy[ndxy] = some = 0;
125 break;
126 case FROM:
127 case AT:
128 ppos = ap->a_val.o;
129 if (ppos == NULL)
130 ERROR "no tag defined for `from' or `at'" FATAL;
131 nx = curx = ppos->o_x;
132 ny = cury = ppos->o_y;
133 break;
134 case WITH:
135 with = ap->a_val.i;
136 break;
137 case CHOP:
138 if (ap->a_sub != PLACENAME) {
139 if( chop == 0)
140 chop1 = chop2 = ap->a_val.f;
141 else
142 chop2 = ap->a_val.f;
144 chop_ap[chop++] = ap;
145 break;
146 case FILL:
147 battr |= FILLBIT;
148 if (ap->a_sub == DEFAULT)
149 fillval = getfval("fillval");
150 else
151 fillval = ap->a_val.f;
152 break;
155 if (with) { /* this doesn't work at all */
156 switch (with) {
157 case CENTER:
158 xwith = (dx[1] - dx[0]) / 2; ywith = (dy[1] - dy[0]) / 2; break;
160 for (i = 0; i < ndxy; i++) {
161 dx[i] -= xwith;
162 dy[i] -= ywith;
164 curx += xwith;
165 cury += ywith;
167 if (some) {
168 nx += dx[ndxy];
169 ny += dy[ndxy];
170 ndxy++;
171 defx = dx[ndxy-1];
172 defy = dy[ndxy-1];
173 } else {
174 defx *= xtab[hvmode];
175 defy *= ytab[hvmode];
176 dx[ndxy] = defx;
177 dy[ndxy] = defy;
178 ndxy++;
179 nx += defx;
180 ny += defy;
182 prevdx = defx;
183 prevdy = defy;
184 if (chop) {
185 if (chop == 1 && chop1 == 0) /* just said "chop", so use default */
186 chop1 = chop2 = getfval("circlerad");
187 theta = atan2(dy[0], dx[0]);
188 x0 = chop1 * cos(theta);
189 y0 = chop1 * sin(theta);
190 curx += x0;
191 cury += y0;
192 dx[0] -= x0;
193 dy[0] -= y0;
195 theta = atan2(dy[ndxy-1], dx[ndxy-1]);
196 x1 = chop2 * cos(theta);
197 y1 = chop2 * sin(theta);
198 nx -= x1;
199 ny -= y1;
200 dx[ndxy-1] -= x1;
201 dy[ndxy-1] -= y1;
202 dprintf("chopping %g %g %g %g; cur=%g,%g end=%g,%g\n",
203 x0, y0, x1, y1, curx, cury, nx, ny);
205 p = makenode(type, 5 + 2 * ndxy);
206 curx = p->o_val[0] = nx;
207 cury = p->o_val[1] = ny;
208 if (head || type == ARROW) {
209 p->o_nhead = getfval("arrowhead");
210 p->o_val[2] = prevw;
211 p->o_val[3] = prevh;
212 if (head == 0)
213 head = HEAD2; /* default arrow head */
215 p->o_attr = head | invis | ddtype | battr;
216 p->o_fillval = fillval;
217 p->o_val[4] = ndxy;
218 nx = p->o_x;
219 ny = p->o_y;
220 for (i = 0, j = 5; i < ndxy; i++, j += 2) {
221 p->o_val[j] = dx[i];
222 p->o_val[j+1] = dy[i];
223 if (type == LINE || type == ARROW)
224 extreme(nx += dx[i], ny += dy[i]);
225 else if (type == SPLINE && i < ndxy-1) {
226 /* to compute approx extreme of spline at p,
227 /* compute midway between p-1 and p+1,
228 /* then go 3/4 from there to p */
229 double ex, ey, xi, yi, xi1, yi1;
230 xi = nx + dx[i]; yi = ny + dy[i]; /* p */
231 xi1 = xi + dx[i+1]; yi1 = yi + dy[i+1]; /* p+1 */
232 ex = (nx+xi1)/2; ey = (ny+yi1)/2; /* midway */
233 ex += 0.75*(xi-ex); ey += 0.75*(yi-ey);
234 extreme(ex, ey);
235 nx = xi; ny = yi;
239 p->o_ddval = ddval;
240 if (dbg) {
241 printf("S or L from %g %g to %g %g with %d elements:\n", p->o_x, p->o_y, curx, cury, ndxy);
242 for (i = 0, j = 5; i < ndxy; i++, j += 2)
243 printf("%g %g\n", p->o_val[j], p->o_val[j+1]);
245 extreme(p->o_x, p->o_y);
246 extreme(curx, cury);
247 return(p);