www.pudn.com > XAnalogClock_demo.zip > WuLine.cpp


// 
// Antialiasing: Wu Algorithm by .Suchit 
// http://www.codeproject.com/gdi/antialias.asp 
// 
 
#include "stdafx.h" 
#include "WuLine.h" 
 
void DrawWuLine(CDC *pDC, int X0, int Y0, int X1, int Y1, COLORREF clrLine) 
{ 
	/* Make sure the line runs top to bottom */ 
	if (Y0 > Y1) 
	{ 
		int 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->SetPixel(X0, Y0, clrLine); 
 
	int XDir, DeltaX = X1 - X0; 
	if(DeltaX >= 0) 
	{ 
		XDir = 1; 
	} 
	else 
	{ 
		XDir   = -1; 
		DeltaX = 0 - 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 */ 
	int DeltaY = Y1 - Y0; 
	if (DeltaY == 0) 
	{ 
		/* Horizontal line */ 
		while (DeltaX-- != 0) 
		{ 
			X0 += XDir; 
			pDC->SetPixel(X0, Y0, clrLine); 
		} 
		return; 
	} 
	if (DeltaX == 0) 
	{ 
		/* Vertical line */ 
		do 
		{ 
			Y0++; 
			pDC->SetPixel(X0, Y0, clrLine); 
		} while (--DeltaY != 0); 
		return; 
	} 
 
	if (DeltaX == DeltaY) 
	{ 
		/* Diagonal line */ 
		do 
		{ 
			X0 += XDir; 
			Y0++; 
			pDC->SetPixel(X0, Y0, clrLine); 
		} while (--DeltaY != 0); 
		return; 
	} 
 
	unsigned short ErrorAdj; 
	unsigned short ErrorAccTemp, Weighting; 
 
	/* Line is not horizontal, diagonal, or vertical */ 
	unsigned short ErrorAcc = 0;  /* initialize the line error accumulator to 0 */ 
 
	BYTE rl = GetRValue(clrLine); 
	BYTE gl = GetGValue(clrLine); 
	BYTE bl = GetBValue(clrLine); 
	double grayl = rl * 0.299 + gl * 0.587 + bl * 0.114; 
 
	/* 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 short) 
			(((unsigned long) DeltaX << 16) / (unsigned long) DeltaY); 
		/* Draw all pixels other than the first and last */ 
		while (--DeltaY) 
		{ 
			ErrorAccTemp = ErrorAcc;   /* remember currrent accumulated error */ 
			ErrorAcc = (unsigned short)(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 = (unsigned short) (ErrorAcc >> 8); 
			ASSERT(Weighting < 256); 
			ASSERT((Weighting ^ 255) < 256); 
 
			COLORREF clrBackGround = ::GetPixel(pDC->m_hDC, X0, Y0); 
			BYTE rb = GetRValue(clrBackGround); 
			BYTE gb = GetGValue(clrBackGround); 
			BYTE bb = GetBValue(clrBackGround); 
			double grayb = rb * 0.299 + gb * 0.587 + bb * 0.114; 
 
			BYTE rr = (rb > rl ? ((BYTE)(((double)(grayl gl ? ((BYTE)(((double)(grayl bl ? ((BYTE)(((double)(graylSetPixel(X0, Y0, RGB(rr, gr, br)); 
 
			clrBackGround = ::GetPixel(pDC->m_hDC, X0 + XDir, Y0); 
			rb = GetRValue(clrBackGround); 
			gb = GetGValue(clrBackGround); 
			bb = GetBValue(clrBackGround); 
			grayb = rb * 0.299 + gb * 0.587 + bb * 0.114; 
 
			rr = (rb > rl ? ((BYTE)(((double)(grayl gl ? ((BYTE)(((double)(grayl bl ? ((BYTE)(((double)(graylSetPixel(X0 + XDir, Y0, RGB(rr, gr, br)); 
		} 
		/* Draw the final pixel, which is always exactly intersected by the line 
		and so needs no weighting */ 
		pDC->SetPixel(X1, Y1, clrLine); 
		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 short)(((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 = (unsigned short)(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 = (unsigned short) (ErrorAcc >> 8); 
		ASSERT(Weighting < 256); 
		ASSERT((Weighting ^ 255) < 256); 
 
		COLORREF clrBackGround = ::GetPixel(pDC->m_hDC, X0, Y0); 
		BYTE rb = GetRValue(clrBackGround); 
		BYTE gb = GetGValue(clrBackGround); 
		BYTE bb = GetBValue(clrBackGround); 
		double grayb = rb * 0.299 + gb * 0.587 + bb * 0.114; 
 
		BYTE rr = (rb > rl ? ((BYTE)(((double)(grayl gl ? ((BYTE)(((double)(grayl bl ? ((BYTE)(((double)(graylSetPixel(X0, Y0, RGB(rr, gr, br)); 
 
		clrBackGround = ::GetPixel(pDC->m_hDC, X0, Y0 + 1); 
		rb = GetRValue(clrBackGround); 
		gb = GetGValue(clrBackGround); 
		bb = GetBValue(clrBackGround); 
		grayb = rb * 0.299 + gb * 0.587 + bb * 0.114; 
 
		rr = (rb > rl ? ((BYTE)(((double)(grayl gl ? ((BYTE)(((double)(grayl bl ? ((BYTE)(((double)(graylSetPixel(X0, Y0 + 1, RGB(rr, gr, br)); 
	} 
 
	/* Draw the final pixel, which is always exactly intersected by the line 
	and so needs no weighting */ 
	pDC->SetPixel(X1, Y1, clrLine); 
}