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