4.4BSD/usr/src/contrib/dipress/src/bin/dipress/bitdraw.c

Compare this file to the similar file:
Show the results in this format:


/******************************************************************************
 *  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, 1986 Xerox Corp.
 *
 ******************************************************************************/


#include <math.h>
#include <stdio.h>
#include <ctype.h>

#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<dis;j++)
		{	
			t = (float) j/dis;
			temp1 = 0.5 * t * t;
			temp2 = -temp1 - temp1 + t + 0.5;
			temp3 = temp1 - t + 0.5;

			xi = temp1 * x[i+2] + temp2 * x[i+1] + temp3 * x[i] + 0.5;
			yi = temp1 * y[i+2] + temp2 * y[i+1] + temp3 * y[i] + 0.5;
			if (xi != hor_pos || yi != ver_pos) 
			{
				hMov(xi);
				vMov(yi);
				setpixel();
			}
		}
	}
}


/*-----------------------------------------------------------------------------
 *	readNumber	read an integer from the string pointed to by *ptr,
 *			returning the integer in val, and updating *ptr for
 *			the caller
 *---------------------------------------------------------------------------*/
readNumber(ptr,val)
char **ptr;
int *val;
{
	int sign = 1;

	*val = 0;

	if (**ptr == '-')
	{
		sign = -1;
		++*ptr;
	}
	while(isdigit(**ptr))
	{
		*val = *val * 10 + **ptr - '0';
		++*ptr;
	}
	*val = *val * sign;

	/* skip all trailing white space */
	while(white(**ptr) || **ptr == '\n') ++*ptr; 

	/* return next char -- if at end of string this is NULL */
	return(**ptr);
}


/*-----------------------------------------------------------------------------
 *	euclidDist	compute euclidean distance between the two cartesian
 *			coordinates
 *---------------------------------------------------------------------------*/
float euclidDist(x, y, x1, y1)	
int x1,y1,x,y;
{
	double deltax, deltay;

	deltax = x - x1;
	deltay = y - y1;
	return(sqrt(deltax*deltax + deltay*deltay) + 0.5);
}