1: 2: /****************************************************************************** 3: * bitdraw - implements the bitmap drawing primitives necessary to turn 4: * ditroff draw commands into a pixel vector for interpress 5: * 6: * 7: * John Mellor-Crummey (Xerox Corp) 8: * 9: * Copyright (c) 1985 Xerox Corp. 10: * 11: ******************************************************************************/ 12: 13: 14: #include <math.h> 15: #include <stdio.h> 16: #include <ctype.h> 17: 18: #include "defs.h" 19: #include "externs.h" 20: 21: 22: /*------------------------------------------------------------------------------ 23: * bitmapDrawCircle incrementally compute the points for one octant 24: * of a circle and complete the figure by 25: * reflecting the points into each of the octants. 26: * 27: * based on an algorithm by J. Michener from 28: * Fundamentals of Interactive Computer Graphics, 29: * Foley & Van Dam, 1982, p. 445 30: *----------------------------------------------------------------------------*/ 31: bitmapDrawCircle(d) 32: int d; 33: { 34: int x,y,xc,yc,delta; 35: 36: xc = hor_pos + d/2; 37: yc = ver_pos; 38: delta = 3 - d; 39: x = 0; 40: y = d/2; 41: while ( x < y) 42: { 43: octPlot(x,y,xc,yc); 44: if (delta < 0) 45: delta = delta + 4 * x + 6; 46: else 47: { 48: delta = delta + 4 * (x - y) + 10; 49: y--; 50: } 51: x++; 52: } 53: if (x == y) octPlot(x,y,xc,yc); 54: hMov(xc + d/2); 55: vMov(yc); 56: } 57: 58: 59: /*------------------------------------------------------------------------------ 60: * octPlot reflect the point x,y into each of the eight 61: * octants centered about xc,yc and set the pixels 62: * in a bitmap 63: *----------------------------------------------------------------------------*/ 64: octPlot(x,y,xc,yc) 65: int x,y,xc,yc; 66: { 67: vMov(yc + y); 68: hMov(xc + x); setpixel(); 69: hMov(xc - x); setpixel(); 70: vMov(yc - y); setpixel(); 71: hMov(xc + x); setpixel(); 72: vMov(yc + x); 73: hMov(xc + y); setpixel(); 74: hMov(xc - y); setpixel(); 75: vMov(yc - x); setpixel(); 76: hMov(xc + y); setpixel(); 77: } 78: 79: /*------------------------------------------------------------------------------ 80: * bitmapDrawEllipse incrementally compute the points for one 81: * quadrant of an ellipse and complete the figure 82: * by reflecting the points into each of the 83: * quadrants. 84: *----------------------------------------------------------------------------*/ 85: bitmapDrawEllipse(xdiam,ydiam) 86: int xdiam,ydiam; 87: { 88: int x,y,xc,yc,a,b; 89: int fourAsq,fourAsqY; 90: int sixBsq,twoBsq,fourBsq,fourBsqX; 91: int d; 92: int midpoint; 93: 94: a = xdiam / 2; 95: b = ydiam / 2; 96: xc = hor_pos + a; 97: yc = ver_pos; 98: 99: x = 0; 100: y = b; 101: fourAsq = a * a * 4; 102: twoBsq = b * b * 2; 103: fourBsq = twoBsq + twoBsq; 104: sixBsq = fourBsq + twoBsq; 105: fourAsqY = fourAsq * y; 106: fourBsqX = 0; 107: midpoint = a * a * sqrt((double) 1.0 / (a * a + b * b)); 108: d = twoBsq + a * a * (2 * b + 1); 109: 110: while(x < midpoint) 111: { 112: quadPlot(x,y,xc,yc); 113: if (d > 0) /* case 2 -> y-- */ 114: { 115: d += fourAsq - fourAsqY; 116: fourAsqY -= fourAsq; 117: y--; 118: } 119: d += fourBsqX + sixBsq; 120: fourBsqX += fourBsq; 121: x++; 122: } 123: d -= twoBsq * x - b * b; 124: while(y >= 0) 125: { 126: quadPlot(x,y,xc,yc); 127: if (d > 0) /* case 3 -> x++ */ 128: { 129: d += fourBsqX + sixBsq; 130: fourBsqX += fourBsq; 131: x++; 132: } 133: d += fourAsq - fourAsqY; 134: fourAsqY -= fourAsq; 135: y--; 136: } 137: hMov(xc + a); 138: vMov(yc); 139: } 140: 141: 142: /*------------------------------------------------------------------------------ 143: * quadPlot reflect the point x,y into each of the four 144: * quadrants centered about xc,yc and set the pixels 145: * in a bitmap 146: *----------------------------------------------------------------------------*/ 147: quadPlot(x,y,xc,yc) 148: int x,y,xc,yc; 149: { 150: vMov(yc + y); 151: hMov(xc + x); setpixel(); 152: hMov(xc - x); setpixel(); 153: vMov(yc - y); setpixel(); 154: hMov(xc + x); setpixel(); 155: } 156: 157: 158: /*------------------------------------------------------------------------------ 159: * bitmapDrawCircle incrementally draw a circular arc in a c 160: * counterclockwise direction. the arguments are 161: * relative coordinates for the center point 162: * from the current point, and the termination 163: * point from the center point. 164: * 165: * based on an algorithm by J. Bresenham 166: * A Linear Algorithm for Incremental Digital 167: * Display of Circular Arcs, Communications of the ACM, 168: * Feb. 1977, pp. 103-104. 169: *----------------------------------------------------------------------------*/ 170: bitmapDrawArc(relxc,relyc,relxt,relyt) 171: int relxc,relyc,relxt,relyt; 172: { 173: int xc,yc; 174: int Xsprime,Ysprime,Xtprime,Ytprime; 175: int Xshat,Yshat,Xthat,Ythat,Xs,Ys,Xt,Yt,Xi,Yi; 176: int delta,deltai,deltaprime; 177: int M1x,M1y,M2x,M2y,M3x,M3y; 178: int q,qs,qt,qstar; 179: int move; 180: int xsave; 181: int radius; 182: double angle; 183: int xplot,yplot; 184: 185: xc = hor_pos + relxc; 186: yc = ver_pos + relyc; 187: Xtprime = hor_pos; 188: Ytprime = ver_pos; 189: Xsprime = relxt + xc; 190: Ysprime = relyt + yc; 191: 192: /* get the radius from the start point */ 193: radius = hypot((double) relxc,(double) relyc); 194: 195: /* readjust start point to be sure it is on proper grid point */ 196: angle = atan2((double) (Ysprime - yc),(double) (Xsprime - xc)); 197: xplot = Xsprime = radius * cos(angle) + xc + .5; 198: yplot = Ysprime = radius * sin(angle) + yc + .5; 199: 200: /* readjust termination point to be sure it is on proper grid point */ 201: angle = atan2((double) (Ytprime - yc),(double) (Xtprime - xc)); 202: Xtprime = radius * cos(angle) + xc + .5; 203: Ytprime = radius * sin(angle) + yc + .5; 204: 205: /* compute start and end points of the arc as relative coordinates */ 206: Xshat = Xsprime - xc; 207: Yshat = Ysprime - yc; 208: Xthat = Xtprime - xc; 209: Ythat = Ytprime - yc; 210: 211: /* implement the quadrant transforms to normalize to first quadrant 212: * for both start and end points 213: */ 214: 215: if (Xshat < 0) 216: { 217: if (Yshat < 0) 218: { 219: Xs = abs(Yshat); 220: Ys = abs(Xshat); 221: qs = 3; 222: M1x = 0; M1y = -1; 223: M2x = 1; M2y = -1; 224: M3x = 1; M3y = 0; 225: } 226: else 227: { 228: Xs = abs(Xshat); 229: Ys = abs(Yshat); 230: qs = 2; 231: M1x = -1; M1y = 0; 232: M2x = -1; M2y = -1; 233: M3x = 0; M3y = -1; 234: } 235: } 236: else 237: { 238: if (Yshat < 0) 239: { 240: Xs = abs(Xshat); 241: Ys = abs(Yshat); 242: qs = 0; 243: M1x = 1; M1y = 0; 244: M2x = 1; M2y = 1; 245: M3x = 0; M3y = 1; 246: } 247: else 248: { 249: Xs = abs(Yshat); 250: Ys = abs(Xshat); 251: qs = 1; 252: M1x = 0; M1y = 1; 253: M2x = -1; M2y = 1; 254: M3x = -1; M3y = 0; 255: } 256: } 257: 258: if (Xthat < 0) 259: { 260: if (Ythat < 0) 261: { 262: Xt = abs(Ythat); 263: Yt = abs(Xthat); 264: qt = 3; 265: } 266: else 267: { 268: Xt = abs(Xthat); 269: Yt = abs(Ythat); 270: qt = 2; 271: } 272: } 273: else 274: { 275: if (Ythat < 0) 276: { 277: Xt = abs(Xthat); 278: Yt = abs(Ythat); 279: qt = 0; 280: } 281: else 282: { 283: Xt = abs(Ythat); 284: Yt = abs(Xthat); 285: qt = 1; 286: } 287: } 288: 289: /* calculate number of quadrants */ 290: qstar = (4 + qt - qs) % 4; 291: if ((qstar == 0) && (Xt <= Xs) && (Yt >= Ys)) 292: q = 3; 293: else q = qstar - 1; 294: 295: /* initialize for iteration */ 296: deltai = 2 * (Xs - Ys + 1); 297: Xi = Xs; 298: Yi = Ys; 299: 300: while(TRUE) 301: { 302: if ((q < 0) && (Xt <= Xi) && (Yt >= Yi)) 303: break; 304: 305: hMov(xplot); 306: vMov(yplot); 307: setpixel(); 308: 309: if (Yi < 1) 310: { 311: xsave = Xi; 312: Xi = - Yi; 313: Yi = xsave; 314: deltai = deltai - 4 * xsave; 315: 316: q = q - 1; 317: M1x = M3x; 318: M1y = M3y; 319: 320: xsave = M2x; 321: M2x = - M2y; 322: M2y = xsave; 323: 324: xsave = M3x; 325: M3x = - M3y; 326: M3y = xsave; 327: 328: continue; 329: } 330: if (deltai <= 0) 331: { 332: delta = 2 * (deltai + Yi) - 1; 333: if (delta > 0) 334: move = M2; 335: else move = M1; 336: } 337: else 338: { 339: deltaprime = 2 * (deltai - Xi) - 1; 340: if (deltaprime > 0) 341: move = M3; 342: else move = M2; 343: } 344: 345: switch(move) 346: { 347: case M1: 348: Xi++; 349: deltai = deltai + 2* Xi + 1; 350: xplot += M1x; 351: yplot += M1y; 352: break; 353: case M2: 354: Xi++; 355: Yi--; 356: deltai = deltai + 2* (Xi - Yi) + 2; 357: xplot += M2x; 358: yplot += M2y; 359: break; 360: case M3: 361: Yi--; 362: deltai = deltai - 2 * Yi + 1; 363: xplot += M3x; 364: yplot += M3y; 365: break; 366: } 367: } 368: } 369: 370: 371: /*------------------------------------------------------------------------------ 372: * bitmapDrawWigglyLine interpolate a curve between the sets of 373: * relative points. the interpolation is done 374: * using a spline like method to produce a curve 375: * compatible with other output of ipic 376: * (if the wiggly line should have arrowheads, 377: * ipic assumes that the wiggly line will pass 378: * close to the 2nd to last point in the curve 379: * when it computes the tilt of the arrowheads. 380: * For a smoother curve such as a 381: * B-spline, the arrowheads will not be tilted 382: * correctly as the spline is not guaranteed to 383: * pass through the 2nd to last point) 384: *----------------------------------------------------------------------------*/ 385: bitmapDrawWigglyLine(s) 386: char *s; 387: { 388: int x[maxPointsInSpline],y[maxPointsInSpline]; 389: int xi,yi,i,j,numPoints; 390: float temp1,temp2,temp3,t,dis; 391: float euclidDist(); 392: 393: /* skip all leading white space */ 394: while(white(*s)) s++; 395: if(!isdigit(*s)) return; 396: 397: /* read in the x y pairs of points for the spline */ 398: for(numPoints = 2; ((numPoints< maxPointsInSpline) && 399: (readNumber(&s,&x[numPoints]) != NULL) && 400: (readNumber(&s,&y[numPoints]) != NULL)); numPoints++); 401: numPoints++; 402: 403: /* first point of curve is current point */ 404: x[1] = hor_pos; 405: y[1] = ver_pos; 406: 407: /* turn relative points into absolute points */ 408: for (i = 2; i < numPoints; i++) 409: { 410: x[i] += x[i-1]; 411: y[i] += y[i-1]; 412: } 413: 414: /* if the wiggle's ends meet, insure the curve meets */ 415: if ((x[1] == x[numPoints-1]) && (y[1] == y[numPoints-1])) 416: { 417: x[0] = x[numPoints-2]; 418: y[0] = y[numPoints-2]; 419: x[numPoints] = x[2]; 420: y[numPoints] = y[2]; 421: } 422: else 423: { 424: x[0] = x[1]; 425: y[0] = y[1]; 426: x[numPoints] = x[numPoints-1]; 427: y[numPoints] = y[numPoints-1]; 428: } 429: numPoints++; 430: 431: /* position next pointers to the start of spline */ 432: hMov((x[0] + x[1]) / 2); 433: vMov((y[0] + y[1]) / 2); 434: 435: for (i = 0; i < numPoints - 2; i++) 436: { 437: dis = (euclidDist(x[i],y[i], x[i+1],y[i+1]) + 438: euclidDist(x[i+1],y[i+1], x[i+2],y[i+2])) / 2; 439: for(j=1;j<dis;j++) 440: { 441: t = (float) j/dis; 442: temp1 = 0.5 * t * t; 443: temp2 = -temp1 - temp1 + t + 0.5; 444: temp3 = temp1 - t + 0.5; 445: 446: xi = temp1 * x[i+2] + temp2 * x[i+1] + temp3 * x[i] + 0.5; 447: yi = temp1 * y[i+2] + temp2 * y[i+1] + temp3 * y[i] + 0.5; 448: if (xi != hor_pos || yi != ver_pos) 449: { 450: hMov(xi); 451: vMov(yi); 452: setpixel(); 453: } 454: } 455: } 456: } 457: 458: 459: /*----------------------------------------------------------------------------- 460: * readNumber read an integer from the string pointed to by *ptr, 461: * returning the integer in val, and updating *ptr for 462: * the caller 463: *---------------------------------------------------------------------------*/ 464: readNumber(ptr,val) 465: char **ptr; 466: int *val; 467: { 468: int sign = 1; 469: 470: *val = 0; 471: 472: if (**ptr == '-') 473: { 474: sign = -1; 475: ++*ptr; 476: } 477: while(isdigit(**ptr)) 478: { 479: *val = *val * 10 + **ptr - '0'; 480: ++*ptr; 481: } 482: *val = *val * sign; 483: 484: /* skip all trailing white space */ 485: while(white(**ptr) || **ptr == '\n') ++*ptr; 486: 487: /* return next char -- if at end of string this is NULL */ 488: return(**ptr); 489: } 490: 491: 492: /*----------------------------------------------------------------------------- 493: * euclidDist compute euclidean distance between the two cartesian 494: * coordinates 495: *---------------------------------------------------------------------------*/ 496: float euclidDist(x, y, x1, y1) 497: int x1,y1,x,y; 498: { 499: double deltax, deltay; 500: 501: deltax = x - x1; 502: deltay = y - y1; 503: return(sqrt(deltax*deltax + deltay*deltay) + 0.5); 504: }