Значение порядка преобразований

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

Примеры составных преобразований

Порядок следования отдельных преобразований имеет важное значение для составного преобразования. Например, если применяется поворот, затем масштабирование, а затем сдвиг, получается совершенно иной результат, чем если бы сначала был применен сдвиг, затем поворот, а затем масштабирование. В GDI+ построение составных преобразований осуществляется слева направо. Если S, R и T являются матрицами масштабирования, поворота и сдвига соответственно, тогда произведение SRT (именно в таком порядке) является матрицей составного преобразования, которое сначала масштабирует, затем поворачивает, а затем осуществляет сдвиг. Матрица, равная произведению SRT, отличается от матрицы, являющейся произведением TRS.

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

В следующем примере комбинация масштабирования, поворота и сдвига (именно в таком порядке) используется для конструирования составного преобразования. Аргумент Append, передаваемый методу RotateTransform, указывает на то, что поворот будет выполняться после масштабирования. Аналогично, аргумент Append, передаваемый методу TranslateTransform, указывает, что сдвиг должен следовать за поворотом. Значения Append и Prepend являются членами перечисления MatrixOrder.

Rectangle rect = new Rectangle(0, 0, 50, 50);
Pen pen = new Pen(Color.FromArgb(128, 200, 0, 200), 2);
e.Graphics.ResetTransform();
e.Graphics.ScaleTransform(1.75f, 0.5f);
e.Graphics.RotateTransform(28, MatrixOrder.Append);
e.Graphics.TranslateTransform(150, 150, MatrixOrder.Append);
e.Graphics.DrawRectangle(pen, rect);
Dim rect As New Rectangle(0, 0, 50, 50)
Dim pen As New Pen(Color.FromArgb(128, 200, 0, 200), 2)
e.Graphics.ResetTransform()
e.Graphics.ScaleTransform(1.75F, 0.5F)
e.Graphics.RotateTransform(28, MatrixOrder.Append)
e.Graphics.TranslateTransform(150, 150, MatrixOrder.Append)
e.Graphics.DrawRectangle(pen, rect)

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

Rectangle rect = new Rectangle(0, 0, 50, 50);
Pen pen = new Pen(Color.FromArgb(128, 200, 0, 200), 2);
e.Graphics.ResetTransform();
e.Graphics.TranslateTransform(150, 150, MatrixOrder.Append);
e.Graphics.RotateTransform(28, MatrixOrder.Append);
e.Graphics.ScaleTransform(1.75f, 0.5f);
e.Graphics.DrawRectangle(pen, rect);
Dim rect As New Rectangle(0, 0, 50, 50)
Dim pen As New Pen(Color.FromArgb(128, 200, 0, 200), 2)
e.Graphics.ResetTransform()
e.Graphics.TranslateTransform(150, 150, MatrixOrder.Append)
e.Graphics.RotateTransform(28, MatrixOrder.Append)
e.Graphics.ScaleTransform(1.75F, 0.5F)
e.Graphics.DrawRectangle(pen, rect)

Первым способом изменения порядка выполнения отдельных преобразований, формирующих составное преобразование, на обратный является изменение на обратный порядка вызовов методов. Второй способ управления порядком операций заключается в изменении значения аргумента порядка следования матриц. Следующий пример аналогичен предыдущему, но в нем параметр Append заменен на Prepend. Перемножение матриц осуществляется в порядке SRT, где S, R и T являются матрицами масштабирования, поворота и сдвига соответственно. При применении составного преобразования сначала осуществляется масштабирование, затем поворот, а затем сдвиг.

Rectangle rect = new Rectangle(0, 0, 50, 50);
Pen pen = new Pen(Color.FromArgb(128, 200, 0, 200), 2);
e.Graphics.ResetTransform();
e.Graphics.TranslateTransform(150, 150, MatrixOrder.Prepend);
e.Graphics.RotateTransform(28, MatrixOrder.Prepend);
e.Graphics.ScaleTransform(1.75f, 0.5f);
e.Graphics.DrawRectangle(pen, rect);
Dim rect As New Rectangle(0, 0, 50, 50)
Dim pen As New Pen(Color.FromArgb(128, 200, 0, 200), 2)
e.Graphics.ResetTransform()
e.Graphics.TranslateTransform(150, 150, MatrixOrder.Prepend)
e.Graphics.RotateTransform(28, MatrixOrder.Prepend)
e.Graphics.ScaleTransform(1.75F, 0.5F)
e.Graphics.DrawRectangle(pen, rect)

Результаты, полученные в рассмотренном примере и самом первом примере данного раздела, ничем не отличаются друг от друга. Это объясняется тем, что были изменены на обратный как порядок вызовов методов, так и порядок умножения матриц.

См. также