xref: /csrg-svn/lib/libplot/bitgraph/arc.c (revision 61330)
148504Sbostic /*-
2*61330Sbostic  * Copyright (c) 1980, 1993
3*61330Sbostic  *	The Regents of the University of California.  All rights reserved.
448504Sbostic  *
548504Sbostic  * %sccs.include.proprietary.c%
619851Sdist  */
719851Sdist 
815409Sralph #ifndef lint
9*61330Sbostic static char sccsid[] = "@(#)arc.c	8.1 (Berkeley) 06/04/93";
1048504Sbostic #endif /* not lint */
1115409Sralph 
1215409Sralph #include "bg.h"
1315409Sralph 
1415409Sralph /* should include test for equality? */
1515409Sralph #define side(x,y)	(a*(x)+b*(y)+c > 0.0 ? 1 : -1)
1615409Sralph 
1715409Sralph /* The beginning and ending points must be distinct. */
arc(xc,yc,xbeg,ybeg,xend,yend)1815409Sralph arc(xc,yc,xbeg,ybeg,xend,yend)
1915409Sralph int xc,yc,xbeg,ybeg,xend,yend;
2015409Sralph {
2115409Sralph 	double r, radius, costheta, sintheta;
2215409Sralph 	double a, b, c, x, y, tempX;
2315409Sralph 	int right_side;
2415409Sralph 
2515409Sralph 	int screen_xc = scaleX(xc);
2615409Sralph 	int screen_yc = scaleY(yc);
2715409Sralph 
2815409Sralph 	/* It is more convienient to beg and end relative to center. */
2915409Sralph 	int screen_xbeg = scaleX(xbeg) - screen_xc;
3015409Sralph 	int screen_ybeg = scaleY(ybeg) - screen_yc;
3115409Sralph 
3215409Sralph 	int screen_xend = scaleX(xend) - screen_xc;
3315409Sralph 	int screen_yend = scaleY(yend) - screen_yc;
3415409Sralph 
3515409Sralph 	/* probably should check that arc is truely circular */
3615409Sralph 	r = sqrt( (double) (screen_xbeg*screen_xbeg + screen_ybeg*screen_ybeg) );
3715409Sralph 
3815409Sralph 	/*
3915409Sralph 	This method is reasonably efficient, clean, and clever.
4015409Sralph 	The easy part is generating the next point on the arc.  This is
4115409Sralph 	done by rotating the points by the angle theta.  Theta is chosen
4215409Sralph 	so that no rotation will cause more than one pixel of a move.
4315409Sralph 	This corresponds to a triangle having x side of r and y side of 1.
4415409Sralph 	The rotation is done (way) below inside the loop.
4515409Sralph 
4615409Sralph 	Note:  all calculations are done in screen coordinates.
4715409Sralph 	*/
4815409Sralph 	if (r <= 1.0) {
4915409Sralph 		/* radius is mapped to length < 1*/
5015409Sralph 		point(xc,yc);
5115409Sralph 		return;
5215409Sralph 		}
5315409Sralph 
5415409Sralph 	radius = sqrt(r*r + 1.0);
5515409Sralph 	sintheta = 1.0/radius;
5615409Sralph 	costheta = r/radius;
5715409Sralph 
5815409Sralph 	/*
5915409Sralph 	The hard part of drawing an arc is figuring out when to stop.
6015409Sralph 	This method works by drawing the line from the beginning point
6115409Sralph 	to the ending point.  This splits the plane in half, with the
6215409Sralph 	arc that we wish to draw on one side of the line.  If we evaluate
6315409Sralph 	side(x,y) = a*x + b*y + c, then all of the points on one side of the
6415409Sralph 	line will result in side being positive, and all the points on the
6515409Sralph 	other side of the line will result in side being negative.
6615409Sralph 
6715409Sralph 	We want to draw the arc in a counter-clockwise direction, so we
6815409Sralph 	must find out what the sign of "side" is for a point which is to the
6915409Sralph 	"right" of a line drawn from "beg" to "end".  A point which must lie
7015409Sralph 	on the right is [xbeg + (yend-ybeg), ybeg - (xend-xbeg)].  (This
7115409Sralph 	point is perpendicular to the line at "beg").
7215409Sralph 
7315409Sralph 	Thus, we compute side of the above point, and then compare the
7415409Sralph 	sign of side for each new point with the sign of the above point.
7515409Sralph 	When they are different, we terminate the loop.
7615409Sralph 	*/
7715409Sralph 
7815409Sralph 	a = (double) (screen_yend - screen_ybeg);
7915409Sralph 	b = (double) (screen_xend - screen_xbeg);
8015409Sralph 	c = (double) (screen_yend*screen_xbeg - screen_xend*screen_ybeg);
8115409Sralph 	right_side = side(screen_xbeg + (screen_yend-screen_ybeg),
8215409Sralph 			  screen_ybeg - (screen_xend-screen_xbeg) );
8315409Sralph 
8415409Sralph 	x = screen_xbeg;
8515409Sralph 	y = screen_ybeg;
8615409Sralph 	move(xbeg, ybeg);
8715409Sralph 	do {
8815409Sralph 		currentx = screen_xc + (int) (x + 0.5);
8915409Sralph 		currenty = screen_yc + (int) (y + 0.5);
9015409Sralph 		putchar( ESC );
9115409Sralph 		printf(":%d;%dd", currentx, currenty);
9215409Sralph 		tempX = x;
9315409Sralph 		x = x*costheta - y*sintheta;
9415409Sralph 		y = tempX*sintheta + y*costheta;
9515409Sralph 	} while( side(x,y) == right_side );
9615409Sralph }
97