Fastest way to draw shapes (Line, FilledRectangle, Rectangle etc)
-
21-06-2021 - |
Domanda
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.
Soluzione
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.