0

I am working on a project using .Net Compact Framework 3.5 using C# 3.0.

I have a user control which receives data every 15 miliseconds and I have to draw shapes

like lines, rectangle, filled rectangles on user control.

I want to know what is the fastest way to draw these shapes, I am also open to use P/Invoke methods if there are some to increase performance and speed.

The code I am using is as follows:

     private void DrawThreeFunctions(Graphics g)
                {
                    // drawing back functions
                    if (DisplayFunction1.DrawOrder == DrawOrder.Back && GraphDataArray.Length > 0)
                    {
                        DrawFunction(g, DisplayFunction1, GraphDataArray[0]);
                    }
                    if (DisplayFunction2.DrawOrder == DrawOrder.Back && GraphDataArray.Length > 1)
                    {
                        DrawFunction(g, DisplayFunction2, GraphDataArray[1]);
                    }
                    if (DisplayFunction3.DrawOrder == DrawOrder.Back && GraphDataArray.Length > 2)
                    {
                        DrawFunction(g, DisplayFunction3, GraphDataArray[2]);
                    }
                    // drawing middle functions
                    if (DisplayFunction1.DrawOrder == DrawOrder.Middle && GraphDataArray.Length > 0)
                    {
                        DrawFunction(g, DisplayFunction1, GraphDataArray[0]);
                    }
                    if (DisplayFunction2.DrawOrder == DrawOrder.Middle && GraphDataArray.Length > 1)
                    {
                        DrawFunction(g, DisplayFunction2, GraphDataArray[1]);
                    }
                    if (DisplayFunction3.DrawOrder == DrawOrder.Middle && GraphDataArray.Length > 2)
                    {
                        DrawFunction(g, DisplayFunction3, GraphDataArray[2]);
                    }
                    // drawing front functions
                    if (DisplayFunction1.DrawOrder == DrawOrder.Front && GraphDataArray.Length > 0)
                    {
                        DrawFunction(g, DisplayFunction1, GraphDataArray[0]);
                    }
                    if (DisplayFunction2.DrawOrder == DrawOrder.Front && GraphDataArray.Length > 1)
                    {
                        DrawFunction(g, DisplayFunction2, GraphDataArray[1]);
                    }
                    if (DisplayFunction3.DrawOrder == DrawOrder.Front && GraphDataArray.Length > 2)
                    {
                        DrawFunction(g, DisplayFunction3, GraphDataArray[2]);
                    }
                } 


    private void DrawFunction(Graphics g, DisplayFunction function, int[] data)
            {
                Color color = Utils.GetColor(function.Color);
                switch (function.Shape)
                {
                    case FunctionShape.StepLine:
                        DrawStepLines(g, data, color);
                        break;
                    case FunctionShape.Rectangle:
                        DrawFilledRectangles(g, data, color);
                        break;
                    case FunctionShape.FramedRectangle:
                        DrawFramedRectangles(g, data, color);
                        break;
                    case FunctionShape.Line:
                        DrawLines(g, data, color);
                        break;
                    default:
                        break;
                }
            }

            #region Drawing methods
            // drawing lines
            private void DrawLines(Graphics g, int[] lineData, Color lineColor)
            {
                BarPositions = new List<int>();
                List<Point> linePoints = new List<Point>();
                int lineYPos = -1;
                int lineXPos = FirstBarDrawPosition;
                Point point = Point.Empty;

                using (Pen linePen = new Pen(lineColor, 2.0f))
                {
                    for (int i = FirstVisibleItemIndex, k = 0; i < _indexLimit; i++, k++)
                    {
                        if (base.GetBarEndPosition(k) > Width)
                            break;

                        lineXPos = GetTickPosition(k);
                        BarPositions.Add(lineXPos);

                        if (i < lineData.Length)
                            lineYPos = lineData[i];
                        else
                            continue;

                        point.X = lineXPos;
                        point.Y = lineYPos;

                        linePoints.Add(point);
                    }

                    if (linePoints.Any())
                    {
                        g.DrawLines(linePen, linePoints.ToArray());
                    }
                }
            }
            // drawing framed rectangles
            private void DrawFramedRectangles(Graphics g, int[] functionValues, Color functionColor)
            {
                BarPositions = new List<int>();

                int barXPos = FirstBarDrawPosition;
                Rectangle barRect = Rectangle.Empty;
                barRect.Width = WidthOfBar - 1;
                int barYPos = -1;

                using (Pen barPen = new Pen(functionColor))
                {
                    for (int i = FirstVisibleItemIndex, k = 0; i < _indexLimit; i++, k++)
                    {
                        if (base.GetBarEndPosition(k) > Width)
                            return;

                        BarPositions.Add(GetTickPosition(k));

                        if (i < functionValues.Length)
                            barYPos = functionValues[i];
                        else
                            continue;

                        //barRect = new Rectangle();
                        barRect.X = barXPos;
                        barRect.Y = barYPos;
                        //barRect.Width = WidthOfBar - 1;
                        barRect.Height = Height - barYPos;
                        g.DrawRectangle(barPen, barRect);
                        barXPos += (WidthOfBar + DistanceBetweenBars);
                    }
                }
            }
            // drawing filled rectangles
            private void DrawFilledRectangles(Graphics g, int[] functionValues, Color functionColor)
            {
                BarPositions = new List<int>();

                int barXPos = FirstBarDrawPosition;
                Rectangle barRect = Rectangle.Empty;
                barRect.Width = WidthOfBar;
                int barYPos = -1;

                using (SolidBrush barBrush = new SolidBrush(functionColor))
                {
                    for (int i = FirstVisibleItemIndex, k = 0; i < _indexLimit; i++, k++)
                    {
                        if (base.GetBarEndPosition(k) > Width)
                            return;

                        BarPositions.Add(GetTickPosition(k));

                        if (i < functionValues.Length)
                            barYPos = functionValues[i];
                        else
                            continue;

                        //barRect = new Rectangle();
                        barRect.X = barXPos;
                        barRect.Y = barYPos;
                        //barRect.Width = WidthOfBar;
                        barRect.Height = Height - barYPos;
                        g.FillRectangle(barBrush, barRect);
                        barXPos += (WidthOfBar + DistanceBetweenBars);
                    }
                }
            }

private void DrawStepLines(Graphics g, int[] lineData, Color lineColor)
        {
            BarPositions = new List<int>();
            int lineYPos = -1;
            int barXPos = FirstBarDrawPosition;

            using (Pen linePen = new Pen(lineColor, 2.0f))
            {
                for (int i = FirstVisibleItemIndex, k = 0; i < _indexLimit; i++, k++)
                {
                    if (base.GetBarEndPosition(k) > Width)
                        return;

                    BarPositions.Add(GetTickPosition(k));

                    if (i < lineData.Length)
                        lineYPos = lineData[i];
                    else
                        continue;

                    // draw third function line
                    //lineHeight = lineData[i];

                    g.DrawLine(linePen, barXPos, lineYPos, barXPos + WidthOfBar - 1, lineYPos);

                    barXPos += (WidthOfBar + DistanceBetweenBars);
                }
            }
        }

I am using drawing order and shape like step line , line , framed rectangle ( just rectangle ) and rectangle is filled rectangle.

Because of performance critical application I want to know the fastest way of drawing these shapes.

Thanks in advance for any suggestion.

svick
  • 236,525
  • 50
  • 385
  • 514
Embedd_0913
  • 16,125
  • 37
  • 97
  • 135
  • 1
    Have you checked that the standard functions are too slow? I think that they should be able to provide a decent animation of at least some 10fps. Which is quite enough for any human needs, because the human will need at least a second to react anyway. Any faster will make the animation smoother, perhaps, but it won't add any real value - just eye candy. – Vilx- Jul 16 '12 at 10:34
  • Probably Flash is your best bet for an underpowered/mobile device. – leppie Jul 16 '12 at 10:35
  • @Vilx-: 15ms goes into 1 second about 67 times. – leppie Jul 16 '12 at 10:35
  • @leppie - Yes, and I'm saying that it's pointless to try and redraw that fast. – Vilx- Jul 16 '12 at 10:37
  • you should try to find some optimization strategies to avoid redrawing all every time. – Felice Pollano Jul 16 '12 at 10:45
  • @Vilx- I was also looking for some code review, so that I can get some advices on any improvement on my code. – Embedd_0913 Jul 16 '12 at 10:47
  • Looks fine to me. A few corners could be cut here and there, but nothing that would be noticeable in performance. Well... maybe just one thing - you're creating new pens and brushes every time you draw. Perhaps you could make them once on startup (or on first use), and then reuse them. That could shave off a few milliseconds. – Vilx- Jul 16 '12 at 10:52
  • @Vilx- Yes, that's a good advice , thanks a lot. – Embedd_0913 Jul 16 '12 at 11:11
  • If you absolutely require that level of performance you're probably using the wrong development platform. You ought to investigate OpenGL or DirectX. – pdriegen Jul 16 '12 at 14:42
  • Praveen, like Vilx has already point out, there is no need to draw that fast. Could you store your shapes in an array and draw them every 200ms or so? If not, your device is going to be so busy trying to draw that it will not respond to user input very well. –  Jul 16 '12 at 18:29

1 Answers1

3

Are you familiar with double-buffering? Keep an offscreen image buffer to do your writes to as the changes come in. Then override the OnPaint to blit the whole image in one statement. Also, override the OnPaintBackground with a no-op to get rid of the default behavior of clearing the control to its backcolor on each paint.


Old as the hills, but here is an article on some best-practices on using GDI in the Compact Framework.

tcarvin
  • 10,715
  • 3
  • 31
  • 52