2010-01-14 57 views
4

我有一个动态列表点,新点可以随时添加。我想画线以使用不同的颜色来连接它们。颜色是基于这些点的指数。这里是代码:使用GDI +使用不同颜色画线的快速方法?

private List<Point> _points; 
    private static Pen pen1 = new Pen(Color.Red, 10); 
    private static Pen pen2 = new Pen(Color.Yellow, 10); 
    private static Pen pen3 = new Pen(Color.Blue, 10); 
    private static Pen pen4 = new Pen(Color.Green, 10); 

    private void Init() 
    { 
     // use fixed 80 for simpicity 
     _points = new List<Point>(80); 

     for (int i = 0; i < 80; i++) 
     { 
      _points.Add(new Point(30 + i * 10, 30)); 
     } 
    } 

    private void DrawLinesNormal(PaintEventArgs e) 
    { 
     for (int i = 0; i < _points.Count-1; i++) 
     { 
      if (i < 20) 
       e.Graphics.DrawLine(pen1, _points[i], _points[i + 1]); 
      else if (i < 40) 
       e.Graphics.DrawLine(pen2, _points[i], _points[i + 1]); 
      else if (i < 60) 
       e.Graphics.DrawLine(pen3, _points[i], _points[i + 1]); 
      else 
       e.Graphics.DrawLine(pen4, _points[i], _points[i + 1]); 
     } 
    } 

我发现这种方法是不够快,当我有新的点高速进来。有什么办法可以让它更快吗?我做了一些研究,有人说使用GraphicsPath可能会更快,但是如何?

[更新]我收集了一些可能的优化:

  1. 使用GrahpicsPath,Original Question
  2. 更改图形质量(如SmoothingMode/PixelOffsetMode ......),也叫setClip的指定只在必要地区渲染。

回答

1

这与使用System.Drawing时一样快。使用Graphics.DrawLines()可能会看到一些收获,但您需要以不同方式格式化数据,以便利用同一支笔一次绘制一堆线。我严重怀疑GraphicsPath会更快。

提高速度的一个可靠方法是降低输出质量。设置Graphics.InterpolationModeInterpolationMode.LowGraphics.CompositingQualityCompositingQuality.HighSpeedGraphics.SmoothingModeSmoothingMode.HighSpeedGraphics.PixelOffsetModePixelOffsetMode.HighSpeedGraphics.CompositingModeCompositingMode.SourceCopy

我记得一次速度测试,有人将图形与P/Invoke比较成GDI例程,并且对于更快的P/Invoke速度感到非常惊讶。你可能会检查出来。我会看看我是否可以找到这种比较... 显然这是为Compact Framework,所以它可能不适用于PC。

另一种方式是使用Direct2D,如果你有合适的硬件,它可以比GDI更快。

5

如果不损失质量或改变为更快的渲染器(GDI,OpenGL,DirectX),您将无法从该代码中挤出更多的速度。但是GDI通常会快很多(可能是2倍),并且DirectX/OpenGL可以更快(可能是10倍),具体取决于您绘制的内容。

使用Path的想法是将许多(在您的示例中为20行)批量转换为单个方法调用,而不是调用DrawLine 20次。如果您可以将传入数据安排到绘图例程的正确列表格式中,这将只对您有益。否则,您将不得不将这些点复制到正确的数据结构中,并且这会浪费您通过批处理路径获得的大量时间。在DrawPath的情况下,您可能必须从点数组中创建一个GraphicsPath,这可能不会节省时间。但是如果你必须不止一次地绘制相同的路径,你可以缓存它,然后你可以看到一个净效益。

如果将新点添加到列表中,但旧点不会被删除(即,您总是只是在显示屏上添加新行),那么您将能够使用离屏位图来存储到目前为止呈现的行。这样,每次添加一个点时,都会绘制一个一行,而不是每次绘制所有80行。

这一切都取决于你想要做什么。

+0

缓存旧点是一个好主意,但是,我可以简单地更改已绘制线的颜色吗?如果不是的话,我仍然必须每次绘制所有80行。 – 2010-01-14 08:18:29

