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