Overview
Examples
Screenshots
Comparisons
Applications
Download
Documentation
Tutorials
Bazaar
Status & Roadmap
FAQ
Authors & License
Forums
Funding Ultimate++
Search on this site
Search in forums












SourceForge.net Logo
Home » U++ Library support » U++ Widgets - General questions or Mixed problems » How to implent a rubber band Class in u++
Re: How to implent a rubber band Class in u++ [message #17297 is a reply to message #17296] Wed, 06 August 2008 08:34 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
Well, one method that comes to mind is to use DrawPolyline.

IMO, significant bottleneck here is that each line drawn means one system call to Win32 API. Using Polyline this would be reduced to just single call.

Mirek
Re: How to implent a rubber band Class in u++ [message #17298 is a reply to message #17297] Wed, 06 August 2008 11:04 Go to previous messageGo to next message
mrjt is currently offline  mrjt
Messages: 705
Registered: March 2007
Location: London
Contributor
I can think of two possible optimisations (besides PolyLine, which is definitely the first one to use)

1- Avoid adding adjacent collinear points. In practice this is a very minor optimisation except for special cases, but it appeals to my sense of correctness.
class RubberBand : public LocalLoop
{
public:
	virtual void MouseMove(Point p, dword keyflags) 	{ AddPoint(p); GetMaster().Refresh(); }
	virtual void LeftUp(Point p, dword keyflags)    	{ EndLoop(); }
	virtual void RightUp(Point p, dword keyflags)   	{ EndLoop(); }

	const Vector<Point> &	GetPoints()					{ return points; }
	void 					Clear()						{ points.Clear(); }
private:
	Vector<Point> points;
	
	void AddPoint(const Point &newp);
};

void RubberBand::AddPoint(const Point &newp)
{
	if (points.GetCount() < 2)
		return points.Add(newp);
	// Get line vectors
	const Point &p = points[points.GetCount()-2];
	Point p1 = points.Top() - p;
	Point p2 = newp - p;
	// If gradient is different, add the new point
	if (p1.x*p2.y - p2.x*p1.y)
		points.Add(newp);
	// Otherwise update last points
	else
		points.Top() = newp;
}


2- Use a back buffer. Providing you have a static background (one that will not change while the rubber band is being drawn), you can use a back buffer to cache the background + the current rubber band and only draw the last line.

This was a major improvement for me, eliminating flickering entirely.
	RubberBand 	band;
	BackDraw 	back;
	Size	 	backsz;
	
	void LeftDown(Point p, dword keyflags)
	{
		band.Clear();
		band.SetMaster(*this);
		Size sz = GetSize();
		if (sz != backsz) {
		    back.Create(sz);
		 	backsz = sz;   
		}
		Paint(back);
		band.Run();
		Refresh();
	}
	
	void Paint(Draw& w)
	{
		const Vector<Point> &p = band.GetPoints();
		if (!band.InLoop()) {
			// Normal painting
			w.DrawRect(GetSize(), White);	
			if (p.GetCount() >= 2) {
				w.DrawPolyline(p);	
				w.DrawLine(p[p.GetCount()-1], p[0]);
			}
						
		}
		else {
                        // RubberBand painting
			if (p.GetCount() >= 2)
				back.DrawLine(p[p.GetCount()-2], p.Top());
			back.Put(w, 0, 0);
			w.DrawText(4, 4, AsString(p.GetCount()));
		}
	}
Re: How to implent a rubber band Class in u++ [message #17373 is a reply to message #17298] Sat, 09 August 2008 18:43 Go to previous message
tojocky is currently offline  tojocky
Messages: 607
Registered: April 2008
Location: UK
Contributor

mrjt wrote on Wed, 06 August 2008 12:04

I can think of two possible optimisations (besides PolyLine, which is definitely the first one to use)

1- Avoid adding adjacent collinear points. In practice this is a very minor optimisation except for special cases, but it appeals to my sense of correctness.
.....

2- Use a back buffer. Providing you have a static background (one that will not change while the rubber band is being drawn), you can use a back buffer to cache the background + the current rubber band and only draw the last line.

This was a major improvement for me, eliminating flickering entirely.
.........



Very Hard optimization. Thank you!

Bu in this example is an error!

void RubberBand::AddPoint(const Point &newp)
{
	if (points.GetCount() < 2)
		return points.Add(newp);
	// Get line vectors
	const Point &p = points[points.GetCount()-2];
	Point p1 = points.Top() - p;
	Point p2 = newp - p;
	// If gradient is different, add the new point
	if (p1.x*p2.y - p2.x*p1.y)
		points.Add(newp);
	// Otherwise update last points
	else
==>HERE		points.Top() = newp;
}


The bug is when the newpoint is in the line draws from the last 2 points AND the newpoint is in between from the last 2 points!
Corrected code is:

void RubberBandClass::AddPoint(const Point &newp) {
	if (points.GetCount() < 2)
		return points.Add(newp);
	// Get line vectors
	const Point &p_second_last = points[points.GetCount()-2];
	const Point &p_last = points.Top();
	
	Point p1 = p_last - p_second_last;
	Point p2 = newp - p_second_last;
	// If gradient is different, add the new point
	if (p1.x*p2.y - p2.x*p1.y)
		points.Add(newp);
	// Otherwise update last points if the newpoint is continue of the last point from the second last point
	else{
		int pos_from_last = 0;
		
		int pos_1=newp.x, pos_2=p_last.x, pos_3=p_second_last.x;
		
		if (!((p_last.x == p_second_last.x)&&(newp.x == p_last.x)))
			int pos_1=newp.y, pos_2=p_last.y, pos_3=p_second_last.y;
		
		if (pos_2 > pos_3 ){
			if (pos_1 > pos_2) {
				pos_from_last = 1;
			}
			else if ( pos_1 < pos_3) {
				pos_from_last = 2;
			}
		}
		else {
			if (pos_1 < pos_3) {
				pos_from_last = 1;
			}
			else if (pos_1 >pos_2){
				pos_from_last = 2;
			}
		}
		if (pos_from_last) points[points.GetCount()-pos_from_last] = newp;
	}
}


In base of this example I can write paint method of controls more optimized!

Thanks a lot about back buffer (BackDraw)!

Is other ideas?

[Updated on: Sat, 09 August 2008 18:51]

Report message to a moderator

Previous Topic: FileList problems with extensions and pop-ups
Next Topic: How to turn off special chars in RichEdit?
Goto Forum:
  


Current Time: Sun Apr 28 21:03:58 CEST 2024

Total time taken to generate the page: 0.03585 seconds