+0

如果您的线条颜色少于256线,那么您可以在8bpp位图上使用调色板循环(因此您可以用独特的颜色绘制每条线,然后只更新调色板以重新显示颜色变化的线)。 – 2010-01-14 13:04:42

+0

或者,您可能只能重新渲染每帧中改变颜色的线条。请注意,这将导致他们透支所有其他线路,因此您可能会在它们重叠的地方出现不需要的“深度”故障(错误的线路出现在“前面”) - 但是您可能能够避开它。如果您使用抗锯齿渲染线条,它也可能会生成奇怪的颜色,因为每条线将与其后面的颜色(包括同一线条的旧颜色)进行混合。但你可以尝试一下,看看你对结果是否满意...... – 2010-01-14 13:05:28

0

你可能想看看画笔对象,这是真的,你就不会接近实时的性能得到了GDI +程序,但你可以很容易,只要保持一个体面的FPS作为对象的几何形状和数量保持在合理范围内。至于画线,我不明白为什么不。

但是,如果你达到了你认为最佳的点,那就是绘制线..你应该考虑一个不同的图形堆栈,如果你喜欢.NET,但是在OpenGL等非托管API方面有问题和DirectX,使用WPF或Silverlight,它非常强大。

无论如何,您可以尝试设置System.Drawing.Drawing2D.GraphicsPath,然后使用System.Drawing.Drawing2D.PathGradientBrush以这种方式应用颜色。这是一个单一的缓冲平局,如果你不能获得足够的表现。您必须完全采用GDI以外的其他方法+

+0

我不认为你可以使用Brush来“填充”一行 – 2010-01-14 20:05:55

0

根本不是GDI(+),但解决此问题的完全不同的方法可能是使用一块内存,将您的线条绘制到那里,将其转换到一个Bitmap对象来即时绘制需要显示线条的位置。

当然,这取决于在快速的方式极端中选择的内存中表示给定颜色的

  • 画线和
  • 将其转换成该Bitmap显现。

不是在.NET Framework中,我想,但也许在第三方库? Silverlight中没有类似这样的东西的bitmap writer? (还没有进入Silverlight我自己,那么多...)

至少它可能是一个开箱即用的方法来处理这个问题。希望能帮助到你。

+0

在.NET 2.0中没有任何东西可以与GDI +很好地协作(你可以做到,但不会特别快)。但是,WPF或Silverlight,取决于您想要使用桌面还是Web方法,都可以。一个可写的位图http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.writeablebitmap.aspx – 2010-01-14 07:48:14

+0

是不是我说的,约翰? ;-) – peSHIr 2010-01-14 08:08:15

+0

我可以使用双缓冲区来绘制一个离屏图像,然后绘制到图形? – 2010-01-14 08:24:53

2

并不能真正帮助提高性能,但我把笔还到一个列表,并以这种方式编写所有这行:

int ratio = _points.Count/_pens.Count; 

for (int i = 0; i < _points.Count - 1; i++) 
{ 
    e.Graphics.DrawLine(_pens[i/ratio], _points[i], _points[i + 1]); 
} 
0

我认为你必须处理笔对象和电子商务。绘图后的图形对象。 还有一件事情,如果你在onPaint()里面写你的drawLine代码会更好。

just override onPaint() method it support better drawing and fast too. 
+0

是的,我必须处理这些笔,但此代码仅用于演示目的,所以我没有写。 - 我不认为我需要处理e.Graphics对象,我没有创建它,为什么我需要处理它? - 你能解释为什么重写OnPaint会更快吗?你的意思是调用Paint事件的开销? – 2010-01-15 19:38:11

1

太晚了,但可能有人仍然需要解决方案。

我已经创建,有着相近(但不是全/等于)GDI +语法,这在OpenTK经营的小型图书馆GLGDI +:http://code.google.com/p/glgdiplus/

我不知道有关的稳定性,它通过DrawString一些问题(有问题来自OpenTK的TextPrint)。但是如果你的实用程序需要性能提升(比如我的情况下的关卡编辑器),它可以是解决方案。