変換順序が重要となる理由
1 つの Matrix オブジェクトは、1 つの変換または一連の変換を格納できます。 後者は 複合変換と呼ばれます。 複合変換の行列は、個々の変換の行列を乗算することによって取得されます。
複合変換では、個々の変換の順序が重要です。 たとえば、最初に回転し、拡大縮小してから、平行移動する場合と、最初に平行移動し、回転してから、拡大縮小する場合では、得られる結果が異なります。 Windows GDI+ では、複合変換は左から右に構築されます。 S、R、T をそれぞれ拡大縮小、回転、拡大縮小の各行列とすると、積 SRT (この順序で) は、最初に拡大縮小し、回転してから、拡大縮小する複合変換の行列になります。 積 SRT によって生成される行列と、積 TRS によって生成される行列は異なります。
順序が重要である理由の 1 つは、回転や拡大縮小などの変換が、座標系の原点に対して行われるということです。 原点を中心にして配置されているオブジェクトの拡大縮小と、原点から離れた位置に移動されたオブジェクトの拡大縮小では、異なる結果が生成されます。 同様に、原点を中心にして配置されているオブジェクトの回転と、原点から離れた位置に移動されたオブジェクトの回転でも、異なる結果になります。
拡大縮小、回転、平行移動を (この順序で) 組み合わせて複合変換を作成する例を次に示します。 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);
複合変換の個々の変換の順序を逆にする方法の 1 つは、一連のメソッド呼び出しの順序を逆にすることです。 操作の順序を制御するもう 1 つの方法は、行列の順序引数を変更することです。 次の例は、 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);
前の例の結果は、このセクションの最初の例で達成した結果と同じです。 これは、メソッド呼び出しの順序と行列乗算の順序の両方を逆にしたためです。