Antialiased line

If you have a cool piece of software to share, but you are not hosting it officially yet, please dump it in here. If you have code snippets that are useful, please donate!
Post Reply
lester
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 211
Joined: Sat Sep 02, 2006 7:24 pm
Location: Ukraine

Antialiased line

Post by lester » Sat Mar 29, 2008 9:52 am

wxWidgets implementation of Wu's algorithm

Code: Select all

/**********************************************************************************************/
wxColour GetColorAverage( wxColour color1, wxColour color2, float weight)
{
	unsigned char r, g, b;

	r = (unsigned char)( 1.0 * color1.Red() * weight + 1.0 * color2.Red() * ( 1 - weight) );
	g = (unsigned char)( 1.0 * color1.Green() * weight + 1.0 * color2.Green() * ( 1 - weight) );
	b = (unsigned char)(1.0 * color1.Blue() * weight + 1.0 * color2.Blue() * ( 1 - weight) );

	return wxColour(r, g, b);
} 

/**********************************************************************************************/
void DrawWuLine( wxDC *pDC, short X0, short Y0, short X1, short Y1 )
{
	wxASSERT( pDC );

	if( !pDC )
		return;

	wxColour cl = pDC->GetPen().GetColour();
	wxColour clb = pDC->GetBrush().GetColour();
	unsigned short IntensityShift, ErrorAdj, ErrorAcc;
	unsigned short ErrorAccTemp, Weighting, WeightingComplementMask;
	short DeltaX, DeltaY, Temp, XDir;

	/* Make sure the line runs top to bottom */
	if (Y0 > Y1) {
		Temp = Y0; Y0 = Y1; Y1 = Temp;
		Temp = X0; X0 = X1; X1 = Temp;
	}
	/* Draw the initial pixel, which is always exactly intersected by
	the line and so needs no weighting */
	pDC->SetPen( cl );
	pDC->DrawPoint( X0, Y0 );

	if ((DeltaX = X1 - X0) >= 0) {
		XDir = 1;
	} else {
		XDir = -1;
		DeltaX = -DeltaX; /* make DeltaX positive */
	}
	/* Special-case horizontal, vertical, and diagonal lines, which
	require no weighting because they go right through the center of
	every pixel */
	if ((DeltaY = Y1 - Y0) == 0) {
		/* Horizontal line */
		while (DeltaX-- != 0) {
			X0 += XDir;
			pDC->DrawPoint( X0, Y0 );
		}
		return;
	}
	if (DeltaX == 0) {
		/* Vertical line */
		do {
			Y0++;
			pDC->DrawPoint( X0, Y0 );
		} while (--DeltaY != 0);
		return;
	}
	if (DeltaX == DeltaY) {
		/* Diagonal line */
		do {
			X0 += XDir;
			Y0++;
			pDC->DrawPoint( X0, Y0 );
		} while (--DeltaY != 0);
		return;
	}
	/* Line is not horizontal, diagonal, or vertical */
	ErrorAcc = 0;  /* initialize the line error accumulator to 0 */
	/* # of bits by which to shift ErrorAcc to get intensity level */
	IntensityShift = 8;
	/* Mask used to flip all bits in an intensity weighting, producing the
	result (1 - intensity weighting) */
	WeightingComplementMask = 255;
	/* Is this an X-major or Y-major line? */
	if (DeltaY > DeltaX) {
		/* Y-major line; calculate 16-bit fixed-point fractional part of a
		pixel that X advances each time Y advances 1 pixel, truncating the
		result so that we won't overrun the endpoint along the X axis */
		ErrorAdj = ((unsigned long) DeltaX << 16) / (unsigned long) DeltaY;
		/* Draw all pixels other than the first and last */
		while (--DeltaY) {
			ErrorAccTemp = ErrorAcc;   /* remember current accumulated error */
			ErrorAcc += ErrorAdj;      /* calculate error for next pixel */
			if (ErrorAcc <= ErrorAccTemp) {
				/* The error accumulator turned over, so advance the X coord */
				X0 += XDir;
			}
			Y0++; /* Y-major, so always advance Y */
			/* The IntensityBits most significant bits of ErrorAcc give us the
			intensity weighting for this pixel, and the complement of the
			weighting for the paired pixel */
			Weighting = ErrorAcc >> IntensityShift;

			wxColour cl2 = GetColorAverage( clb, cl, 1. * Weighting / 255 );
			pDC->SetPen( cl2 );
			pDC->DrawPoint( X0, Y0 );
			cl2 = GetColorAverage( clb, cl, 1. * ( Weighting ^ WeightingComplementMask ) / 255 );
			pDC->SetPen( cl2 );
			pDC->DrawPoint( X0 + XDir, Y0 );
		}
		/* Draw the final pixel, which is 
		always exactly intersected by the line
		and so needs no weighting */
		pDC->SetPen( cl );
		pDC->DrawPoint( X1, Y1 );
		return;
	}
	/* It's an X-major line; calculate 16-bit fixed-point fractional part of a
	pixel that Y advances each time X advances 1 pixel, truncating the
	result to avoid overrunning the endpoint along the X axis */
	ErrorAdj = ((unsigned long) DeltaY << 16) / (unsigned long) DeltaX;
	/* Draw all pixels other than the first and last */
	while (--DeltaX) {
		ErrorAccTemp = ErrorAcc;   /* remember currrent accumulated error */
		ErrorAcc += ErrorAdj;      /* calculate error for next pixel */
		if (ErrorAcc <= ErrorAccTemp) {
			/* The error accumulator turned over, so advance the Y coord */
			Y0++;
		}
		X0 += XDir; /* X-major, so always advance X */
		/* The IntensityBits most significant bits of ErrorAcc give us the
		intensity weighting for this pixel, and the complement of the
		weighting for the paired pixel */
		Weighting = ErrorAcc >> IntensityShift;
		wxColour cl2 = GetColorAverage( clb, cl, 1. * Weighting / 255 );
		pDC->SetPen( cl2 );
		pDC->DrawPoint( X0, Y0 );
		cl2 = GetColorAverage( clb, cl, 1. * ( Weighting ^ WeightingComplementMask ) / 255 );
		pDC->SetPen( cl2 );
		pDC->DrawPoint( X0, Y0 + 1 );
	}
	/* Draw the final pixel, which is always exactly intersected by the line
	and so needs no weighting */
	pDC->SetPen( cl );
	pDC->DrawPoint( X1, Y1 );
}

Post Reply