xref: /csrg-svn/lib/libplot/bitgraph/arc.c (revision 15409)
1*15409Sralph #ifndef lint
2*15409Sralph static char sccsid[] = "@(#)arc.c	4.1 (Berkeley) 11/10/83";
3*15409Sralph #endif
4*15409Sralph 
5*15409Sralph #include "bg.h"
6*15409Sralph 
7*15409Sralph /* should include test for equality? */
8*15409Sralph #define side(x,y)	(a*(x)+b*(y)+c > 0.0 ? 1 : -1)
9*15409Sralph 
10*15409Sralph /* The beginning and ending points must be distinct. */
11*15409Sralph arc(xc,yc,xbeg,ybeg,xend,yend)
12*15409Sralph int xc,yc,xbeg,ybeg,xend,yend;
13*15409Sralph {
14*15409Sralph 	double r, radius, costheta, sintheta;
15*15409Sralph 	double a, b, c, x, y, tempX;
16*15409Sralph 	int right_side;
17*15409Sralph 
18*15409Sralph 	int screen_xc = scaleX(xc);
19*15409Sralph 	int screen_yc = scaleY(yc);
20*15409Sralph 
21*15409Sralph 	/* It is more convienient to beg and end relative to center. */
22*15409Sralph 	int screen_xbeg = scaleX(xbeg) - screen_xc;
23*15409Sralph 	int screen_ybeg = scaleY(ybeg) - screen_yc;
24*15409Sralph 
25*15409Sralph 	int screen_xend = scaleX(xend) - screen_xc;
26*15409Sralph 	int screen_yend = scaleY(yend) - screen_yc;
27*15409Sralph 
28*15409Sralph 	/* probably should check that arc is truely circular */
29*15409Sralph 	r = sqrt( (double) (screen_xbeg*screen_xbeg + screen_ybeg*screen_ybeg) );
30*15409Sralph 
31*15409Sralph 	/*
32*15409Sralph 	This method is reasonably efficient, clean, and clever.
33*15409Sralph 	The easy part is generating the next point on the arc.  This is
34*15409Sralph 	done by rotating the points by the angle theta.  Theta is chosen
35*15409Sralph 	so that no rotation will cause more than one pixel of a move.
36*15409Sralph 	This corresponds to a triangle having x side of r and y side of 1.
37*15409Sralph 	The rotation is done (way) below inside the loop.
38*15409Sralph 
39*15409Sralph 	Note:  all calculations are done in screen coordinates.
40*15409Sralph 	*/
41*15409Sralph 	if (r <= 1.0) {
42*15409Sralph 		/* radius is mapped to length < 1*/
43*15409Sralph 		point(xc,yc);
44*15409Sralph 		return;
45*15409Sralph 		}
46*15409Sralph 
47*15409Sralph 	radius = sqrt(r*r + 1.0);
48*15409Sralph 	sintheta = 1.0/radius;
49*15409Sralph 	costheta = r/radius;
50*15409Sralph 
51*15409Sralph 	/*
52*15409Sralph 	The hard part of drawing an arc is figuring out when to stop.
53*15409Sralph 	This method works by drawing the line from the beginning point
54*15409Sralph 	to the ending point.  This splits the plane in half, with the
55*15409Sralph 	arc that we wish to draw on one side of the line.  If we evaluate
56*15409Sralph 	side(x,y) = a*x + b*y + c, then all of the points on one side of the
57*15409Sralph 	line will result in side being positive, and all the points on the
58*15409Sralph 	other side of the line will result in side being negative.
59*15409Sralph 
60*15409Sralph 	We want to draw the arc in a counter-clockwise direction, so we
61*15409Sralph 	must find out what the sign of "side" is for a point which is to the
62*15409Sralph 	"right" of a line drawn from "beg" to "end".  A point which must lie
63*15409Sralph 	on the right is [xbeg + (yend-ybeg), ybeg - (xend-xbeg)].  (This
64*15409Sralph 	point is perpendicular to the line at "beg").
65*15409Sralph 
66*15409Sralph 	Thus, we compute side of the above point, and then compare the
67*15409Sralph 	sign of side for each new point with the sign of the above point.
68*15409Sralph 	When they are different, we terminate the loop.
69*15409Sralph 	*/
70*15409Sralph 
71*15409Sralph 	a = (double) (screen_yend - screen_ybeg);
72*15409Sralph 	b = (double) (screen_xend - screen_xbeg);
73*15409Sralph 	c = (double) (screen_yend*screen_xbeg - screen_xend*screen_ybeg);
74*15409Sralph 	right_side = side(screen_xbeg + (screen_yend-screen_ybeg),
75*15409Sralph 			  screen_ybeg - (screen_xend-screen_xbeg) );
76*15409Sralph 
77*15409Sralph 	x = screen_xbeg;
78*15409Sralph 	y = screen_ybeg;
79*15409Sralph 	move(xbeg, ybeg);
80*15409Sralph 	do {
81*15409Sralph 		currentx = screen_xc + (int) (x + 0.5);
82*15409Sralph 		currenty = screen_yc + (int) (y + 0.5);
83*15409Sralph 		putchar( ESC );
84*15409Sralph 		printf(":%d;%dd", currentx, currenty);
85*15409Sralph 		tempX = x;
86*15409Sralph 		x = x*costheta - y*sintheta;
87*15409Sralph 		y = tempX*sintheta + y*costheta;
88*15409Sralph 	} while( side(x,y) == right_side );
89*15409Sralph }
90