Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implement faster graphics operation on WPF Canvas

I am trying to build a simple graphics application in WPF C#. The purpose is to draw 10000*10000 rectangles of size 4 pixels each.

I have modified the OnRender method of the canvas to draw the rectangles. Drawings are performed for smaller number of rectangles (say 50*50 or 100*100 rectangles of 4 pixel each) but it is slowing down as I am increasing the no. of rectangles.

Following is my code:

  protected override void OnRender(DrawingContext dc)
    {
        base.OnRender(dc);

        FillCells(dc);

        if (_ShowGrids)
        {
            DrawGrid(dc); // draw grid lines
        }
    }
 void FillCells(DrawingContext dc)
    {

        int cellSize=4;

        for (int i = 0; i < MaxRow; i++)
        {
            for (int j = 0; j < MaxColumn; j++)
            {
                dc.DrawRectangle(GetRectBrush(i,j), GetRectPen(i,j), new Rect(j * cellSize , i * cellSize , cellSize - 1, cellSize - 1));

            }
        }
    }

The above code takes more than a minute to draw 1000*1000 rectangles.

Is there any method to make this process faster? Is there any other thing I can use in place of this?

Thanks.

like image 272
Vinod Maurya Avatar asked Oct 25 '10 05:10

Vinod Maurya


3 Answers

The purpose is to draw 10000*10000 rectangles of size 4 pixels each.

Do NOT draw them. That simple. This would be 40k to 40k pixels.

Most will not be visible. So they must not bee drawn. Basically only draw those that are visible in the canvas. When resizing or scrolling you repaint anyway, then do the same - only draw those that are visible.

Virtualization is the key to performance here. Take things out of the drawing loop as early as possible. Stuff not visible per definition does not need to be drawn at all.

Next alternative would be not to use a canvas. Try a bitmap. Prepare it on a separate thread, then draw this one at once.

like image 94
TomTom Avatar answered Oct 20 '22 09:10

TomTom


You should try StreamGeometry then. http://msdn.microsoft.com/en-us/library/system.windows.media.streamgeometry.aspx

For complex geometries that don’t need to be modified after they are created, you should consider using StreamGeometry rather than PathGeometry as a performance optimization. StreamGeometry works like PathGeometry, except that it can only be filled via procedural code. Its odd name refers to an implementation detail: To use less memory (and less of the CPU), its PathFigures and PathSegments are stored as a compact byte stream rather than a graph of .NET objects.

Quoted from Adam Nathan's book WPF Unleashed.

like image 3
Prince Ashitaka Avatar answered Oct 20 '22 07:10

Prince Ashitaka


You don't need to recreate the brush for each iteration of the loop, since they use the same color over and over:

SolidColorBrush blueBrush = new SolidColorBrush(Colors.Blue)
SolidColorPen bluePen = new SolidColorPen(blueBrush)

for (int i = 0; i < MaxRow; i++)
{
    for (int j = 0; j < MaxColumn; j++)
    {
        dc.DrawRectangle(blueBrush, bluePen, 1), new Rect(j * cellSize , i * cellSize , cellSize - 1, cellSize - 1));
    }
}

This may speed up the loop a bit.

like image 2
Fredrik Mörk Avatar answered Oct 20 '22 07:10

Fredrik Mörk