netlib.narod.ru< Назад | Оглавление | Далее >

Отсечение при помощи контуров

Помимо рисования и заливки, контуры позволяют определять область отсечения для объекта Graphics.


Методы SetClip класса Graphics (выборочно)



void SetClip(GraphicsPath path)
void SetClip(GraphicsPath path, CombineMode cm)


Пусть в контуре содержится эллипс. При вызове первой версии метода SetClip вывод всех элементов, которые будут нарисованы затем, будет ограничен областью, заданной этим эллипсом. О второй версии метода SetClip я расскажу чуть позже. А сейчас давайте сразу перейдем к демонстрационной программе. Программа Clover определяет контур из четырех перекрывающихся эллипсов, задающий область отсечения.

Clover.cs

  //---------------------------------------
  // Clover.cs (C) 2001 by Charles Petzold
  //---------------------------------------
  using System;
  using System.Drawing;
  using System.Drawing.Drawing2D;
  using System.Windows.Forms;

  class Clover: PrintableForm
  {
      public new static void Main()
      {
          Application.Run(new Clover());
      }
      public Clover()
      {
          Text = "Clover";
      }
      protected override void DoPage(Graphics grfx, Color clr, int cx, int cy)
      {
          GraphicsPath path = new GraphicsPath();

          path.AddEllipse(0,      cy / 3, cx / 2, cy / 3);  // Левый
          path.AddEllipse(cx / 2, cy / 3, cx / 2, cy / 3);  // Правый
          path.AddEllipse(cx / 3, 0,      cx / 3, cy / 2);  // Верхний
          path.AddEllipse(cx / 3, cy / 2, cx / 3, cy / 2);  // Нижний

          grfx.SetClip(path);
          grfx.TranslateTransform(cx / 2, cy / 2);

          Pen   pen     = new Pen(clr);
          float fRadius = (float) Math.Sqrt(Math.Pow(cx / 2, 2) + 
                                            Math.Pow(cy / 2, 2));
     
          for (float fAngle = 0; fAngle <  (float) Math.PI * 2; 
                                 fAngle += (float) Math.PI / 180)
          {
              grfx.DrawLine(pen, 0, 0, fRadius * (float) Math.Cos(fAngle),
                                      -fRadius * (float) Math.Sin(fAngle));
          }
      }
  }

Метод DoPage создает объект GraphicsPath. Созданный контур состоит из 4 эллипсов, размер которых зависит от размера клиентской области или страницы принтера. Метод SetClip задаст для объекта Graphics область отсечения, ограниченную созданным контуром.

Далее DoPage указывает начало координат в центре области рисования и рисует 360 линий, расходящихся от центра во все стороны. Линии обрезаются по границам внутренних областей эллипсов:


Рис. 15.8.

Нарисовать такую картинку любым другим способом было бы куда труднее. Заметьте: в область отсечения не входят области перекрытия эллипсов. Это результат режима заливки контуров, заданного по умолчанию, — FillMode.Alternate. Если перед вызовом SetClip изменить режим заливки:

  path.FillMode = FillMode.Winding;

области перекрытия эллипсов станут частью области отсечения.

Алгоритм отсечения часто работает медленно. Я породил класс Clover от PrintableForm, так что можно распечатать картинку, щелкнув по клиентской области, но знайте: программа может печатать изображение час или даже дольше.

Естественно, возникает вопрос: как преобразование страницы и мировое преобразование повлияют на область отсечения?

При вызове SetClip предполагается, что координаты контура — это мировые координаты. Последние преобразуются в координаты устройства так же, как при прорисовке или заливке контура. При этом границы области отсечения сохраняются в координатах устройства и остаются таковыми. Например, после вызова SetClip в программе Clover можно как угодно менять преобразование страницы и мировое преобразование, но рисование линий по-прежнему будет ограничено той же областью окна. Фактически после вызова метода TranslateTransform расположение области отсечения в программе Clover не изменилось.

Вторая из версий SetClip позволяет дополнить существующую область отсечения новой, заданной этим методом.


Перечисление CombineMode



Член Значение Описание

Replace 0 Область отсечения заменяется на новую
Intersect 1 Область отсечения — общий фрагмент старой и новой областей
Union 2 Область отсечения — объединение старой и новой областей
Xor 3 Область отсечения — объединение неперекрывающихся частей старой и новой областей
Exclude 4 Область отсечения — старая область без фрагментов, перекрывающихся новой
Complement 5 Область отсечения — новая область без фрагментов, перекрывающихся старой


Следующая программа создаст область отсечения на основе двух перекрывающихся эллипсов. Команда меню позволяет выбирать значение перечисления CombineMode, определяющее способ объединения двух эллипсов. После этого программа целиком закрашивает клиентскую область. Как и в PathWarping, я присвоил каждому пункту меню значение от 1 до 5, соответствующее одному из значений перечисления CombineMode.

ClippingCombinations.cs

  //-----------------------------------------------------
  // ClippingCombinations.cs (C) 2001 by Charles Petzold
  //-----------------------------------------------------
  using System;
  using System.Drawing;
  using System.Drawing.Drawing2D;
  using System.Windows.Forms;

  class ClippingCombinations: PrintableForm
  {
      string   strCaption = "CombineMode = ";
      MenuItem miCombineMode;

      public new static void Main()
      {
          Application.Run(new ClippingCombinations());
      }
      public ClippingCombinations()
      {
          Text = strCaption + (CombineMode)0;

          Menu = new MainMenu();
          Menu.MenuItems.Add("&CombineMode");

          EventHandler ehClick = new EventHandler(MenuCombineModeOnClick);
          
          for (int i = 0; i < 6; i++)
          {
              MenuItem mi   = new MenuItem("&" + (CombineMode)i);
              mi.Click     += ehClick;
              mi.RadioCheck = true;

              Menu.MenuItems[0].MenuItems.Add(mi);
          }
          miCombineMode = Menu.MenuItems[0].MenuItems[0];
          miCombineMode.Checked = true;
      }
      void MenuCombineModeOnClick(object obj, EventArgs ea)
      {
          miCombineMode.Checked = false;
          miCombineMode = (MenuItem) obj;
          miCombineMode.Checked = true;

          Text = strCaption + (CombineMode)miCombineMode.Index;
          Invalidate();
      }
      protected override void DoPage(Graphics grfx, Color clr, int cx, int cy)
      {
          GraphicsPath path = new GraphicsPath();
          path.AddEllipse(0, 0, 2 * cx / 3, cy);
          grfx.SetClip(path);

          path.Reset();
          path.AddEllipse(cx / 3, 0, 2 * cx / 3, cy);
          grfx.SetClip(path, (CombineMode)miCombineMode.Index);

          grfx.FillRectangle(Brushes.Red, 0, 0, cx, cy);
      }
  }

Вот результат выполнения программы при выборе режима объединения CombineMode.Xor.


Рис. 15.9.

Дополнительные версии метода позволяют задавать (или комбинировать) области отсечения при помощи прямоугольников:


Методы SetClip класса Graphics (выборочно)



void SetClip(Rectangle rect)
void SetClip(Rectangle rect, CombineMode cm)
void SetClip(RectangleF rectf)
void SetClip(RectangleF rectf, CombineMode cm)


В классе Graphics также есть методы IntersectClip и ExcludeClip, которые позволяют модифицировать существующую область отсечения. Чтобы задать обычную (т.е. бесконечно большую) область отсечения, вызовите метод ResetClip.


Метод ResetClip класса Graphics



void ResetClip()


netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz