Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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