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

Знакомство с мировым преобразованием

Еще одно преобразование, поддерживаемое GDI+, называется мировым преобразованием (world transform). Оно использует традиционную матрицу 3 × 3, но это не обязательно, и матрицу можно заменить любым удобным методом. Для начала взгляните на эту программу, которая выводит первый абзац книги Г. Мелвилла «Моби Дик».

MobyDick.cs

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

  class MobyDick: PrintableForm
  {
      public new static void Main()
      {
          Application.Run(new MobyDick());
      }
      public MobyDick()
      {
          Text = "Moby-Dick by Herman Melville";
      }
      protected override void DoPage(Graphics grfx, Color clr, int cx, int cy)
      {
          // Сюда можно вставить вызовы RotateTransform,
          // ScaleTransform, TranslateTransform и других функций

          grfx.DrawString("Call me Ishmael. Some years ago\x2014never " +
                          "mind how long precisely\x2014having little " +
                          "or no money in my purse, and nothing " +
                          "particular to interest me on shore, I " +
                          "thought I would sail about a little and " +
                          "see the watery part of the world. It is " +
                          "a way I have of driving off the spleen, " +
                          "and regulating the circulation. Whenever " +
                          "I find myself growing grim about the " +
                          "mouth; whenever it is a damp, drizzly " +
                          "November in my soul; whenever I find " +
                          "myself involuntarily pausing before " +
                          "coffin warehouses, and bringing up the " +
                          "rear of every funeral I meet; and " +
                          "especially whenever my hypos get such an " +
                          "upper hand of me, that it requires a " +
                          "strong moral principle to prevent me " +
                          "from deliberately stepping into the " +
                          "street, and methodically knocking " +
                          "people's hats off\x2014then, I account it " +
                          "high time to get to sea as soon as I " +
                          "can. This is my substitute for pistol " +
                          "and ball. With a philosophical flourish " +
                          "Cato throws himself upon his sword; I " +
                          "quietly take to the ship. There is " +
                          "nothing surprising in this. If they but " +
                          "knew it, almost all men in their degree, " +
                          "some time or other, cherish very nearly " +
                          "the same feelings towards the ocean with " +
                          "me.", 
                          Font, new SolidBrush(clr), 
                          new Rectangle(0, 0, cx, cy));
     }
}

Для вас здесь нет ничего нового. Я лишь отметил место, куда можно вставить пару строк кода, после чего, перекомпилировав программу, можно посмотреть на результат.

Начать можно с этого:

  grfx.RotateTransform(45);

Проследите, чтобы этот вызов был вставлен перед вызовом DrawString. В результате текст будет повернут на 45° по часовой стрелке:


Рис. 7.6.

Довольно просто, не так ли? Заметьте: текст по-прежнему внутри прямоугольника, заданного вызовом функции DrawString, хотя этот прямоугольник был повернут вместе с текстом. Повернутый текст также можно напечатать, но должен вас предупредить, что создание файла задания печати займет больше времени, чем обычно.

На что действует RotateTransform? На все упомянутые выше функции рисования объекта Graphics. Аргументом RotateTransform является значение float, которое может быть как положительным, так и отрицательным.

Теперь попробуйте вставить такой код:

  grfx.RotateTransform(-45);

Текст поворачивается на 45° против часовой стрелки. Угол может быть и больше 360°, и меньше –360°. В нашем примере любое значение, которое не разрешается в угол между &hdash;90° и 90°, вызовет поворот текста вправо с выходом за пределы видимой области окна.

Последовательные вызовы RotateTransform имеют кумулятивный эффект. В результате вызовов:

  grfx.RotateTransform(5);
  grfx.RotateTransform(10);
  grfx.RotateTransform(-20);

текст повернется на 5° против часовой стрелки.

А теперь попробуйте это:

  grfx.ScaleTransform(1, 3);

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

  grfx.ScaleTransform(3, 1);

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

  grfx.ScaleTransform(3, 3);

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

  grfx.ScaleTransform(3, 1);
  grfx.ScaleTransform(1, 3);

