drawline produces broken lines Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
anandvincent78
Earned a small fee
Earned a small fee
Posts: 17
Joined: Fri Oct 05, 2007 8:46 am

drawline produces broken lines

Post by anandvincent78 » Fri Mar 28, 2008 2:44 pm

Some of the lines in my drawing are broken. Please see the file attached. Any solution to how to draw absolutely smooth lines would be greatly appreciated.

Thanks
Anand.
Wxwidgets 2.8.9
OS WindowsXP
IDE VS 2005

lester
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 211
Joined: Sat Sep 02, 2006 7:24 pm
Location: Ukraine

Post by lester » Fri Mar 28, 2008 2:45 pm

Are You sure that attach file? I cannot see it

anandvincent78
Earned a small fee
Earned a small fee
Posts: 17
Joined: Fri Oct 05, 2007 8:46 am

Post by anandvincent78 » Fri Mar 28, 2008 3:06 pm

I am sorry. Will attach now
Attachments
arcids.PNG
Wxwidgets 2.8.9
OS WindowsXP
IDE VS 2005

tan
Moderator
Moderator
Posts: 1471
Joined: Tue Nov 14, 2006 7:58 am
Location: Saint-Petersburg, Russia

Post by tan » Fri Mar 28, 2008 3:29 pm

Hi,
i absolutely don't sure, but you could try to make drawing with wxGCDC.
OS: Windows XP Pro
Compiler: MSVC++ 7.1
wxWidgets: 2.8.10

Auria
Site Admin
Site Admin
Posts: 6695
Joined: Thu Sep 28, 2006 12:23 am
Contact:

Post by Auria » Fri Mar 28, 2008 5:55 pm

I personnaly render my stuff with OpenGL, where there is smooth line support... even though that may be an overkill for what you are trying to do.

phlox81
wxWorld Domination!
wxWorld Domination!
Posts: 1387
Joined: Thu Aug 18, 2005 7:49 pm
Location: Germany
Contact:

Post by phlox81 » Fri Mar 28, 2008 7:06 pm

Auria wrote:I personnaly render my stuff with OpenGL, where there is smooth line support... even though that may be an overkill for what you are trying to do.
Well, I think there should be also a way for wxWidgets to that... ;)

Jorg
Moderator
Moderator
Posts: 3971
Joined: Fri Aug 27, 2004 9:38 pm
Location: Delft, Netherlands
Contact:

Post by Jorg » Fri Mar 28, 2008 7:10 pm

It might be totally stupid what I am saying, but there is nothing broken with the lines. It seems you are drawing two lines over eachother, slightly mispositioned.

If you look at the top part you are drawing lines 10, 107 and 112. And at the bottom part, where it looks jagged you are drawing one line over the other you are drawing 17, 110, 113 and 111. So the only issue you have is anti-aliasing, there is nothing "broken" with line drawing here.

With regards,
- Jorgen
Forensic Software Engineer
Netherlands Forensic Insitute
http://english.forensischinstituut.nl/
-------------------------------------
Jorg's WasteBucket
http://www.xs4all.nl/~jorgb/wb

Auria
Site Admin
Site Admin
Posts: 6695
Joined: Thu Sep 28, 2006 12:23 am
Contact:

Post by Auria » Fri Mar 28, 2008 7:12 pm

Well it depends what he means with "broken". I took it he meant "non-anti-aliased"; maybe precise it?

lester
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 211
Joined: Sat Sep 02, 2006 7:24 pm
Location: Ukraine

Post by lester » Fri Mar 28, 2008 7:44 pm

I have found one example:

Code: Select all

void AALine(int x0, int y0, int x1, int y1)
{
    int addr = (y0*640+x0)*4;
    int dx = x1-x0;
    int dy = y1-y0;
    /* By switching to (u,v), we combine all eight octants */
    if (abs(dx) > abs(dy))
    {
	/* Note: If this were actual C, these integers would be lost
	 * at the closing brace.  That's not what I mean to do.  Do what
	 * I mean. */
	int du = abs(dx);
	int dv = abs(dy);
	int u = x1;
	int v = y1;
	int uincr = 4;
	int vincr = 640*4;
	if (dx < 0) uincr = -uincr;
	if (dy < 0) vincr = -vincr;
    }
    else
    {
	int du = abs(dy);
	int dv = abs(dx);
	int u = y1;
	int v = x1;
	int uincr = 640*4;
	int vincr = 4;
	if (dy < 0) uincr = -uincr;
	if (dx < 0) vincr = -vincr;
    }
    int uend = u + 2 * du;
    int d = (2 * dv) - du;	    /* Initial value as in Bresenham's */
    int incrS = 2 * dv;	/* Δd for straight increments */
    int incrD = 2 * (dv - du);	/* Δd for diagonal increments */
    int twovdu = 0;	/* Numerator of distance; starts at 0 */
    double invD = 1.0 / (2.0*sqrt(du*du + dv*dv));   /* Precomputed inverse denominator */
    double invD2du = 2.0 * (du*invD);   /* Precomputed constant */
    do
    {
	/* Note: this pseudocode doesn't ensure that the address is
	 * valid, or that it even represents a pixel on the same side of
	 * the screen as the adjacent pixel */
	DrawPixelD(addr, twovdu*invD);
	DrawPixelD(addr + vincr, invD2du - twovdu*invD);
	DrawPixelD(addr - vincr, invD2du + twovdu*invD);

	if (d < 0)
	{
	    /* choose straight (u direction) */
	    twovdu = d + du;
	    d = d + incrS;
	}
	else
	{
	    /* choose diagonal (u+v direction) */
	    twovdu = d - du;
	    d = d + incrD;
	    v = v+1;
	    addr = addr + vincr;
	}
	u = u+1;
	addr = addr+uincr;
    } while (u < uend);
}
That's very interesting - I also use lines in my diagrams, so I'll try write wx function for this algorithm

