为什么转换顺序非常重要

单个 Matrix 对象可以存储一个转换或一系列转换。 后者称为复合转换。 通过将单个转换的矩阵相乘,可获得复合转换的矩阵。

复合转换示例

在复合转换中,单个转换的顺序非常重要。 例如,“先旋转再缩放后平移”与“先平移再旋转后缩放”得到的结果并不一样。 在 GDI+ 中,复合转换是从左到右构建的。 如果 S、R 和 T 是缩放、旋转和平移矩阵,SRT 乘积(按该顺序)就表示“先缩放再旋转后平移”的复合转换矩阵。 由 SRT 乘积生成的矩阵不同于 TRS 乘积生成的矩阵。

顺序之所以重要,原因之一就是像旋转和缩放这样的转换是相对于坐标系原点进行的。 缩放以原点为中心的对象产生的结果不同于缩放远离原点的对象所产生的结果。 同样,旋转以原点为中心的对象产生的结果不同于旋转远离原点的对象所产生的结果。

以下示例将缩放、旋转和平移(按该顺序)组合,从而形成复合转换。 传递给 RotateTransform 方法的参数 Append 表示旋转排在缩放之后。 同理,传递给 TranslateTransform 方法的参数 Append 表示平移排在旋转之后。 AppendPrependMatrixOrder 枚举的成员。

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)

前一个示例的结果与本主题中第一个示例的结果相同。 这是因为我们颠倒了方法调用的顺序和矩阵乘法顺序。

另请参阅