или:

  grfx.ScaleTransform((float)Math.Sqrt(3), (float)Math.Sqrt(3));
  grfx.ScaleTransform((float)Math.Sqrt(3), (float)Math.Sqrt(3));

Но что самое интересное: после масштабирования текст не становится рваным. Эффект скорее напоминает текст, напечатанный шрифтом большего размера, чем результат увеличения размера уже существующего шрифта.

Могут ли коэффициенты масштабирования быть отрицательными? Да. Однако, если попытаться использовать отрицательный коэффициент прямо сейчас, вы ничего не увидите. Но скоро мы доберемся до места, когда вы сможете применить отрицательные коэффициенты масштабирования и увидеть их потрясающий эффект. Коэффициент масштабирования не может равняться 0, при этом функция вызовет исключение.

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

  grfx.TranslateTransform{100, 50);

добавленный в программу MobyDick, сдвигает начало текста на 100 пикселов вправо и на 50 пикселов вниз от начала клиентской области. Если напечатать эту версию, текст окажется сдвинутым на 1 дюйм вправо и на 1/2 дюйма вниз относительно начала области печати страницы. Отрицательное значение первого аргумента сдвигает текст за левую границу клиентской области, а отрицательное значение — за верхнюю границу этой области.

Смещая текст, можно продемонстрировать другие методики. Вставьте в программу строку:

  grfx.TranslateTransform(cx / 2 , су / 2);

В результате текст начнется в центре клиентской области или страницы принтера, что само по себе не очень интересно. А теперь вставьте такой вызов TranslateTransform:

  grfx.ScaleTransform(-1, 1);

Теперь все стало намного интереснее, правда? А случилось вот что: текст был отражен по вертикальной оси и теперь выводится в зеркально отраженном виде в левой нижней четверти клиентской области:


Рис. 7.7.

А теперь замените вызов ScaleTransform следующим:

  grfx.ScaleTransform(1, -1);

Заметьте, что текст отражается по горизонтальной оси и кажется перевернутым. Эти два эффекта также можно комбинировать:

  grfx.ScaleTransform(-1, -1);

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

Ладно, а теперь поэкспериментируем с порядком вызова TranslateTransform и ScaleTransform:

  grfx.ScaleTransform(-1, 1);
  grfx.TranslateTransform(cx / 2 , су / 2);

Сейчас в клиентской области ничего не видно. Наверное, вы догадались, что текст почему-то переместился за пределы клиентской области. Есть два способа вернуть его назад. Первый — сделать первый аргумент TranslateTransform отрицательным:

  grfx.ScaleTransform(-1, 1);
  grfx.Translatelransform(-cx / 2 , су / 2);

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

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

grfx.ScaleTransform(-1, 1);
grfx.TranslateTransform(cx / 2 , су / 2, MatrixOrder.Append);

Все три рассмотренных выше метода (RotateTransform, ScaleTransform и TranslateTransform) являются перегруженными, чтобы можно было применить последний аргумент — MatrixOrder. Это перечисление, определяемое в пространстве имен System.Drawing.Drawing2D (именно поэтому я для удобства поместил в начале программы MobyDick дополнительную инструкцию using).

Вот формальные определения методов класса Graphics, как уже обсуждавшихся, так и одного нового:


Методы Graphics (выборочно)



void TranslateTransform(float dx, float dy)
void TranslateTransform(float dx, float dy, MatrixOrder mo)
void ScaleTransform(float sx, float sy)
void ScaleTransform(float sx, float sy, MatrixOrder mo)
void RotateTransform(float fAngle)
void RotateTransform(float fAngle, MatrixOrder mo)
void ResetTransform()


Метод ResetTransform возвращает все в исходное состояние. Перечисление MatrixOrder состоит всего из двух членов:


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



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

Prepend 0 Задано по умолчанию
Append 1 Меняет порядок применения преобразований


До конца этой главы функции значений этого перечисления станут ясны.


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

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