2016-11-15 83 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