|
|
1.1 root 1: /* Copyright (c) 1988 AT&T */
2: /* All Rights Reserved */
3:
4: /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
5: /* The copyright notice above does not evidence any */
6: /* actual or intended publication of such source code. */
7:
8: /* @(#)picasso:arcgen.c 1.0 */
9: #include "picasso.h"
10: #include "y.tab.h"
11:
12: obj *arcgen(type) /* handles circular and (eventually) elliptical arcs */
13: {
14: static double prevwid = HT10;
15: static double prevht = HT5;
16: static double prevrad = HT2;
17: static int dtox[2][4] ={ 1, -1, -1, 1, 1, 1, -1, -1 };
18: static int dtoy[2][4] ={ 1, 1, -1, -1, -1, 1, 1, -1 };
19: static int dctrx[2][4] ={ 0, -1, 0, 1, 0, 1, 0, -1 };
20: static int dctry[2][4] ={ 1, 0, -1, 0, -1, 0, 1, 0 };
21: static int nexthv[2][4] ={ U_DIR, L_DIR, D_DIR, R_DIR, D_DIR,
22: R_DIR, U_DIR, L_DIR };
23: struct objattr obat;
24: double dx2, dy2, phi, r, d, fromx, fromy, tox, toy;
25: int i, head, to, at, cw;
26: obj *p, *ppos;
27: Attr *ap;
28:
29: obat.a_ht = getfval("arrowht");
30: obat.a_wid = getfval("arrowwid");
31: obat.a_rad = getfval("arcrad");
32: obat.a_layer = (int)getfval("curlayer");
33: obat.a_flags = EDGED;
34: obat.a_weight = obat.a_lcolor = obat.a_pcolor = obat.a_tcolor = -1;
35: obat.a_dashpat.a = (float *)0;
36: set_text();
37: fromx = curx;
38: fromy = cury;
39: head = to = at = cw = 0;
40: for (i = 0; i < nattr; i++) {
41: ap = &attr[i];
42: switch (ap->a_type) {
43: default:
44: miscattrs(ap, &obat);
45: break;
46: case HEAD:
47: head += ap->a_val.i;
48: break;
49: case CW:
50: cw = 1;
51: break;
52: case FROM: /* start point of arc */
53: ppos = ap->a_val.o;
54: fromx = Xformx(ppos, 1, ppos->o_x, ppos->o_y);
55: fromy = Xformy(ppos, 0, ppos->o_x, ppos->o_y);
56: break;
57: case TO: /* end point of arc */
58: ppos = ap->a_val.o;
59: tox = Xformx(ppos, 1, ppos->o_x, ppos->o_y);
60: toy = Xformy(ppos, 0, ppos->o_x, ppos->o_y);
61: to++;
62: break;
63: case AT: /* center of arc */
64: ppos = ap->a_val.o;
65: curx = Xformx(ppos, 1, ppos->o_x, ppos->o_y);
66: cury = Xformy(ppos, 0, ppos->o_x, ppos->o_y);
67: at = 1;
68: break;
69: case UP:
70: hvmode = U_DIR;
71: break;
72: case DOWN:
73: hvmode = D_DIR;
74: break;
75: case RIGHT:
76: hvmode = R_DIR;
77: break;
78: case LEFT:
79: hvmode = L_DIR;
80: break;
81: case SAME:
82: obat.a_ht = prevht;
83: obat.a_wid = prevwid;
84: obat.a_rad = prevrad;
85: break;
86: }
87: }
88: if (!at && !to) { /* the defaults are mostly OK */
89: curx = fromx + obat.a_rad * dctrx[cw][hvmode];
90: cury = fromy + obat.a_rad * dctry[cw][hvmode];
91: tox = fromx + obat.a_rad * dtox[cw][hvmode];
92: toy = fromy + obat.a_rad * dtoy[cw][hvmode];
93: hvmode = nexthv[cw][hvmode];
94: }
95: else if (!at) {
96: dx2 = (tox - fromx) / 2;
97: dy2 = (toy - fromy) / 2;
98: phi = atan2(dy2, dx2) + (cw ? -M_PI_2 : M_PI_2);
99: if (obat.a_rad <= 0.0)
100: obat.a_rad = sqrt(dx2*dx2+dy2*dy2);
101: for (r=obat.a_rad; (d = r*r - (dx2*dx2+dy2*dy2)) <= 0.0; r *= 2)
102: ; /* this kludge gets around too-small radii */
103: obat.a_rad = r;
104: d = sqrt(d);
105: curx = fromx + dx2 + d * cos(phi);
106: cury = fromy + dy2 + d * sin(phi);
107: }
108: else if (at && !to) { /* do we have all the cases??? */
109: tox = fromx + obat.a_rad * dtox[cw][hvmode];
110: toy = fromy + obat.a_rad * dtoy[cw][hvmode];
111: hvmode = nexthv[cw][hvmode];
112: }
113: p = makenode(type, N_VAL + 10, obat.a_layer);
114: prevrad = p->o_val[N_VAL+0].f = p->o_val[N_VAL+1].f = obat.a_rad;
115: prevwid = p->o_val[N_VAL+8].f = obat.a_wid;
116: prevht = p->o_val[N_VAL+9].f = obat.a_ht;
117: if (cw) { /* interchange roles of from-to and heads */
118: double temp;
119: temp = fromx; curx = fromx = tox; tox = temp;
120: temp = fromy; cury = fromy = toy; toy = temp;
121: if (head == HEAD1)
122: head = HEAD2;
123: else if (head == HEAD2)
124: head = HEAD1;
125: p->o_attr |= CW_ARC;
126: }
127: else {
128: curx = tox;
129: cury = toy;
130: }
131: p->o_val[N_VAL+2].f = fromx;
132: p->o_val[N_VAL+3].f = fromy;
133: p->o_val[N_VAL+4].f = tox;
134: p->o_val[N_VAL+5].f = toy;
135: if (head)
136: p->o_attr |= head | arrowfill();
137: primattrs(p, &obat);
138: text_bounds(p);
139: arc_extreme(p);
140: return(p);
141: }
142:
143: quadrant(x,y)
144: double x, y;
145: {
146: if ( x>=0.0 && y> 0.0) return(1);
147: else if( x< 0.0 && y>=0.0) return(2);
148: else if( x<=0.0 && y< 0.0) return(3);
149: else if( x> 0.0 && y<=0.0) return(4);
150: else
151: { fprintf(stderr,"can't happen: x,y=%g,%g",x,y); exit(1);}
152: }
153:
154: /***************************************************************************
155: bounding box of a circular arc Eric Grosse 24 May 84
156:
157: Conceptually, this routine generates a list consisting of the start,
158: end, and whichever north, east, south, and west points lie on the arc.
159: The bounding box is then the range of this list.
160: list = {start,end}
161: j = quadrant(start)
162: k = quadrant(end)
163: if( j==k && long way 'round ) append north,west,south,east
164: else
165: while( j != k )
166: append center+radius*[j-th of north,west,south,east unit vectors]
167: j += 1 (mod 4)
168: set bounds (return object with wid/ht and offset from arc center)
169: The following code implements this, with simple optimizations.
170: ***********************************************************************/
171:
172: arc_extreme(p)
173: obj *p;
174: {
175: /* assumes center isn't too far out */
176:
177: double x0, y0, x1, y1, xc, yc; /* start, end, center */
178: double r, xmin, ymin, xmax, ymax, wgt;
179: int j, k;
180:
181: x0 = p->o_val[N_VAL+2].f - (xc = p->o_x); /* translate to center */
182: y0 = p->o_val[N_VAL+3].f - (yc = p->o_y);
183: x1 = p->o_val[N_VAL+4].f - xc;
184: y1 = p->o_val[N_VAL+5].f - 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 = p->o_val[N_VAL].f;
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: if (p->o_type == SECTOR) { /* include center */
208: if (xmin * xmax > 0)
209: if (xmin > 0) xmin = 0; else xmax = 0;
210: if (ymin * ymax > 0)
211: if (ymin > 0) ymin = 0; else ymax = 0;
212: }
213: p->o_wid = xmax - xmin;
214: p->o_ht = ymax - ymin;
215: p->o_val[N_VAL+6].f = -0.5 * (xmin+xmax); /* record offset to center */
216: p->o_val[N_VAL+7].f = -0.5 * (ymin+ymax);
217: wgt = p->o_weight/2;
218: track_bounds(xmin+xc-wgt, ymin+yc-wgt, xmax+xc+wgt, ymax+yc+wgt);
219: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.