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