]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/pic/linegen.c
cc: use 7 octal digits for 21 bit runes
[plan9front.git] / sys / src / cmd / pic / linegen.c
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"
7
8 obj *linegen(int type)
9 {
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];
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 = 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;
96                         }
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;
110                         }
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;
124                         }
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;
143                         }
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;
153                 }
154         }
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;
159                 }
160                 for (i = 0; i < ndxy; i++) {
161                         dx[i] -= xwith;
162                         dy[i] -= ywith;
163                 }
164                 curx += xwith;
165                 cury += ywith;
166         }
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;
181         }
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;
194
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);
204         }
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 */
214         }
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;
236                 }
237                         
238         }
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]);
244         }
245         extreme(p->o_x, p->o_y);
246         extreme(curx, cury);
247         return(p);
248 }