|
|
1.1 ! root 1: #ifndef lint ! 2: static char sccsid[] = "@(#)crtplot.c 4.1 (Berkeley) 11/11/83"; ! 3: #endif ! 4: ! 5: /* ! 6: This plotting routine interprets plot commands and outputs them onto ! 7: intelligent terminals (ie, terminals with clear screen and cursor ! 8: addressability. It uses the curses library. It should be compiled ! 9: as follows: ! 10: cc crtdriver.c crtplot.c -lcurses -ltermcap -lm ! 11: Note: This requires as slightly modified driver from the standard driver ! 12: because some function names conflicted with the curses library. ! 13: (That's what you get when you have a flat name space!) ! 14: */ ! 15: ! 16: ! 17: #include <curses.h> ! 18: #include <math.h> ! 19: #include <signal.h> ! 20: ! 21: ! 22: /* These map from plot routine coordinates to screen coordinates. */ ! 23: #define scaleX(x) (int) ((x-lowX)*rangeX + 0.5) ! 24: #define scaleY(y) (int) (LINES-0.5 - ((y-lowY)*rangeY)) ! 25: ! 26: #define plot_movech(y, x, ch) { plot_move(x, y); plot_addch(ch); } ! 27: ! 28: ! 29: static double lowX, rangeX; /* min and range of x */ ! 30: static double lowY, rangeY; /* min and range of y */ ! 31: static int lastX, lastY; /* last point plotted */ ! 32: ! 33: ! 34: char *getenv(); ! 35: extern char _putchar(); ! 36: ! 37: /* This routine just moves the cursor. */ ! 38: screen_move(y, x) ! 39: int x,y; ! 40: { ! 41: /* must check for automatic wrap at last col */ ! 42: if (!AM || (y < LINES -1) || (x < COLS -1)) { ! 43: mvcur(lastY, lastX, y, x); ! 44: lastY = y; ! 45: lastX = x; ! 46: } ! 47: } ! 48: ! 49: ! 50: /* This routine assumes the cursor is positioned correctly. */ ! 51: plot_addch(ch) ! 52: char ch; ! 53: { ! 54: putchar(ch); ! 55: if (++lastX >= COLS) { ! 56: if (AM) { ! 57: lastX = 0; ! 58: lastY++; ! 59: } else { ! 60: lastX = COLS - 1; ! 61: } ! 62: } ! 63: } ! 64: ! 65: ! 66: ! 67: ! 68: /* See the curses manual for what is been done and why. */ ! 69: openpl() ! 70: { ! 71: char *sp; ! 72: int closepl(); ! 73: ! 74: gettmode(); ! 75: if (sp=getenv("TERM")) ! 76: setterm(sp); ! 77: signal(SIGINT, closepl); ! 78: ! 79: } ! 80: ! 81: ! 82: ! 83: ! 84: closepl() ! 85: { ! 86: signal(SIGINT, SIG_IGN); ! 87: /* Leave cursor at top of screen. */ ! 88: mvcur(LINES-1, COLS-1, 0, 0); ! 89: endwin(); ! 90: exit(0); ! 91: } ! 92: ! 93: ! 94: ! 95: plot_move(x,y) ! 96: int x, y; ! 97: { ! 98: screen_move(scaleY(y), scaleX(x)); ! 99: } ! 100: ! 101: ! 102: ! 103: line(x0, y0, x1, y1) ! 104: int x0, y0, x1, y1; ! 105: { ! 106: plot_movech(y0, x0, '*'); ! 107: dda_line('*', scaleX(x0), scaleY(y0), scaleX(x1), scaleY(y1)); ! 108: } ! 109: ! 110: label(str) ! 111: char *str; ! 112: { ! 113: reg i, length; ! 114: int strlen(); ! 115: ! 116: if ( (length=strlen(str)) > (COLS-lastX) ) ! 117: length = COLS - lastX; ! 118: for (i=0; i<length; ++i) ! 119: plot_addch(str[i]); ! 120: } ! 121: ! 122: plot_erase() ! 123: { ! 124: /* ! 125: Some of these functions probably belong in openpl(). However, if the ! 126: input is being typed in, putting them in openpl would not work ! 127: since "noecho", etc would prevent (sort of) input. Notice that ! 128: the driver calls openpl before doing anything. This is actually ! 129: wrong, but it is what whoever originally wrote the driver decided ! 130: to do. (openpl() in libplot does nothing -- that is the main problem!) ! 131: */ ! 132: _puts(TI); ! 133: _puts(VS); ! 134: ! 135: noecho(); ! 136: nonl(); ! 137: tputs(CL, LINES, _putchar); ! 138: mvcur(0, COLS-1, LINES-1, 0); ! 139: lastX = 0; ! 140: lastY = LINES-1; ! 141: } ! 142: ! 143: ! 144: point(x, y) ! 145: int x,y; ! 146: { ! 147: plot_movech(y, x, '*'); ! 148: } ! 149: ! 150: ! 151: cont(x, y) ! 152: int x,y; ! 153: { ! 154: dda_line('*', lastX-1, lastY, scaleX(x), scaleY(y)); ! 155: } ! 156: ! 157: ! 158: space(x0, y0, x1, y1) ! 159: int x0, y0, x1, y1; ! 160: { ! 161: lowX = (double) x0; ! 162: lowY = (double) y0; ! 163: rangeX = COLS/(double) (x1 - x0); ! 164: rangeY = LINES/(double) (y1 - y0); ! 165: } ! 166: ! 167: ! 168: linemod(string) ! 169: char *string; ! 170: { ! 171: } ! 172: ! 173: ! 174: ! 175: /* See Neuman & Sproul for explanation and rationale. */ ! 176: /* Does not plot first point -- assumed that it is already plotted */ ! 177: dda_line(ch, x0, y0, x1, y1) ! 178: char ch; ! 179: int x0, y0, x1, y1; /* already transformed to screen coords */ ! 180: { ! 181: int length, i; ! 182: double deltaX, deltaY; ! 183: double x, y; ! 184: double floor(); ! 185: int abs(); ! 186: ! 187: length = abs(x1 - x0); ! 188: if (abs(y1 -y0) > length) ! 189: length = abs(y1 - y0); ! 190: ! 191: if (length == 0) ! 192: return; ! 193: ! 194: deltaX = (double) (x1 - x0)/(double) length; ! 195: deltaY = (double) (y1 - y0)/(double) length; ! 196: ! 197: x = (double) x0 + 0.5; ! 198: y = (double) y0 + 0.5; ! 199: ! 200: for (i=0; i < length; ++i) ! 201: { ! 202: x += deltaX; ! 203: y += deltaY; ! 204: screen_move((int) floor(y), (int) floor(x)); ! 205: plot_addch(ch); ! 206: } ! 207: } ! 208: ! 209: ! 210: circle (xc,yc,r) ! 211: int xc,yc,r; ! 212: { ! 213: arc(xc,yc, xc+r,yc, xc-r,yc); ! 214: arc(xc,yc, xc-r,yc, xc+r,yc); ! 215: } ! 216: ! 217: ! 218: /* should include test for equality? */ ! 219: #define side(x,y) (a*(x)+b*(y)+c > 0.0 ? 1 : -1) ! 220: ! 221: arc(xc,yc,xbeg,ybeg,xend,yend) ! 222: int xc,yc,xbeg,ybeg,xend,yend; ! 223: { ! 224: double r, radius, costheta, sintheta; ! 225: double a, b, c, x, y, tempX; ! 226: int right_side; ! 227: ! 228: xbeg -= xc; ybeg -= yc; ! 229: xend -= xc; yend -= yc; ! 230: ! 231: /* probably should check that arc is truely circular */ ! 232: /* Note: r is in screen coordinates. */ ! 233: r = sqrt( rangeX*rangeX*xbeg*xbeg + rangeY*rangeY*ybeg*ybeg); ! 234: ! 235: /* ! 236: This method is reasonably efficient, clean, and clever. ! 237: The easy part is generating the next point on the arc. This is ! 238: done by rotating the points by the angle theta. Theta is chosen ! 239: so that no rotation will cause more than one pixel of a move. ! 240: This corresponds to a triangle having 'x side' of r and 'y side' of 1. ! 241: The rotation is done (way) below inside the loop. ! 242: */ ! 243: if (r <= 1.0) { ! 244: /* radius is mapped to length < 1*/ ! 245: point(xc,yc); ! 246: return; ! 247: } ! 248: ! 249: radius = sqrt(r*r + 1.0); ! 250: sintheta = 1.0/radius; ! 251: costheta = r/radius; ! 252: ! 253: /* ! 254: The hard part of drawing an arc is figuring out when to stop. ! 255: This method works by drawing the line from the beginning point ! 256: to the ending point. This splits the plane in half, with the ! 257: arc that we wish to draw on one side of the line. If we evaluate ! 258: side(x,y) = a*x + b*y + c, then all of the points on one side of the ! 259: line will result in side being positive, and all the points on the ! 260: other side of the line will result in side being negative. ! 261: ! 262: We want to draw the arc in a counter-clockwise direction, so we ! 263: must find out what the sign of "side" is for a point which is to the ! 264: "right" of a line drawn from "beg" to "end". A point which must lie ! 265: on the right is [xbeg + (yend-ybeg), ybeg - (xend-xbeg)]. (This ! 266: point is perpendicular to the line at "beg"). ! 267: ! 268: Thus, we compute "side" of the above point, and then compare the ! 269: sign of side for each new point with the sign of the above point. ! 270: When they are different, we terminate the loop. ! 271: */ ! 272: ! 273: a = (double) (yend - ybeg); ! 274: b = (double) (xend - xbeg); ! 275: c = (double) (yend*xbeg - xend*ybeg); ! 276: right_side = side(xbeg + (yend-ybeg), ! 277: ybeg - (xend-xbeg) ); ! 278: ! 279: x = xbeg; ! 280: y = ybeg; ! 281: plot_move(xbeg+xc, ybeg+yc); ! 282: do { ! 283: dda_line('*',lastX-1, lastY, scaleX(xc + x), scaleY(yc + y )); ! 284: /* ! 285: screen_move( scaleY(yc + y), scaleX(xc + x) ); ! 286: plot_addch('*'); ! 287: */ ! 288: tempX = x; ! 289: x = x*costheta - y*sintheta; ! 290: y = tempX*sintheta + y*costheta; ! 291: } while( side(x,y) == right_side ); ! 292: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.