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