diff options
Diffstat (limited to 'usr/src/ucbcmd/plot/libplot/bitgraph/arc.c')
-rw-r--r-- | usr/src/ucbcmd/plot/libplot/bitgraph/arc.c | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/usr/src/ucbcmd/plot/libplot/bitgraph/arc.c b/usr/src/ucbcmd/plot/libplot/bitgraph/arc.c new file mode 100644 index 0000000000..6ba92aaddd --- /dev/null +++ b/usr/src/ucbcmd/plot/libplot/bitgraph/arc.c @@ -0,0 +1,103 @@ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */ + +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* + * Copyright (c) 1983, 1984 1985, 1986, 1987, 1988, Sun Microsystems, Inc. + * All Rights Reserved. + */ + + +#include "bg.h" + +/* should include test for equality? */ +#define side(x,y) (a*(x)+b*(y)+c > 0.0 ? 1 : -1) + +/* The beginning and ending points must be distinct. */ +arc(xc,yc,xbeg,ybeg,xend,yend) +int xc,yc,xbeg,ybeg,xend,yend; +{ + double r, radius, costheta, sintheta; + double a, b, c, x, y, tempX; + int right_side; + + int screen_xc = scaleX(xc); + int screen_yc = scaleY(yc); + + /* It is more convienient to beg and end relative to center. */ + int screen_xbeg = scaleX(xbeg) - screen_xc; + int screen_ybeg = scaleY(ybeg) - screen_yc; + + int screen_xend = scaleX(xend) - screen_xc; + int screen_yend = scaleY(yend) - screen_yc; + + /* probably should check that arc is truely circular */ + r = sqrt( (double) (screen_xbeg*screen_xbeg + screen_ybeg*screen_ybeg) ); + + /* + This method is reasonably efficient, clean, and clever. + The easy part is generating the next point on the arc. This is + done by rotating the points by the angle theta. Theta is chosen + so that no rotation will cause more than one pixel of a move. + This corresponds to a triangle having x side of r and y side of 1. + The rotation is done (way) below inside the loop. + + Note: all calculations are done in screen coordinates. + */ + if (r <= 1.0) { + /* radius is mapped to length < 1*/ + point(xc,yc); + return; + } + + radius = sqrt(r*r + 1.0); + sintheta = 1.0/radius; + costheta = r/radius; + + /* + The hard part of drawing an arc is figuring out when to stop. + This method works by drawing the line from the beginning point + to the ending point. This splits the plane in half, with the + arc that we wish to draw on one side of the line. If we evaluate + side(x,y) = a*x + b*y + c, then all of the points on one side of the + line will result in side being positive, and all the points on the + other side of the line will result in side being negative. + + We want to draw the arc in a counter-clockwise direction, so we + must find out what the sign of "side" is for a point which is to the + "right" of a line drawn from "beg" to "end". A point which must lie + on the right is [xbeg + (yend-ybeg), ybeg - (xend-xbeg)]. (This + point is perpendicular to the line at "beg"). + + Thus, we compute side of the above point, and then compare the + sign of side for each new point with the sign of the above point. + When they are different, we terminate the loop. + */ + + a = (double) (screen_yend - screen_ybeg); + b = (double) (screen_xend - screen_xbeg); + c = (double) (screen_yend*screen_xbeg - screen_xend*screen_ybeg); + right_side = side(screen_xbeg + (screen_yend-screen_ybeg), + screen_ybeg - (screen_xend-screen_xbeg) ); + + x = screen_xbeg; + y = screen_ybeg; + move(xbeg, ybeg); + do { + currentx = screen_xc + (int) (x + 0.5); + currenty = screen_yc + (int) (y + 0.5); + putchar( ESC ); + printf(":%d;%dd", currentx, currenty); + tempX = x; + x = x*costheta - y*sintheta; + y = tempX*sintheta + y*costheta; + } while( side(x,y) == right_side ); +} |