変換順序が重要となる理由

1 つの Matrix オブジェクトに格納できるのは、1 つの変換または連続する複数の変換です。 後者を複合変換と呼びます。 複合変換の行列は、個々の変換の行列を掛け合わせることによって得られます。

複合変換の例

複合変換では、個々の変換が行われる順序が重要となります。 たとえば、最初に回転し、スケーリングし、平行移動する場合と、最初に平行移動し、回転し、スケーリングする場合とでは結果が異なります。 GDI+ では、複合変換は左から右に行われます。 S がスケール行列、R が回転行列、T が平行移動行列である場合、その積である SRT (そのままの順序) は、最初にスケーリングし、回転し、平行移動する複合変換の行列となります。 積 SRT によって生成される行列は、積 TRS によって生成される行列と異なります。

実行順序が重要となる理由の 1 つとして、回転やスケーリングなどの変換が座標系の原点を基準にして行われるという点が挙げられます。 原点を中心とするオブジェクトをスケーリングする場合と、原点から離れているオブジェクトをスケーリングする場合とでは、結果が異なります。 同様に、原点を中心とするオブジェクトを回転する場合と、原点から離れているオブジェクトを回転する場合とでも、その結果は異なります。

スケーリング、回転、および平行移動をこの順序で組み合わせて実行される複合変換を次の例に示します。 RotateTransform メソッドに渡される引数 Append は、スケーリングの後に回転が続くことを示します。 同様に、TranslateTransform メソッドに渡される引数 Append は、回転の後に平行移動が続くことを示します。 Append および Prepend は、MatrixOrder 列挙体のメンバーです。

        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.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.TranslateTransform(150, 150, MatrixOrder.Append)
        e.Graphics.RotateTransform(28, MatrixOrder.Append)
        e.Graphics.ScaleTransform(1.75F, 0.5F)
        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);

複合変換の個々の変換の順序を逆にする方法の 1 つとして、連続する複数のメソッドの呼び出し順序を反転させる方法があります。 操作の順序を制御する 2 番目の方法として、行列の順序引数を変更する方法もあります。 次の例は、AppendPrepend に変更されている点を除いて上の例と同じです。 行列の掛け合わせは SRT の順序で行われます。この場合、S、R、T は、それぞれスケール、回転、平行移動の行列です。 複合変換の順序は、最初がスケーリング、次が回転、最後が平行移動となります。

        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)

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);

直前の例の結果は、このトピックの最初の例の結果と同じになります。 それは、メソッドの呼び出し順序も、行列の掛け合わせ順序も両方とも反転させたためです。

参照

参照

Matrix

その他の技術情報

座標系と変換

マネージ GDI+ での変換の使用