/****************************************************************************** * bitdraw - implements the bitmap drawing primitives necessary to turn * ditroff draw commands into a pixel vector for interpress * * * John Mellor-Crummey (Xerox Corp) * * Copyright (c) 1985 Xerox Corp. * ******************************************************************************/ #include #include #include #include "defs.h" #include "externs.h" /*------------------------------------------------------------------------------ * bitmapDrawCircle incrementally compute the points for one octant * of a circle and complete the figure by * reflecting the points into each of the octants. * * based on an algorithm by J. Michener from * Fundamentals of Interactive Computer Graphics, * Foley & Van Dam, 1982, p. 445 *----------------------------------------------------------------------------*/ bitmapDrawCircle(d) int d; { int x,y,xc,yc,delta; xc = hor_pos + d/2; yc = ver_pos; delta = 3 - d; x = 0; y = d/2; while ( x < y) { octPlot(x,y,xc,yc); if (delta < 0) delta = delta + 4 * x + 6; else { delta = delta + 4 * (x - y) + 10; y--; } x++; } if (x == y) octPlot(x,y,xc,yc); hMov(xc + d/2); vMov(yc); } /*------------------------------------------------------------------------------ * octPlot reflect the point x,y into each of the eight * octants centered about xc,yc and set the pixels * in a bitmap *----------------------------------------------------------------------------*/ octPlot(x,y,xc,yc) int x,y,xc,yc; { vMov(yc + y); hMov(xc + x); setpixel(); hMov(xc - x); setpixel(); vMov(yc - y); setpixel(); hMov(xc + x); setpixel(); vMov(yc + x); hMov(xc + y); setpixel(); hMov(xc - y); setpixel(); vMov(yc - x); setpixel(); hMov(xc + y); setpixel(); } /*------------------------------------------------------------------------------ * bitmapDrawEllipse incrementally compute the points for one * quadrant of an ellipse and complete the figure * by reflecting the points into each of the * quadrants. *----------------------------------------------------------------------------*/ bitmapDrawEllipse(xdiam,ydiam) int xdiam,ydiam; { int x,y,xc,yc,a,b; int fourAsq,fourAsqY; int sixBsq,twoBsq,fourBsq,fourBsqX; int d; int midpoint; a = xdiam / 2; b = ydiam / 2; xc = hor_pos + a; yc = ver_pos; x = 0; y = b; fourAsq = a * a * 4; twoBsq = b * b * 2; fourBsq = twoBsq + twoBsq; sixBsq = fourBsq + twoBsq; fourAsqY = fourAsq * y; fourBsqX = 0; midpoint = a * a * sqrt((double) 1.0 / (a * a + b * b)); d = twoBsq + a * a * (2 * b + 1); while(x < midpoint) { quadPlot(x,y,xc,yc); if (d > 0) /* case 2 -> y-- */ { d += fourAsq - fourAsqY; fourAsqY -= fourAsq; y--; } d += fourBsqX + sixBsq; fourBsqX += fourBsq; x++; } d -= twoBsq * x - b * b; while(y >= 0) { quadPlot(x,y,xc,yc); if (d > 0) /* case 3 -> x++ */ { d += fourBsqX + sixBsq; fourBsqX += fourBsq; x++; } d += fourAsq - fourAsqY; fourAsqY -= fourAsq; y--; } hMov(xc + a); vMov(yc); } /*------------------------------------------------------------------------------ * quadPlot reflect the point x,y into each of the four * quadrants centered about xc,yc and set the pixels * in a bitmap *----------------------------------------------------------------------------*/ quadPlot(x,y,xc,yc) int x,y,xc,yc; { vMov(yc + y); hMov(xc + x); setpixel(); hMov(xc - x); setpixel(); vMov(yc - y); setpixel(); hMov(xc + x); setpixel(); } /*------------------------------------------------------------------------------ * bitmapDrawCircle incrementally draw a circular arc in a c * counterclockwise direction. the arguments are * relative coordinates for the center point * from the current point, and the termination * point from the center point. * * based on an algorithm by J. Bresenham * A Linear Algorithm for Incremental Digital * Display of Circular Arcs, Communications of the ACM, * Feb. 1977, pp. 103-104. *----------------------------------------------------------------------------*/ bitmapDrawArc(relxc,relyc,relxt,relyt) int relxc,relyc,relxt,relyt; { int xc,yc; int Xsprime,Ysprime,Xtprime,Ytprime; int Xshat,Yshat,Xthat,Ythat,Xs,Ys,Xt,Yt,Xi,Yi; int delta,deltai,deltaprime; int M1x,M1y,M2x,M2y,M3x,M3y; int q,qs,qt,qstar; int move; int xsave; int radius; double angle; int xplot,yplot; xc = hor_pos + relxc; yc = ver_pos + relyc; Xtprime = hor_pos; Ytprime = ver_pos; Xsprime = relxt + xc; Ysprime = relyt + yc; /* get the radius from the start point */ radius = hypot((double) relxc,(double) relyc); /* readjust start point to be sure it is on proper grid point */ angle = atan2((double) (Ysprime - yc),(double) (Xsprime - xc)); xplot = Xsprime = radius * cos(angle) + xc + .5; yplot = Ysprime = radius * sin(angle) + yc + .5; /* readjust termination point to be sure it is on proper grid point */ angle = atan2((double) (Ytprime - yc),(double) (Xtprime - xc)); Xtprime = radius * cos(angle) + xc + .5; Ytprime = radius * sin(angle) + yc + .5; /* compute start and end points of the arc as relative coordinates */ Xshat = Xsprime - xc; Yshat = Ysprime - yc; Xthat = Xtprime - xc; Ythat = Ytprime - yc; /* implement the quadrant transforms to normalize to first quadrant * for both start and end points */ if (Xshat < 0) { if (Yshat < 0) { Xs = abs(Yshat); Ys = abs(Xshat); qs = 3; M1x = 0; M1y = -1; M2x = 1; M2y = -1; M3x = 1; M3y = 0; } else { Xs = abs(Xshat); Ys = abs(Yshat); qs = 2; M1x = -1; M1y = 0; M2x = -1; M2y = -1; M3x = 0; M3y = -1; } } else { if (Yshat < 0) { Xs = abs(Xshat); Ys = abs(Yshat); qs = 0; M1x = 1; M1y = 0; M2x = 1; M2y = 1; M3x = 0; M3y = 1; } else { Xs = abs(Yshat); Ys = abs(Xshat); qs = 1; M1x = 0; M1y = 1; M2x = -1; M2y = 1; M3x = -1; M3y = 0; } } if (Xthat < 0) { if (Ythat < 0) { Xt = abs(Ythat); Yt = abs(Xthat); qt = 3; } else { Xt = abs(Xthat); Yt = abs(Ythat); qt = 2; } } else { if (Ythat < 0) { Xt = abs(Xthat); Yt = abs(Ythat); qt = 0; } else { Xt = abs(Ythat); Yt = abs(Xthat); qt = 1; } } /* calculate number of quadrants */ qstar = (4 + qt - qs) % 4; if ((qstar == 0) && (Xt <= Xs) && (Yt >= Ys)) q = 3; else q = qstar - 1; /* initialize for iteration */ deltai = 2 * (Xs - Ys + 1); Xi = Xs; Yi = Ys; while(TRUE) { if ((q < 0) && (Xt <= Xi) && (Yt >= Yi)) break; hMov(xplot); vMov(yplot); setpixel(); if (Yi < 1) { xsave = Xi; Xi = - Yi; Yi = xsave; deltai = deltai - 4 * xsave; q = q - 1; M1x = M3x; M1y = M3y; xsave = M2x; M2x = - M2y; M2y = xsave; xsave = M3x; M3x = - M3y; M3y = xsave; continue; } if (deltai <= 0) { delta = 2 * (deltai + Yi) - 1; if (delta > 0) move = M2; else move = M1; } else { deltaprime = 2 * (deltai - Xi) - 1; if (deltaprime > 0) move = M3; else move = M2; } switch(move) { case M1: Xi++; deltai = deltai + 2* Xi + 1; xplot += M1x; yplot += M1y; break; case M2: Xi++; Yi--; deltai = deltai + 2* (Xi - Yi) + 2; xplot += M2x; yplot += M2y; break; case M3: Yi--; deltai = deltai - 2 * Yi + 1; xplot += M3x; yplot += M3y; break; } } } /*------------------------------------------------------------------------------ * bitmapDrawWigglyLine interpolate a curve between the sets of * relative points. the interpolation is done * using a spline like method to produce a curve * compatible with other output of ipic * (if the wiggly line should have arrowheads, * ipic assumes that the wiggly line will pass * close to the 2nd to last point in the curve * when it computes the tilt of the arrowheads. * For a smoother curve such as a * B-spline, the arrowheads will not be tilted * correctly as the spline is not guaranteed to * pass through the 2nd to last point) *----------------------------------------------------------------------------*/ bitmapDrawWigglyLine(s) char *s; { int x[maxPointsInSpline],y[maxPointsInSpline]; int xi,yi,i,j,numPoints; float temp1,temp2,temp3,t,dis; float euclidDist(); /* skip all leading white space */ while(white(*s)) s++; if(!isdigit(*s)) return; /* read in the x y pairs of points for the spline */ for(numPoints = 2; ((numPoints< maxPointsInSpline) && (readNumber(&s,&x[numPoints]) != NULL) && (readNumber(&s,&y[numPoints]) != NULL)); numPoints++); numPoints++; /* first point of curve is current point */ x[1] = hor_pos; y[1] = ver_pos; /* turn relative points into absolute points */ for (i = 2; i < numPoints; i++) { x[i] += x[i-1]; y[i] += y[i-1]; } /* if the wiggle's ends meet, insure the curve meets */ if ((x[1] == x[numPoints-1]) && (y[1] == y[numPoints-1])) { x[0] = x[numPoints-2]; y[0] = y[numPoints-2]; x[numPoints] = x[2]; y[numPoints] = y[2]; } else { x[0] = x[1]; y[0] = y[1]; x[numPoints] = x[numPoints-1]; y[numPoints] = y[numPoints-1]; } numPoints++; /* position next pointers to the start of spline */ hMov((x[0] + x[1]) / 2); vMov((y[0] + y[1]) / 2); for (i = 0; i < numPoints - 2; i++) { dis = (euclidDist(x[i],y[i], x[i+1],y[i+1]) + euclidDist(x[i+1],y[i+1], x[i+2],y[i+2])) / 2; for(j=1;j