xref: /original-bsd/lib/libplot/bitgraph/arc.c (revision 775a9ebd)
1466d507cSbostic /*-
2*775a9ebdSbostic  * Copyright (c) 1980, 1993
3*775a9ebdSbostic  *	The Regents of the University of California.  All rights reserved.
4466d507cSbostic  *
5466d507cSbostic  * %sccs.include.proprietary.c%
627fac43cSdist  */
727fac43cSdist 
87b87f4ffSralph #ifndef lint
9*775a9ebdSbostic static char sccsid[] = "@(#)arc.c	8.1 (Berkeley) 06/04/93";
10466d507cSbostic #endif /* not lint */
117b87f4ffSralph 
127b87f4ffSralph #include "bg.h"
137b87f4ffSralph 
147b87f4ffSralph /* should include test for equality? */
157b87f4ffSralph #define side(x,y)	(a*(x)+b*(y)+c > 0.0 ? 1 : -1)
167b87f4ffSralph 
177b87f4ffSralph /* The beginning and ending points must be distinct. */
arc(xc,yc,xbeg,ybeg,xend,yend)187b87f4ffSralph arc(xc,yc,xbeg,ybeg,xend,yend)
197b87f4ffSralph int xc,yc,xbeg,ybeg,xend,yend;
207b87f4ffSralph {
217b87f4ffSralph 	double r, radius, costheta, sintheta;
227b87f4ffSralph 	double a, b, c, x, y, tempX;
237b87f4ffSralph 	int right_side;
247b87f4ffSralph 
257b87f4ffSralph 	int screen_xc = scaleX(xc);
267b87f4ffSralph 	int screen_yc = scaleY(yc);
277b87f4ffSralph 
287b87f4ffSralph 	/* It is more convienient to beg and end relative to center. */
297b87f4ffSralph 	int screen_xbeg = scaleX(xbeg) - screen_xc;
307b87f4ffSralph 	int screen_ybeg = scaleY(ybeg) - screen_yc;
317b87f4ffSralph 
327b87f4ffSralph 	int screen_xend = scaleX(xend) - screen_xc;
337b87f4ffSralph 	int screen_yend = scaleY(yend) - screen_yc;
347b87f4ffSralph 
357b87f4ffSralph 	/* probably should check that arc is truely circular */
367b87f4ffSralph 	r = sqrt( (double) (screen_xbeg*screen_xbeg + screen_ybeg*screen_ybeg) );
377b87f4ffSralph 
387b87f4ffSralph 	/*
397b87f4ffSralph 	This method is reasonably efficient, clean, and clever.
407b87f4ffSralph 	The easy part is generating the next point on the arc.  This is
417b87f4ffSralph 	done by rotating the points by the angle theta.  Theta is chosen
427b87f4ffSralph 	so that no rotation will cause more than one pixel of a move.
437b87f4ffSralph 	This corresponds to a triangle having x side of r and y side of 1.
447b87f4ffSralph 	The rotation is done (way) below inside the loop.
457b87f4ffSralph 
467b87f4ffSralph 	Note:  all calculations are done in screen coordinates.
477b87f4ffSralph 	*/
487b87f4ffSralph 	if (r <= 1.0) {
497b87f4ffSralph 		/* radius is mapped to length < 1*/
507b87f4ffSralph 		point(xc,yc);
517b87f4ffSralph 		return;
527b87f4ffSralph 		}
537b87f4ffSralph 
547b87f4ffSralph 	radius = sqrt(r*r + 1.0);
557b87f4ffSralph 	sintheta = 1.0/radius;
567b87f4ffSralph 	costheta = r/radius;
577b87f4ffSralph 
587b87f4ffSralph 	/*
597b87f4ffSralph 	The hard part of drawing an arc is figuring out when to stop.
607b87f4ffSralph 	This method works by drawing the line from the beginning point
617b87f4ffSralph 	to the ending point.  This splits the plane in half, with the
627b87f4ffSralph 	arc that we wish to draw on one side of the line.  If we evaluate
637b87f4ffSralph 	side(x,y) = a*x + b*y + c, then all of the points on one side of the
647b87f4ffSralph 	line will result in side being positive, and all the points on the
657b87f4ffSralph 	other side of the line will result in side being negative.
667b87f4ffSralph 
677b87f4ffSralph 	We want to draw the arc in a counter-clockwise direction, so we
687b87f4ffSralph 	must find out what the sign of "side" is for a point which is to the
697b87f4ffSralph 	"right" of a line drawn from "beg" to "end".  A point which must lie
707b87f4ffSralph 	on the right is [xbeg + (yend-ybeg), ybeg - (xend-xbeg)].  (This
717b87f4ffSralph 	point is perpendicular to the line at "beg").
727b87f4ffSralph 
737b87f4ffSralph 	Thus, we compute side of the above point, and then compare the
747b87f4ffSralph 	sign of side for each new point with the sign of the above point.
757b87f4ffSralph 	When they are different, we terminate the loop.
767b87f4ffSralph 	*/
777b87f4ffSralph 
787b87f4ffSralph 	a = (double) (screen_yend - screen_ybeg);
797b87f4ffSralph 	b = (double) (screen_xend - screen_xbeg);
807b87f4ffSralph 	c = (double) (screen_yend*screen_xbeg - screen_xend*screen_ybeg);
817b87f4ffSralph 	right_side = side(screen_xbeg + (screen_yend-screen_ybeg),
827b87f4ffSralph 			  screen_ybeg - (screen_xend-screen_xbeg) );
837b87f4ffSralph 
847b87f4ffSralph 	x = screen_xbeg;
857b87f4ffSralph 	y = screen_ybeg;
867b87f4ffSralph 	move(xbeg, ybeg);
877b87f4ffSralph 	do {
887b87f4ffSralph 		currentx = screen_xc + (int) (x + 0.5);
897b87f4ffSralph 		currenty = screen_yc + (int) (y + 0.5);
907b87f4ffSralph 		putchar( ESC );
917b87f4ffSralph 		printf(":%d;%dd", currentx, currenty);
927b87f4ffSralph 		tempX = x;
937b87f4ffSralph 		x = x*costheta - y*sintheta;
947b87f4ffSralph 		y = tempX*sintheta + y*costheta;
957b87f4ffSralph 	} while( side(x,y) == right_side );
967b87f4ffSralph }
97