2010-07-15 2 views
0

Я рисую рисунок на области рисования.Обновить прямоугольную область на чертеже

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

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

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

Я хочу нарисовать не все пути, которые пересекают прямоугольник, но на самом деле только пути внутри отсечение региона.

alt text http://lh5.ggpht.com/_1TPOP7DzY1E/TD7T0jNU-wI/AAAAAAAADUM/YxaQu4hANpU/s800/Capture1.gif

Другими словами, мне нужен метод, который будет сделать синие линии внутри красной области PINK.

Вот код:

using System.Drawing; 
using System.Windows.Forms; 

namespace WindowsApplication38 
{ 
    public partial class Form1 : Form 
    { 
     Point center; 
     int radius, penWidth; 

     public Form1() 
     { 
      InitializeComponent(); 
      center = new Point(50, 50); 
      radius = 100; 
      penWidth = 5; 
      this.ResizeRedraw = true; 
     } 

     protected override void OnPaint(PaintEventArgs e) 
     { 
      base.OnPaint(e); 

      e.Graphics.Clear(this.BackColor); 

      e.Graphics.DrawImage(
       GetBitmapFromRectangle(e.ClipRectangle), 
       e.ClipRectangle.Location); 

      // 
      // INITIAL DRAWING METHOD 
      //    
      Pen p = new Pen(Color.Blue, penWidth); 
      // draw O 
      e.Graphics.DrawEllipse(p, center.X - radius, center.Y - radius, radius * 2, radius * 2); 
      // draw X 
      Point[] line1 = new Point[] { new Point(0, 0), new Point(this.Width, this.Height) }; 
      Point[] line2 = new Point[] { new Point(this.Width, 0), new Point(0, this.Height) }; 
      e.Graphics.DrawLines(p, line1); 
      e.Graphics.DrawLines(p, line2); 
      p.Dispose(); 
     } 

     private Bitmap GetBitmapFromRectangle(Rectangle rect) 
     { 
      Bitmap bmp = new Bitmap(rect.Width, rect.Height); 
      Graphics g = Graphics.FromImage(bmp); 
      if (rect != this.DisplayRectangle) 
       g.Clear(Color.Red); 
      else 
       g.Clear(this.BackColor); 

      // Draw ONLY! the intersetion between drawing and rectangle... 
      // How to ??? 

      return bmp; 
     } 
    } 
} 

Nota Bene

Пример приведен пример только для демо-целей. В реальном проекте у меня очень сложная графика, а время рисования намного дороже, чем вычисление. Вот почему я хочу не перерисовывать всю картину, а только линии внутри области отсечения!

ответ

0

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

Если вы обнаружите, что это полезно для выбраковки, самый простой подход, чтобы найти ограничительную рамку для каждого объекта и тест для прямоугольника пересечения:

bool intersect = left1 < right2 && left2 < right1 && top1 < bottom2 && top2 < bottom1. 

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

+0

Возможно, однако, я буду использовать GetBitmapFromRectangle (...) для обновления графика в ситуациях, таких как перемещение с помощью мыши графического элемента внутри чертежа. – serhio

+0

Ваш «код» слева направо не имеет смысла. Посмотрите приведенный пример, как вы можете применить свой тест? – serhio

+1

Знаете ли вы, что означает «найти ограничивающий прямоугольник»? В случае эллипса 'left1 = center.X - радиус; right1 = center.X + radius; top1 = center.Y - радиус; bottom1 = center.Y + radius; 'и' (left/right/top/bottom) 2 соответствуют области отсечения. Перед тем, как голосовать, кто-то, кто отвечает вам, не понимает, вы, возможно, захотите дать им возможность решить свои проблемы. –

0

Я бы скопировал существующий код чертежа в метод GetBitmapFromRectangle без каких-либо изменений. Необходимая оптимизация уже выполняется путем уменьшения обновленной области. Существующий код, скопированный в GetBitmapFromRectangle, просто рисует некоторые строки за пределами границ растрового изображения, это нормально - класс Graphics может справиться с этим. Тестирование каждого примитива рисунка для пересечения с отсекающим прямоугольником только снижает производительность программы.

+0

не согласны. фигура параллельна (или хуже изогнута) линиями ширины панели и тонким вертикальным обрезающим прямоугольником. И, после моих тестов, время рисования занимает еще больше, чем вычисление. – serhio

+0

Если ваш фактический чертеж намного сложнее, это делает смысл. В этом случае вам нужна математика, специфичная для ваших алгоритмов - как простой тест, показанный Марсело Кантосом. Но это невозможно сказать, не глядя на ваш фактический код чертежа. –

+0

Код, который я дал, близок коду, который я использую. Мне нужно просто получить пути пересечения в коде выше. – serhio

-1

Вы должны проверить класс GraphicsPath в System.Drawing.Drawing2D.

+0

GraphicsPath - это единственный способ в GDI + сделать то, что вам нужно. – pmcilreavy

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