148286Sbostic /*-
248286Sbostic * %sccs.include.proprietary.c%
348286Sbostic */
448286Sbostic
515505Sralph #ifndef lint
6*65560Sbostic static char sccsid[] = "@(#)crtplot.c 4.7 (Berkeley) 01/07/94";
748286Sbostic #endif /* not lint */
815505Sralph
915505Sralph /*
1015505Sralph This plotting routine interprets plot commands and outputs them onto
1115505Sralph intelligent terminals (ie, terminals with clear screen and cursor
1215505Sralph addressability. It uses the curses library. It should be compiled
1315505Sralph as follows:
1415505Sralph cc crtdriver.c crtplot.c -lcurses -ltermcap -lm
1515505Sralph Note: This requires as slightly modified driver from the standard driver
1615505Sralph because some function names conflicted with the curses library.
1715505Sralph (That's what you get when you have a flat name space!)
1815505Sralph */
1915505Sralph
2015505Sralph
2115505Sralph #include <curses.h>
2215505Sralph #include <math.h>
2315505Sralph #include <signal.h>
2458181Storek #include <stdlib.h>
2558181Storek #include <string.h>
2615505Sralph
2715505Sralph
2815505Sralph /* These map from plot routine coordinates to screen coordinates. */
2915505Sralph #define scaleX(x) (int) ((x-lowX)*rangeX + 0.5)
3015505Sralph #define scaleY(y) (int) (LINES-0.5 - ((y-lowY)*rangeY))
3115505Sralph
3215505Sralph #define plot_movech(y, x, ch) { plot_move(x, y); plot_addch(ch); }
3315505Sralph
3415505Sralph
3515505Sralph static double lowX, rangeX; /* min and range of x */
3615505Sralph static double lowY, rangeY; /* min and range of y */
3715505Sralph static int lastX, lastY; /* last point plotted */
3815505Sralph
3915505Sralph
4015505Sralph /* This routine just moves the cursor. */
screen_move(y,x)4115505Sralph screen_move(y, x)
4215505Sralph int x,y;
4315505Sralph {
4415505Sralph /* must check for automatic wrap at last col */
4515505Sralph if (!AM || (y < LINES -1) || (x < COLS -1)) {
4615505Sralph mvcur(lastY, lastX, y, x);
4715505Sralph lastY = y;
4815505Sralph lastX = x;
4915505Sralph }
5015505Sralph }
5115505Sralph
5215505Sralph
5315505Sralph /* This routine assumes the cursor is positioned correctly. */
plot_addch(ch)5415505Sralph plot_addch(ch)
5515505Sralph char ch;
5615505Sralph {
5756109Selan _putchar(ch);
5815505Sralph if (++lastX >= COLS) {
5915505Sralph if (AM) {
6015505Sralph lastX = 0;
6115505Sralph lastY++;
6215505Sralph } else {
6315505Sralph lastX = COLS - 1;
6415505Sralph }
6515505Sralph }
6615505Sralph }
6715505Sralph
6815505Sralph
6915505Sralph
7015505Sralph
7115505Sralph /* See the curses manual for what is been done and why. */
openpl()7215505Sralph openpl()
7315505Sralph {
7415505Sralph char *sp;
7546844Sbostic void closepl();
7615505Sralph
7715505Sralph gettmode();
7815505Sralph if (sp=getenv("TERM"))
7915505Sralph setterm(sp);
8015505Sralph signal(SIGINT, closepl);
8115505Sralph
8215505Sralph }
8315505Sralph
8415505Sralph
8515505Sralph
8615505Sralph
8746844Sbostic void
closepl()8815505Sralph closepl()
8915505Sralph {
9015505Sralph signal(SIGINT, SIG_IGN);
9115505Sralph /* Leave cursor at top of screen. */
9215505Sralph mvcur(LINES-1, COLS-1, 0, 0);
9315505Sralph endwin();
9415505Sralph exit(0);
9515505Sralph }
9615505Sralph
9715505Sralph
9815505Sralph
plot_move(x,y)9915505Sralph plot_move(x,y)
10015505Sralph int x, y;
10115505Sralph {
10215505Sralph screen_move(scaleY(y), scaleX(x));
10315505Sralph }
10415505Sralph
10515505Sralph
10615505Sralph
line(x0,y0,x1,y1)10715505Sralph line(x0, y0, x1, y1)
10815505Sralph int x0, y0, x1, y1;
10915505Sralph {
11015505Sralph plot_movech(y0, x0, '*');
11115505Sralph dda_line('*', scaleX(x0), scaleY(y0), scaleX(x1), scaleY(y1));
11215505Sralph }
11315505Sralph
label(str)11415505Sralph label(str)
11515505Sralph char *str;
11615505Sralph {
11715505Sralph reg i, length;
11815505Sralph
11915505Sralph if ( (length=strlen(str)) > (COLS-lastX) )
12015505Sralph length = COLS - lastX;
12115505Sralph for (i=0; i<length; ++i)
12215505Sralph plot_addch(str[i]);
12315505Sralph }
12415505Sralph
12557662Sbostic void
cputchar(ch)12657662Sbostic cputchar(ch)
12757662Sbostic int ch;
12857662Sbostic {
12957662Sbostic (void)putchar(ch);
13057662Sbostic }
13157662Sbostic
plot_erase()13215505Sralph plot_erase()
13315505Sralph {
13415505Sralph /*
13515505Sralph Some of these functions probably belong in openpl(). However, if the
13615505Sralph input is being typed in, putting them in openpl would not work
13715505Sralph since "noecho", etc would prevent (sort of) input. Notice that
13815505Sralph the driver calls openpl before doing anything. This is actually
13915505Sralph wrong, but it is what whoever originally wrote the driver decided
14015505Sralph to do. (openpl() in libplot does nothing -- that is the main problem!)
14115505Sralph */
14257662Sbostic tputs(TI, 0, cputchar);
14357662Sbostic tputs(VS, 0, cputchar);
14415505Sralph
14515505Sralph noecho();
14615505Sralph nonl();
14757662Sbostic tputs(CL, LINES, cputchar);
14815505Sralph mvcur(0, COLS-1, LINES-1, 0);
14915505Sralph lastX = 0;
15015505Sralph lastY = LINES-1;
15115505Sralph }
15215505Sralph
point(x,y)15315505Sralph point(x, y)
15415505Sralph int x,y;
15515505Sralph {
15615505Sralph plot_movech(y, x, '*');
15715505Sralph }
15815505Sralph
15915505Sralph
cont(x,y)16015505Sralph cont(x, y)
16115505Sralph int x,y;
16215505Sralph {
16315505Sralph dda_line('*', lastX-1, lastY, scaleX(x), scaleY(y));
16415505Sralph }
16515505Sralph
16615505Sralph
space(x0,y0,x1,y1)16715505Sralph space(x0, y0, x1, y1)
16815505Sralph int x0, y0, x1, y1;
16915505Sralph {
17015505Sralph lowX = (double) x0;
17115505Sralph lowY = (double) y0;
17215505Sralph rangeX = COLS/(double) (x1 - x0);
17315505Sralph rangeY = LINES/(double) (y1 - y0);
17415505Sralph }
17515505Sralph
17615505Sralph
linemod(string)17715505Sralph linemod(string)
17815505Sralph char *string;
17915505Sralph {
18015505Sralph }
18115505Sralph
18215505Sralph
18315505Sralph
18415505Sralph /* See Neuman & Sproul for explanation and rationale. */
18515505Sralph /* Does not plot first point -- assumed that it is already plotted */
dda_line(ch,x0,y0,x1,y1)18615505Sralph dda_line(ch, x0, y0, x1, y1)
18715505Sralph char ch;
18815505Sralph int x0, y0, x1, y1; /* already transformed to screen coords */
18915505Sralph {
19015505Sralph int length, i;
19115505Sralph double deltaX, deltaY;
19215505Sralph double x, y;
19315505Sralph
19415505Sralph length = abs(x1 - x0);
19515505Sralph if (abs(y1 -y0) > length)
19615505Sralph length = abs(y1 - y0);
19715505Sralph
19815505Sralph if (length == 0)
19915505Sralph return;
20015505Sralph
20115505Sralph deltaX = (double) (x1 - x0)/(double) length;
20215505Sralph deltaY = (double) (y1 - y0)/(double) length;
20315505Sralph
20415505Sralph x = (double) x0 + 0.5;
20515505Sralph y = (double) y0 + 0.5;
20615505Sralph
20715505Sralph for (i=0; i < length; ++i)
20815505Sralph {
20915505Sralph x += deltaX;
21015505Sralph y += deltaY;
21115505Sralph screen_move((int) floor(y), (int) floor(x));
21215505Sralph plot_addch(ch);
21315505Sralph }
21415505Sralph }
21515505Sralph
21615505Sralph
circle(xc,yc,r)21715505Sralph circle (xc,yc,r)
21815505Sralph int xc,yc,r;
21915505Sralph {
22015505Sralph arc(xc,yc, xc+r,yc, xc-r,yc);
22115505Sralph arc(xc,yc, xc-r,yc, xc+r,yc);
22215505Sralph }
22315505Sralph
22415505Sralph
22515505Sralph /* should include test for equality? */
22615505Sralph #define side(x,y) (a*(x)+b*(y)+c > 0.0 ? 1 : -1)
22715505Sralph
arc(xc,yc,xbeg,ybeg,xend,yend)22815505Sralph arc(xc,yc,xbeg,ybeg,xend,yend)
22915505Sralph int xc,yc,xbeg,ybeg,xend,yend;
23015505Sralph {
23115505Sralph double r, radius, costheta, sintheta;
23215505Sralph double a, b, c, x, y, tempX;
23315505Sralph int right_side;
23415505Sralph
23515505Sralph xbeg -= xc; ybeg -= yc;
23615505Sralph xend -= xc; yend -= yc;
23715505Sralph
23815505Sralph /* probably should check that arc is truely circular */
23915505Sralph /* Note: r is in screen coordinates. */
24015505Sralph r = sqrt( rangeX*rangeX*xbeg*xbeg + rangeY*rangeY*ybeg*ybeg);
24115505Sralph
24215505Sralph /*
24315505Sralph This method is reasonably efficient, clean, and clever.
24415505Sralph The easy part is generating the next point on the arc. This is
24515505Sralph done by rotating the points by the angle theta. Theta is chosen
24615505Sralph so that no rotation will cause more than one pixel of a move.
24715505Sralph This corresponds to a triangle having 'x side' of r and 'y side' of 1.
24815505Sralph The rotation is done (way) below inside the loop.
24915505Sralph */
25015505Sralph if (r <= 1.0) {
25115505Sralph /* radius is mapped to length < 1*/
25215505Sralph point(xc,yc);
25315505Sralph return;
25415505Sralph }
25515505Sralph
25615505Sralph radius = sqrt(r*r + 1.0);
25715505Sralph sintheta = 1.0/radius;
25815505Sralph costheta = r/radius;
25915505Sralph
26015505Sralph /*
26115505Sralph The hard part of drawing an arc is figuring out when to stop.
26215505Sralph This method works by drawing the line from the beginning point
26315505Sralph to the ending point. This splits the plane in half, with the
26415505Sralph arc that we wish to draw on one side of the line. If we evaluate
26515505Sralph side(x,y) = a*x + b*y + c, then all of the points on one side of the
26615505Sralph line will result in side being positive, and all the points on the
26715505Sralph other side of the line will result in side being negative.
26815505Sralph
26915505Sralph We want to draw the arc in a counter-clockwise direction, so we
27015505Sralph must find out what the sign of "side" is for a point which is to the
27115505Sralph "right" of a line drawn from "beg" to "end". A point which must lie
27215505Sralph on the right is [xbeg + (yend-ybeg), ybeg - (xend-xbeg)]. (This
27315505Sralph point is perpendicular to the line at "beg").
27415505Sralph
27515505Sralph Thus, we compute "side" of the above point, and then compare the
27615505Sralph sign of side for each new point with the sign of the above point.
27715505Sralph When they are different, we terminate the loop.
27815505Sralph */
27915505Sralph
28015505Sralph a = (double) (yend - ybeg);
28115505Sralph b = (double) (xend - xbeg);
28215505Sralph c = (double) (yend*xbeg - xend*ybeg);
28315505Sralph right_side = side(xbeg + (yend-ybeg),
28415505Sralph ybeg - (xend-xbeg) );
28515505Sralph
28615505Sralph x = xbeg;
28715505Sralph y = ybeg;
28815505Sralph plot_move(xbeg+xc, ybeg+yc);
28915505Sralph do {
29015505Sralph dda_line('*',lastX-1, lastY, scaleX(xc + x), scaleY(yc + y ));
29115505Sralph /*
29215505Sralph screen_move( scaleY(yc + y), scaleX(xc + x) );
29315505Sralph plot_addch('*');
29415505Sralph */
29515505Sralph tempX = x;
29615505Sralph x = x*costheta - y*sintheta;
29715505Sralph y = tempX*sintheta + y*costheta;
29815505Sralph } while( side(x,y) == right_side );
29915505Sralph }
300