为什么转换顺序非常重要

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

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

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

以下示例将缩放、旋转和平移(按该顺序)组合,从而形成复合转换。 传递给 Graphics::RotateTransform 方法的参数 MatrixOrderAppend 指定旋转将遵循缩放比例。 同样,传递给 Graphics::TranslateTransform 方法的参数 MatrixOrderAppend 指定转换将跟随旋转。

Rect rect(0, 0, 50, 50);
Pen pen(Color(255, 255, 0, 0), 0);
graphics.ScaleTransform(1.75f, 0.5f);
graphics.RotateTransform(28.0f, MatrixOrderAppend);
graphics.TranslateTransform(150.0f, 150.0f, MatrixOrderAppend);
graphics.DrawRectangle(&pen, rect);

以下示例进行的方法调用与上一示例相同,但调用顺序相反。 生成的操作顺序是先平移、再旋转、再缩放,这会产生与第一个缩放、旋转、再平移非常不同的结果:

Rect rect(0, 0, 50, 50);
Pen pen(Color(255, 255, 0, 0), 0);
graphics.TranslateTransform(150.0f, 150.0f);
graphics.RotateTransform(28.0f, MatrixOrderAppend);
graphics.ScaleTransform(1.75f, 0.5f, MatrixOrderAppend);
graphics.DrawRectangle(&pen, rect);

在复合转换中反转单个转换顺序的一种方法是反转方法调用序列的顺序。 控制操作顺序的第二种方法是更改矩阵顺序参数。 以下示例与上一个示例相同,只不过 MatrixOrderAppend 已更改为 MatrixOrderPrepend。 矩阵乘法按 SRT 顺序执行,其中 S、R 和 T 分别是缩放、旋转和平移矩阵。 复合转换的顺序是“先缩放再旋转后平移”。

Rect rect(0, 0, 50, 50);
Pen pen(Color(255, 255, 0, 0), 0);
graphics.TranslateTransform(150.0f, 150.0f,MatrixOrderPrepend);
graphics.RotateTransform(28.0f, MatrixOrderPrepend);
graphics.ScaleTransform(1.75f, 0.5f, MatrixOrderPrepend);
graphics.DrawRectangle(&pen, rect);

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