2016-11-15 42 views
2

使用自写图形控件时,我注意到在显示噪点数据时图的绘制要比显示干净数据时慢得多。
我进一步挖掘并将问题缩小到其最小差异:绘制具有相同Y值的具有不同Y值的绘制线的相同数量的线。绘制之字形线比绘制直线要慢

因此,举例来说,我将以下测试放在一起。我生成点列表,其中一个具有随机Y值,一个具有相同的Y值,另一个具有锯齿形Y型。

private List<PointF> GenerateRandom(int n, int width, int height) 
{ 
    //Generate random pattern 
    Random rnd = new Random(); 
    float stepwidth = Convert.ToSingle(width/n); 
    float mid = Convert.ToSingle(height/2); 
    float lastx = 0; 
    float lasty = mid; 
    List<PointF> res = new List<PointF>(); 
    res.Add(new PointF(lastx, lasty)); 
    for (int i = 1; i <= n; i++) 
    { 
     var x = stepwidth * i; 
     var y = Convert.ToSingle(height * rnd.NextDouble()); 
     res.Add(new PointF(x, y)); 
    } 
    return res; 
} 
private List<PointF> GenerateUnity(int n, int width, int height) 
{ 
    //Generate points along a simple line 
    float stepwidth = Convert.ToSingle(width/n); 
    float mid = Convert.ToSingle(height/2); 
    float lastx = 0; 
    float lasty = mid; 
    List<PointF> res = new List<PointF>(); 
    res.Add(new PointF(lastx, lasty)); 
    for (int i = 1; i <= n; i++) 
    { 
     var x = stepwidth * i; 
     var y = mid; 
     res.Add(new PointF(x, y)); 
    } 
    return res; 
} 
private List<PointF> GenerateZigZag(int n, int width, int height) 
{ 
    //Generate an Up/Down List 
    float stepwidth = Convert.ToSingle(width/n); 
    float mid = Convert.ToSingle(height/2); 
    float lastx = 0; 
    float lasty = mid; 
    List<PointF> res = new List<PointF>(); 
    res.Add(new PointF(lastx, lasty)); 
    var state = false; 
    for (int i = 1; i <= n; i++) 
    { 
     var x = stepwidth * i; 
     var y = mid - (state ? 50 : -50); 
     res.Add(new PointF(x, y)); 
     state = !state; 
    } 
    return res; 
} 

我现在画点的每个列表几次,比较需要多长时间:

private void DoTheTest() 
{ 
    Bitmap bmp = new Bitmap(970, 512); 
    var random = GenerateRandom(2500, bmp.Width, bmp.Height).ToArray(); 
    var unity = GenerateUnity(2500, bmp.Width, bmp.Height).ToArray(); 
    var ZigZag = GenerateZigZag(2500, bmp.Width, bmp.Height).ToArray(); 

    using (Graphics g = Graphics.FromImage(bmp)) 
    { 
     var tUnity = BenchmarkDraw(g, 200, unity); 
     var tRandom = BenchmarkDraw(g, 200, random); 
     var tZigZag = BenchmarkDraw(g, 200, ZigZag); 
     MessageBox.Show(tUnity.ToString() + "\r\n" + tRandom.ToString() + "\r\n" + tZigZag.ToString()); 
    } 
} 
private double BenchmarkDraw(Graphics g, int n, PointF[] Points) 
{ 
    var Times = new List<double>(); 
    for (int i = 1; i <= n; i++) 
    { 
     g.Clear(Color.White); 
     System.DateTime d3 = DateTime.Now; 
     DrawLines(g, Points); 
     System.DateTime d4 = DateTime.Now; 
     Times.Add((d4 - d3).TotalMilliseconds); 
    } 
    return Times.Average(); 
} 
private void DrawLines(Graphics g, PointF[] Points) 
{ 
    g.DrawLines(Pens.Black, Points); 
} 

我拿出每绘图以下持续时间:

Straight Line: 0.095 ms 
Zig-Zag Pattern: 3.24 ms 
Random Pattern: 5.47 ms 

所以似乎逐渐变得越来越糟糕,绘制线条的变化越大,这也是我在开始时提到的控制绘画中遇到的真实世界效果。

我的问题是这样如下:

  1. 为什么会做出如此残酷的差异,这行是要绘制?
  2. 如何提高噪音数据的绘图速度?
+2

忽略一个事实,即bechmarks总是很难得到正确的答案,而不是错误的:1)根据y变化,你的线可能会变长__lot__。你应该从结果中消除这种差异。 2)如果直线不是更快,我会感到惊讶,因为这意味着gdi例程不会识别它们,并错过了优化的好机会。即使是快速线路算法也必须比直接水平/垂直直线运动要慢,因为根本不需要算法,也不需要保持斜率不能去除步骤的滑动。 – TaW

+0

3)您可能需要测试各种平滑模式。即使有轻微的倾斜也会导致大约2-3倍的像素数量,必须在中心线上方和下方涂漆。 – TaW

+0

@TaW妈的,我认为你的第一点是正确的,现在你指出了这点。如果用平均线长划分,随机和曲折时间会收敛。直线实际上是最慢的,但这可能意味着某种其他开销。所以这就是其中的原因,如果有的话要考虑一下。但是优化线条绘制是另一个问题。你会添加一个答案吗? – Jens

回答

3

三点注意的原因是:

  • 线长度:根据实际人数斜线可能不再由少数像素还是很多,甚至通过一些实质性因素。看你的代码我怀疑后者..

  • 算法:绘制斜线确实需要一些算法来找到下一个像素。即使是快速绘图程序也需要做一些计算,而不是垂直或水平线,它们直接穿过像素阵列。

  • 抗锯齿:除非你关掉抗锯齿完全(所有丑陋的后果)像素画的数量也将围绕2-3倍,因为所有那些抗锯齿上方的像素和中心线以下也必须进行计算和绘制。不要忘记计算他们的颜色!

后者的补救措施显然是关闭反锯齿,但其他问题只是事情的方式。所以最好不要担心,并快速的快速直线:-)

1

如果你真的有很多线路或你的线路可能会很长(几次的屏幕大小),或者如果你有很多几乎0像素线,你必须编写代码来减少无用的线条绘制。

好了,这里有一些想法:

  • 如果你写在相同的X多行,那么你可以取代那些由最小值和最大值的Y是x之间的单行。
  • 如果您的线条超出屏幕边界,则应剪切它们。
  • 如果一条线完全位于可见区域之外,则应该跳过它。
  • 如果一条线的长度为0,则不应写入。
  • 如果一行有单个像素长度,则应该只写入该像素。

显然,利益取决于你有多少行画...而且还替代可能无法给出确切相同的结果很多...

在实践中,你画一个图上屏幕,如果你只显示有用的信息,它应该在现代硬件上非常快。

那么如果你使用风格或颜色,它可能不是微不足道的优化数据的显示。

另外,它们是为显示大量数据而优化的一些制图组件...良好的通常很昂贵,但它仍然值得。通常可以进行试验,以便您可以了解您可以提高绩效的多少,然后决定要做什么。

+0

谢谢你的提问,phil。您可以优化绘图过程以减少不需要的绘图操作。我会研究它。在大多数情况下,这很好,因为我的组件不用于实时数据。最近我用数字读出它,并注意到嘈杂时期的极端放缓,这对我来说很奇怪。该图表通常针对具有一些奇怪自定义特征的其他事物进行优化;) – Jens