1 #include <stdio.h>
2 #include "pic.h"
3 #include "picy.h"
4
arcgen(type)5 struct obj *arcgen(type) /* handles circular and (eventually) elliptical
6 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 double sqrt(), atan2(), sin(), cos();
17 float start,stop,cx1,cy1,cx2,cy2,cx3,cy3,cx4,cy4;
18 float dx2, dy2, ht, phi, r, d;
19 int i, head, to, at, cw, invis;
20 struct obj *p, *ppos;
21 float fromx, fromy, tox, toy;
22
23 prevrad = getfval("arcrad");
24 prevh = getfval("arrowht");
25 prevw = getfval("arrowwid");
26 fromx = curx;
27 fromy = cury;
28 head = to = at = cw = invis = 0;
29 for (i = 0; i < nattr; i++) {
30 switch (attr[i].a_type) {
31 case LJUST: case RJUST: case CENTER: case SPREAD: case FILL: case ABOVE: case BELOW:
32 savetext(attr[i].a_type, attr[i].a_val.p);
33 break;
34 case HEAD:
35 head += attr[i].a_val.i;
36 break;
37 case INVIS:
38 invis = INVIS;
39 break;
40 case HEIGHT: /* length of arrowhead */
41 prevh = attr[i].a_val.f;
42 break;
43 case WIDTH: /* width of arrowhead */
44 prevw = attr[i].a_val.f;
45 break;
46 case RADIUS:
47 prevrad = attr[i].a_val.f;
48 break;
49 case DIAMETER:
50 prevrad = attr[i].a_val.f / 2;
51 break;
52 case CW:
53 cw = 1;
54 break;
55 case FROM: /* start point of arc */
56 ppos = attr[i].a_val.o;
57 fromx = ppos->o_x;
58 fromy = ppos->o_y;
59 break;
60 case TO: /* end point of arc */
61 ppos = attr[i].a_val.o;
62 tox = ppos->o_x;
63 toy = ppos->o_y;
64 to++;
65 break;
66 case AT: /* center of arc */
67 ppos = attr[i].a_val.o;
68 curx = ppos->o_x;
69 cury = ppos->o_y;
70 at = 1;
71 break;
72 case UP:
73 hvmode = U_DIR;
74 break;
75 case DOWN:
76 hvmode = D_DIR;
77 break;
78 case RIGHT:
79 hvmode = R_DIR;
80 break;
81 case LEFT:
82 hvmode = L_DIR;
83 break;
84 }
85 }
86 if (!at && !to) { /* the defaults are mostly OK */
87 curx = fromx + prevrad * dctrx[cw][hvmode];
88 cury = fromy + prevrad * dctry[cw][hvmode];
89 tox = fromx + prevrad * dtox[cw][hvmode];
90 toy = fromy + prevrad * dtoy[cw][hvmode];
91 hvmode = nexthv[cw][hvmode];
92 }
93 else if (!at) {
94 dx2 = (tox - fromx) / 2;
95 dy2 = (toy - fromy) / 2;
96 phi = atan2(dy2, dx2) + (cw ? -PI2 : PI2);
97 for (r=prevrad; (d = r*r - (dx2*dx2+dy2*dy2)) < 0.0; r *= 2)
98 ; /* this kludge gets around too-small radii */
99 prevrad = r;
100 ht = sqrt(d);
101 curx = fromx + dx2 + ht * cos(phi);
102 cury = fromy + dy2 + ht * sin(phi);
103 dprintf("dx2,dy2=%g,%g, phi=%g, r,ht=%g,%g\n",
104 dx2, dy2, phi, r, ht);
105 }
106 else if (at && !to) { /* do we have all the cases??? */
107 tox = fromx + prevrad * dtox[cw][hvmode];
108 toy = fromy + prevrad * dtoy[cw][hvmode];
109 hvmode = nexthv[cw][hvmode];
110 }
111 if (cw) { /* interchange roles of from-to and heads */
112 float temp;
113 temp = fromx; fromx = tox; tox = temp;
114 temp = fromy; fromy = toy; toy = temp;
115 if (head == HEAD1)
116 head = HEAD2;
117 else if (head == HEAD2)
118 head = HEAD1;
119 }
120 p = makenode(type, 7);
121 cx1 = curx;
122 cy1 = cury + prevrad;
123 cx2 = curx - prevrad;
124 cy2 = cury;
125 cx3 = curx;
126 cy3 = cury - prevrad;
127 cx4 = curx + prevrad;
128 cy4 = cury;
129 start = atan2(fromy-cury, fromx-curx);
130 while (start < 0.0) start += 2*PI;
131 while (start >= 2*PI) start -= 2*PI;
132 stop = atan2(toy-cury, tox-curx);
133 while (stop < 0.0) stop += 2*PI;
134 while (stop < start) stop += 2*PI;
135 if (is_onarc(0.0,start,stop)) extreme(cx4,cy4);
136 if (is_onarc(PI/2,start,stop)) extreme(cx1,cy1);
137 if (is_onarc(PI,start,stop)) extreme(cx2,cy2);
138 if (is_onarc(1.5*PI,start,stop)) extreme(cx3,cy3);
139 /* these are wrong in general */
140 extreme(fromx, fromy);
141 extreme(tox, toy);
142 p->o_val[0] = fromx;
143 p->o_val[1] = fromy;
144 p->o_val[2] = tox;
145 p->o_val[3] = toy;
146 if (cw) {
147 curx = fromx;
148 cury = fromy;
149 } else {
150 curx = tox;
151 cury = toy;
152 }
153 p->o_val[4] = prevw;
154 p->o_val[5] = prevh;
155 p->o_val[6] = prevrad;
156 p->o_attr = head | (cw ? CW_ARC : 0) | invis;
157 dprintf("arc rad %g at %g %g from %g %g to %g %g head %g %g\n",
158 prevrad, p->o_x, p->o_y,
159 p->o_val[0], p->o_val[1], p->o_val[2], p->o_val[3], p->o_val[4]
160 , p->o_val[5]);
161 return(p);
162 }
163
164
165 /*
166 * Check if the angle is between the starting and stopping angles
167 */
is_onarc(pt,start,stop)168 is_onarc(pt,start,stop)
169 float pt,start,stop;
170 {
171 if (start <= pt && pt <= stop)
172 return 1;
173 pt += 2*PI;
174 if (start <= pt && pt <= stop)
175 return 1;
176 return 0;
177 }
178