2016-11-15 2 views
2

При использовании самописного управления графикой я заметил, что картина графика была намного медленнее при отображении шумных данных, чем при отображении чистых данных.
Я вникнул и сузил проблему до ее минимальной минимальной разницы: рисовал то же количество линий с переменными значениями Y по сравнению с линиями рисования с тем же значением Y.Рисование линий зигзага намного медленнее, чем рисование прямых линий.

Так, например, я собрал следующие тесты. Я генерирую списки точек, один со случайными значениями Y, один с тем же Y, и один с шаблоном Zig-Zag 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) вы можете протестировать различные сглаживающие моды. с antaliasing даже небольшой уклон приведет к примерно в 2-3 раза больше пикселей, которые должны быть окрашены выше и ниже центральной линии. – TaW

+0

@TaW Черт, я думаю, что ваш первый пункт правильный и даже совершенно очевидный, когда вы указываете его. Если я разделяю среднюю длину строки, случайные и зигзагообразные времена сходятся. Прямая на самом деле самая медленная, но это может означать лишь некоторые другие накладные расходы. Так вот в чем причина, подумать об этом, если есть. Но оптимизировать рисование линии - еще один вопрос. Не могли бы вы добавить ответ? – Jens

ответ

3

Три причины приходят на ум:

  • Длина линии: В зависимости от фактического числа наклонных линий может быть больше всего на несколько пикселей или много или даже каким-то существенным фактором. Глядя на ваш код, я подозреваю, что последний.

  • Алгоритм: Нанесение наклонных линий требует некоторого алгоритма для поиска следующих пикселей. Даже быстрые процедуры рисования должны выполнять некоторые вычисления, а не вертикальные или горизонтальные линии, которые проходят прямо через массивы пикселей.

  • Сглаживание: Если вы не отключить антиалиасинг полностью (со всеми уродливыми последствиями) количество пикселей раскрасить также будет примерно в 2-3 раза больше, как и все те, сглаживание пикселей выше и ниже центральных линий также должны быть рассчитаны и нарисованы. Не забывайте вычислять их цвета!

Средство для последней части, очевидно, должно отключить сглаживание, но другие проблемы - это просто вещи. Поэтому лучше всего не волнуйтесь и будьте счастливы в отношении быстрых прямых линий :-)

1

Если у вас действительно много линий или ваши линии могут быть очень длинными (в несколько раз размером экрана), или если вы имеют много почти 0-пиксельной строки, вам нужно написать код, чтобы уменьшить бесполезный рисунок строк.

Ну, вот некоторые идеи:

  • Если вы пишете много строк в то же х, то вы могли бы заменить те, на одной линии между мин и макс у в то х.
  • Если ваша линия выходит за границы экрана, вы должны закрепить их.
  • Если линия полностью вне видимой области, вы должны пропустить ее.
  • Если линия имеет длину 0, ее не следует записывать.
  • Если линия имеет длину одного пикселя, вы должны написать только этот пиксель.

Очевидно, что преимущество во многом зависит от того, сколько строк вы рисуете ... А также альтернатива не может дать тот же результат ...

На практике вы рисуете диаграмму на экран, тогда, если вы показываете только полезную информацию, она должна быть довольно быстрой на современном оборудовании.

Ну, если вы используете стиль или цвета, возможно, не так просто оптимизировать отображение данных.

В качестве альтернативы, они представляют собой компонент диаграмм, которые оптимизированы для отображения больших данных ... Хороший, как правило, дорогой, но он все равно может стоить того. Часто проводятся испытания, поэтому вы можете получить представление о том, как увеличить производительность, а затем решить, что делать.

+0

Спасибо за ваш вклад, фил. Вы делаете хорошие советы об оптимизации процесса рисования, чтобы уменьшить ненужные операции рисования. Я посмотрю. В большинстве случаев это нормально, поскольку мой компонент не используется для данных в реальном времени. В последнее время я использовал его с цифровыми считываниями и заметил экстремальное замедление в течение шумных периодов, вот что показалось мне странным. Диаграмма обычно оптимизирована для других вещей с некоторыми странными пользовательскими функциями;) – Jens

Смежные вопросы