148286Sbostic /*- 248286Sbostic * %sccs.include.proprietary.c% 348286Sbostic */ 448286Sbostic 515505Sralph #ifndef lint 6*56109Selan static char sccsid[] = "@(#)crtplot.c 4.4 (Berkeley) 08/31/92"; 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> 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 4015505Sralph /* This routine just moves the cursor. */ 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. */ 5415505Sralph plot_addch(ch) 5515505Sralph char ch; 5615505Sralph { 57*56109Selan _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. */ 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 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 9915505Sralph plot_move(x,y) 10015505Sralph int x, y; 10115505Sralph { 10215505Sralph screen_move(scaleY(y), scaleX(x)); 10315505Sralph } 10415505Sralph 10515505Sralph 10615505Sralph 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 11415505Sralph label(str) 11515505Sralph char *str; 11615505Sralph { 11715505Sralph reg i, length; 11815505Sralph int strlen(); 11915505Sralph 12015505Sralph if ( (length=strlen(str)) > (COLS-lastX) ) 12115505Sralph length = COLS - lastX; 12215505Sralph for (i=0; i<length; ++i) 12315505Sralph plot_addch(str[i]); 12415505Sralph } 12515505Sralph 12615505Sralph plot_erase() 12715505Sralph { 12815505Sralph /* 12915505Sralph Some of these functions probably belong in openpl(). However, if the 13015505Sralph input is being typed in, putting them in openpl would not work 13115505Sralph since "noecho", etc would prevent (sort of) input. Notice that 13215505Sralph the driver calls openpl before doing anything. This is actually 13315505Sralph wrong, but it is what whoever originally wrote the driver decided 13415505Sralph to do. (openpl() in libplot does nothing -- that is the main problem!) 13515505Sralph */ 13615505Sralph _puts(TI); 13715505Sralph _puts(VS); 13815505Sralph 13915505Sralph noecho(); 14015505Sralph nonl(); 141*56109Selan tputs(CL, LINES, __cputchar); 14215505Sralph mvcur(0, COLS-1, LINES-1, 0); 14315505Sralph lastX = 0; 14415505Sralph lastY = LINES-1; 14515505Sralph } 14615505Sralph 14715505Sralph 14815505Sralph point(x, y) 14915505Sralph int x,y; 15015505Sralph { 15115505Sralph plot_movech(y, x, '*'); 15215505Sralph } 15315505Sralph 15415505Sralph 15515505Sralph cont(x, y) 15615505Sralph int x,y; 15715505Sralph { 15815505Sralph dda_line('*', lastX-1, lastY, scaleX(x), scaleY(y)); 15915505Sralph } 16015505Sralph 16115505Sralph 16215505Sralph space(x0, y0, x1, y1) 16315505Sralph int x0, y0, x1, y1; 16415505Sralph { 16515505Sralph lowX = (double) x0; 16615505Sralph lowY = (double) y0; 16715505Sralph rangeX = COLS/(double) (x1 - x0); 16815505Sralph rangeY = LINES/(double) (y1 - y0); 16915505Sralph } 17015505Sralph 17115505Sralph 17215505Sralph linemod(string) 17315505Sralph char *string; 17415505Sralph { 17515505Sralph } 17615505Sralph 17715505Sralph 17815505Sralph 17915505Sralph /* See Neuman & Sproul for explanation and rationale. */ 18015505Sralph /* Does not plot first point -- assumed that it is already plotted */ 18115505Sralph dda_line(ch, x0, y0, x1, y1) 18215505Sralph char ch; 18315505Sralph int x0, y0, x1, y1; /* already transformed to screen coords */ 18415505Sralph { 18515505Sralph int length, i; 18615505Sralph double deltaX, deltaY; 18715505Sralph double x, y; 18815505Sralph double floor(); 18915505Sralph int abs(); 19015505Sralph 19115505Sralph length = abs(x1 - x0); 19215505Sralph if (abs(y1 -y0) > length) 19315505Sralph length = abs(y1 - y0); 19415505Sralph 19515505Sralph if (length == 0) 19615505Sralph return; 19715505Sralph 19815505Sralph deltaX = (double) (x1 - x0)/(double) length; 19915505Sralph deltaY = (double) (y1 - y0)/(double) length; 20015505Sralph 20115505Sralph x = (double) x0 + 0.5; 20215505Sralph y = (double) y0 + 0.5; 20315505Sralph 20415505Sralph for (i=0; i < length; ++i) 20515505Sralph { 20615505Sralph x += deltaX; 20715505Sralph y += deltaY; 20815505Sralph screen_move((int) floor(y), (int) floor(x)); 20915505Sralph plot_addch(ch); 21015505Sralph } 21115505Sralph } 21215505Sralph 21315505Sralph 21415505Sralph circle (xc,yc,r) 21515505Sralph int xc,yc,r; 21615505Sralph { 21715505Sralph arc(xc,yc, xc+r,yc, xc-r,yc); 21815505Sralph arc(xc,yc, xc-r,yc, xc+r,yc); 21915505Sralph } 22015505Sralph 22115505Sralph 22215505Sralph /* should include test for equality? */ 22315505Sralph #define side(x,y) (a*(x)+b*(y)+c > 0.0 ? 1 : -1) 22415505Sralph 22515505Sralph arc(xc,yc,xbeg,ybeg,xend,yend) 22615505Sralph int xc,yc,xbeg,ybeg,xend,yend; 22715505Sralph { 22815505Sralph double r, radius, costheta, sintheta; 22915505Sralph double a, b, c, x, y, tempX; 23015505Sralph int right_side; 23115505Sralph 23215505Sralph xbeg -= xc; ybeg -= yc; 23315505Sralph xend -= xc; yend -= yc; 23415505Sralph 23515505Sralph /* probably should check that arc is truely circular */ 23615505Sralph /* Note: r is in screen coordinates. */ 23715505Sralph r = sqrt( rangeX*rangeX*xbeg*xbeg + rangeY*rangeY*ybeg*ybeg); 23815505Sralph 23915505Sralph /* 24015505Sralph This method is reasonably efficient, clean, and clever. 24115505Sralph The easy part is generating the next point on the arc. This is 24215505Sralph done by rotating the points by the angle theta. Theta is chosen 24315505Sralph so that no rotation will cause more than one pixel of a move. 24415505Sralph This corresponds to a triangle having 'x side' of r and 'y side' of 1. 24515505Sralph The rotation is done (way) below inside the loop. 24615505Sralph */ 24715505Sralph if (r <= 1.0) { 24815505Sralph /* radius is mapped to length < 1*/ 24915505Sralph point(xc,yc); 25015505Sralph return; 25115505Sralph } 25215505Sralph 25315505Sralph radius = sqrt(r*r + 1.0); 25415505Sralph sintheta = 1.0/radius; 25515505Sralph costheta = r/radius; 25615505Sralph 25715505Sralph /* 25815505Sralph The hard part of drawing an arc is figuring out when to stop. 25915505Sralph This method works by drawing the line from the beginning point 26015505Sralph to the ending point. This splits the plane in half, with the 26115505Sralph arc that we wish to draw on one side of the line. If we evaluate 26215505Sralph side(x,y) = a*x + b*y + c, then all of the points on one side of the 26315505Sralph line will result in side being positive, and all the points on the 26415505Sralph other side of the line will result in side being negative. 26515505Sralph 26615505Sralph We want to draw the arc in a counter-clockwise direction, so we 26715505Sralph must find out what the sign of "side" is for a point which is to the 26815505Sralph "right" of a line drawn from "beg" to "end". A point which must lie 26915505Sralph on the right is [xbeg + (yend-ybeg), ybeg - (xend-xbeg)]. (This 27015505Sralph point is perpendicular to the line at "beg"). 27115505Sralph 27215505Sralph Thus, we compute "side" of the above point, and then compare the 27315505Sralph sign of side for each new point with the sign of the above point. 27415505Sralph When they are different, we terminate the loop. 27515505Sralph */ 27615505Sralph 27715505Sralph a = (double) (yend - ybeg); 27815505Sralph b = (double) (xend - xbeg); 27915505Sralph c = (double) (yend*xbeg - xend*ybeg); 28015505Sralph right_side = side(xbeg + (yend-ybeg), 28115505Sralph ybeg - (xend-xbeg) ); 28215505Sralph 28315505Sralph x = xbeg; 28415505Sralph y = ybeg; 28515505Sralph plot_move(xbeg+xc, ybeg+yc); 28615505Sralph do { 28715505Sralph dda_line('*',lastX-1, lastY, scaleX(xc + x), scaleY(yc + y )); 28815505Sralph /* 28915505Sralph screen_move( scaleY(yc + y), scaleX(xc + x) ); 29015505Sralph plot_addch('*'); 29115505Sralph */ 29215505Sralph tempX = x; 29315505Sralph x = x*costheta - y*sintheta; 29415505Sralph y = tempX*sintheta + y*costheta; 29515505Sralph } while( side(x,y) == right_side ); 29615505Sralph } 297