Update a rectangular region in a drawing
I paint a drawing on a drawing area.
In order to optimize the performance of that drawing I decided to redraw only inside the really necessary region(clipping region). See the picture.
The problem is that I don't arrive to build a method(GetBitmapFromRectangle
) that returns me the result of intersection of my paths with the clipping rectangle.
This method could be very useful when the user moves(with the mouse) paths. In that case there is need to repaint only the former and current moved path area - and not the whole picture, that in case of complex pictures can visibly slow down the application performance.
My tests shows that the calculation time is much less important that the drawing one, so I'd better perform more calculations that more drawing.
I want to draw not the entire paths that intersects the rectangle, but really only the paths inside the clipping regi开发者_Go百科on.
alt text http://lh5.ggpht.com/_1TPOP7DzY1E/TD7T0jNU-wI/AAAAAAAADUM/YxaQu4hANpU/s800/Capture1.gif
In other words, I need a method that will make the BLUE lines inside the red area PINK.
Here is the code:
using System.Drawing;
using System.Windows.Forms;
namespace WindowsApplication38
{
public partial class Form1 : Form
{
Point center;
int radius, penWidth;
public Form1()
{
InitializeComponent();
center = new Point(50, 50);
radius = 100;
penWidth = 5;
this.ResizeRedraw = true;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.Clear(this.BackColor);
e.Graphics.DrawImage(
GetBitmapFromRectangle(e.ClipRectangle),
e.ClipRectangle.Location);
//
// INITIAL DRAWING METHOD
//
Pen p = new Pen(Color.Blue, penWidth);
// draw O
e.Graphics.DrawEllipse(p, center.X - radius, center.Y - radius, radius * 2, radius * 2);
// draw X
Point[] line1 = new Point[] { new Point(0, 0), new Point(this.Width, this.Height) };
Point[] line2 = new Point[] { new Point(this.Width, 0), new Point(0, this.Height) };
e.Graphics.DrawLines(p, line1);
e.Graphics.DrawLines(p, line2);
p.Dispose();
}
private Bitmap GetBitmapFromRectangle(Rectangle rect)
{
Bitmap bmp = new Bitmap(rect.Width, rect.Height);
Graphics g = Graphics.FromImage(bmp);
if (rect != this.DisplayRectangle)
g.Clear(Color.Red);
else
g.Clear(this.BackColor);
// Draw ONLY! the intersetion between drawing and rectangle...
// How to ???
return bmp;
}
}
}
Nota bene
The example is a sample for demo purpose only. In the real project I have very complex graphic, and the drawing time is much more expensive that the calculation one. This why I want to not redraw all the painting, but only the lines inside the clipping region!
Before doing this, I suggest testing the performance improvement by manually culling the set and comparing frame rates with and without culling. You may find that GDI+ already optimises anything you draw outside the viewport.
If you find that it is helpful to cull, the simplest approach is to find the bounding box of each object and test for rectangle intersection:
bool intersect = left1 < right2 && left2 < right1 && top1 < bottom2 && top2 < bottom1.
Depending on the type of drawings, this may have a high rate of false hits, such as a large hollow circle that goes around the viewport, but it usually does well enough for most purposes.
I would copy existing drawing code to GetBitmapFromRectangle method without any changes. Required optimization is already done by reducing the updated area. Existing code, copied to GetBitmapFromRectangle, just draws some lines outside of the bitmap bounds, this is OK - Graphics class can handle this. Testing every drawing primitive for intersiction with clipping rectangle only reduces the program performance.
You should check out the GraphicsPath class in System.Drawing.Drawing2D.
精彩评论