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