Поделиться через


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

Один объект 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)

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

См. также