lester
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 211
Joined: Sat Sep 02, 2006 7:24 pm
Location: Ukraine

Post by lester » Fri Mar 28, 2008 7:56 pm

I have found better code - WU line, please wait...

lester
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 211
Joined: Sat Sep 02, 2006 7:24 pm
Location: Ukraine

Post by lester » Fri Mar 28, 2008 8:20 pm

It work :)

That's my implementation of Wu's algorithm for wxWidgets ( I have found code and adapt it to wx ), it's ugly but work fine:

Code: Select all

/**********************************************************************************************/
void DrawWuLine( wxDC *pDC, short X0, short Y0, short X1, short Y1 )
{
	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( *wxBLACK );
	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 currrent 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;
			pDC->SetPen( wxColour( Weighting, Weighting, Weighting ) );
			pDC->DrawPoint( X0, Y0 );
			pDC->SetPen( wxColour( Weighting ^ WeightingComplementMask, Weighting ^ WeightingComplementMask, Weighting ^ WeightingComplementMask ) );
			pDC->DrawPoint( X0 + XDir, Y0 );
		}
		/* Draw the final pixel, which is 
		always exactly intersected by the line
		and so needs no weighting */
		pDC->SetPen( *wxBLACK );
		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;
		pDC->SetPen( wxColour( Weighting, Weighting, Weighting ) );
		pDC->DrawPoint( X0, Y0 );
		pDC->SetPen( wxColour( Weighting ^ WeightingComplementMask, Weighting ^ WeightingComplementMask, Weighting ^ WeightingComplementMask ) );
		pDC->DrawPoint( X0, Y0 + 1 );
	}
	/* Draw the final pixel, which is always exactly intersected by the line
	and so needs no weighting */
	pDC->SetPen( *wxBLACK );
	pDC->DrawPoint( X1, Y1 );
}

lester
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 211
Joined: Sat Sep 02, 2006 7:24 pm
Location: Ukraine

Post by lester » Fri Mar 28, 2008 8:43 pm

v2 for draw coloured line ( use Pen and Brush from DC )

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 );
}

Jorg
Moderator
Moderator
Posts: 3971
Joined: Fri Aug 27, 2004 9:38 pm
Location: Delft, Netherlands
Contact:

Post by Jorg » Sat Mar 29, 2008 9:25 am

Lester, this is very interesting stuff! Would you consider reposting that in the Code Dump under a new topic? It might help people looking for a line drawing routine.

Also, you might want to consider seeing if this can be integrated with wxWidgets itself. It would be a nice contribution to the original drawing algoritm

- Jorgen
Forensic Software Engineer
Netherlands Forensic Insitute
http://english.forensischinstituut.nl/
-------------------------------------
Jorg's WasteBucket
http://www.xs4all.nl/~jorgb/wb

lester
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 211
Joined: Sat Sep 02, 2006 7:24 pm
Location: Ukraine

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

Jorg wrote:Lester, this is very interesting stuff! Would you consider reposting that in the Code Dump under a new topic? It might help people looking for a line drawing routine.

Also, you might want to consider seeing if this can be integrated with wxWidgets itself. It would be a nice contribution to the original drawing algoritm

- Jorgen
Sure, I'll be happy if it will help to somebody

User avatar
doublemax
Moderator
Moderator
Posts: 15159
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post by doublemax » Sat Mar 29, 2008 10:51 am

like tan already mentioned, wxWidgets supports antialiased drawing operations on all major platforms using wxGCGC.

Usually you only have to change/add 2 lines of code in your drawing routine.

Check the "drawing" sample.

http://forums.wxwidgets.org/viewtopic.php?p=66885#66885
Use the source, Luke!

Post Reply