Blob


1 #include <stdio.h>
2 #include <math.h>
3 #include "pic.h"
4 #include "y.tab.h"
6 void arc_extreme(double, double, double, double, double, double);
7 int quadrant(double x, double y);
9 obj *arcgen(int type) /* handles circular and (eventually) elliptical arcs */
10 {
11 static double prevw = HT10;
12 static double prevh = HT5;
13 static double prevrad = HT2;
14 static int dtox[2][4] ={ { 1, -1, -1, 1}, {1, 1, -1, -1} };
15 static int dtoy[2][4] ={ {1, 1, -1, -1}, {-1, 1, 1, -1} };
16 static int dctrx[2][4] ={ {0, -1, 0, 1}, {0, 1, 0, -1} };
17 static int dctry[2][4] ={ {1, 0, -1, 0}, {-1, 0, 1, 0} };
18 static int nexthv[2][4] ={ {U_DIR, L_DIR, D_DIR, R_DIR}, {D_DIR, R_DIR, U_DIR, L_DIR} };
19 double dx2, dy2, ht, phi, r, d;
20 int i, head, to, at, cw, invis, ddtype, battr;
21 obj *p, *ppos;
22 double fromx, fromy, tox, toy, fillval = 0;
23 Attr *ap;
25 tox=toy=0.0; /* Botch? (gcc) */
27 prevrad = getfval("arcrad");
28 prevh = getfval("arrowht");
29 prevw = getfval("arrowwid");
30 fromx = curx;
31 fromy = cury;
32 head = to = at = cw = invis = ddtype = battr = 0;
33 for (i = 0; i < nattr; i++) {
34 ap = &attr[i];
35 switch (ap->a_type) {
36 case TEXTATTR:
37 savetext(ap->a_sub, ap->a_val.p);
38 break;
39 case HEAD:
40 head += ap->a_val.i;
41 break;
42 case INVIS:
43 invis = INVIS;
44 break;
45 case HEIGHT: /* length of arrowhead */
46 prevh = ap->a_val.f;
47 break;
48 case WIDTH: /* width of arrowhead */
49 prevw = ap->a_val.f;
50 break;
51 case RADIUS:
52 prevrad = ap->a_val.f;
53 break;
54 case DIAMETER:
55 prevrad = ap->a_val.f / 2;
56 break;
57 case CW:
58 cw = 1;
59 break;
60 case FROM: /* start point of arc */
61 ppos = ap->a_val.o;
62 fromx = ppos->o_x;
63 fromy = ppos->o_y;
64 break;
65 case TO: /* end point of arc */
66 ppos = ap->a_val.o;
67 tox = ppos->o_x;
68 toy = ppos->o_y;
69 to++;
70 break;
71 case AT: /* center of arc */
72 ppos = ap->a_val.o;
73 curx = ppos->o_x;
74 cury = ppos->o_y;
75 at = 1;
76 break;
77 case UP:
78 hvmode = U_DIR;
79 break;
80 case DOWN:
81 hvmode = D_DIR;
82 break;
83 case RIGHT:
84 hvmode = R_DIR;
85 break;
86 case LEFT:
87 hvmode = L_DIR;
88 break;
89 case FILL:
90 battr |= FILLBIT;
91 if (ap->a_sub == DEFAULT)
92 fillval = getfval("fillval");
93 else
94 fillval = ap->a_val.f;
95 break;
96 }
97 }
98 if (!at && !to) { /* the defaults are mostly OK */
99 curx = fromx + prevrad * dctrx[cw][hvmode];
100 cury = fromy + prevrad * dctry[cw][hvmode];
101 tox = fromx + prevrad * dtox[cw][hvmode];
102 toy = fromy + prevrad * dtoy[cw][hvmode];
103 hvmode = nexthv[cw][hvmode];
105 else if (!at) {
106 dx2 = (tox - fromx) / 2;
107 dy2 = (toy - fromy) / 2;
108 phi = atan2(dy2, dx2) + (cw ? -PI/2 : PI/2);
109 if (prevrad <= 0.0)
110 prevrad = dx2*dx2+dy2*dy2;
111 for (r=prevrad; (d = r*r - (dx2*dx2+dy2*dy2)) <= 0.0; r *= 2)
112 ; /* this kludge gets around too-small radii */
113 prevrad = r;
114 ht = sqrt(d);
115 curx = fromx + dx2 + ht * cos(phi);
116 cury = fromy + dy2 + ht * sin(phi);
117 dprintf("dx2,dy2=%g,%g, phi=%g, r,ht=%g,%g\n",
118 dx2, dy2, phi, r, ht);
120 else if (at && !to) { /* do we have all the cases??? */
121 tox = fromx + prevrad * dtox[cw][hvmode];
122 toy = fromy + prevrad * dtoy[cw][hvmode];
123 hvmode = nexthv[cw][hvmode];
125 if (cw) { /* interchange roles of from-to and heads */
126 double temp;
127 temp = fromx; fromx = tox; tox = temp;
128 temp = fromy; fromy = toy; toy = temp;
129 if (head == HEAD1)
130 head = HEAD2;
131 else if (head == HEAD2)
132 head = HEAD1;
134 p = makenode(type, 7);
135 arc_extreme(fromx, fromy, tox, toy, curx, cury);
136 p->o_val[0] = fromx;
137 p->o_val[1] = fromy;
138 p->o_val[2] = tox;
139 p->o_val[3] = toy;
140 if (cw) {
141 curx = fromx;
142 cury = fromy;
143 } else {
144 curx = tox;
145 cury = toy;
147 p->o_val[4] = prevw;
148 p->o_val[5] = prevh;
149 p->o_val[6] = prevrad;
150 p->o_attr = head | (cw ? CW_ARC : 0) | invis | ddtype | battr;
151 p->o_fillval = fillval;
152 if (head)
153 p->o_nhead = getfval("arrowhead");
154 dprintf("arc rad %g at %g %g from %g %g to %g %g head %g %g\n",
155 prevrad, p->o_x, p->o_y,
156 p->o_val[0], p->o_val[1], p->o_val[2], p->o_val[3], p->o_val[4], p->o_val[5]);
157 return(p);
160 /***************************************************************************
161 bounding box of a circular arc Eric Grosse 24 May 84
163 Conceptually, this routine generates a list consisting of the start,
164 end, and whichever north, east, south, and west points lie on the arc.
165 The bounding box is then the range of this list.
166 list = {start,end}
167 j = quadrant(start)
168 k = quadrant(end)
169 if( j==k && long way 'round ) append north,west,south,east
170 else
171 while( j != k )
172 append center+radius*[j-th of north,west,south,east unit vectors]
173 j += 1 (mod 4)
174 return( bounding box of list )
175 The following code implements this, with simple optimizations.
176 ***********************************************************************/
179 void arc_extreme(double x0, double y0, double x1, double y1, double xc, double yc)
180 /* start, end, center */
182 /* assumes center isn't too far out */
183 double r, xmin, ymin, xmax, ymax;
184 int j, k;
185 x0 -= xc; y0 -= yc; /* move to center */
186 x1 -= xc; y1 -= yc;
187 xmin = (x0<x1)?x0:x1; ymin = (y0<y1)?y0:y1;
188 xmax = (x0>x1)?x0:x1; ymax = (y0>y1)?y0:y1;
189 r = sqrt(x0*x0 + y0*y0);
190 if (r > 0.0) {
191 j = quadrant(x0,y0);
192 k = quadrant(x1,y1);
193 if (j == k && y1*x0 < x1*y0) {
194 /* viewed as complex numbers, if Im(z1/z0)<0, arc is big */
195 if( xmin > -r) xmin = -r; if( ymin > -r) ymin = -r;
196 if( xmax < r) xmax = r; if( ymax < r) ymax = r;
197 } else {
198 while (j != k) {
199 switch (j) {
200 case 1: if( ymax < r) ymax = r; break; /* north */
201 case 2: if( xmin > -r) xmin = -r; break; /* west */
202 case 3: if( ymin > -r) ymin = -r; break; /* south */
203 case 4: if( xmax < r) xmax = r; break; /* east */
205 j = j%4 + 1;
209 xmin += xc; ymin += yc;
210 xmax += xc; ymax += yc;
211 extreme(xmin, ymin);
212 extreme(xmax, ymax);
215 int
216 quadrant(double x, double y)
218 if ( x>=0.0 && y> 0.0) return(1);
219 else if( x< 0.0 && y>=0.0) return(2);
220 else if( x<=0.0 && y< 0.0) return(3);
221 else if( x> 0.0 && y<=0.0) return(4);
222 else return 0; /* shut up lint */