為何變換順序很重要
單一的 Matrix 物件可儲存單一變換或一系列變換。後者稱為複合變換。複合變換矩陣的取得方式是乘以個別變換的矩陣。
在複合變換中,個別變換的順序非常重要。例如,如果先旋轉、再縮放,然後轉換,取得的結果和先轉換、再旋轉,然後縮放的結果不同。在 GDI+ 中,複合變換是從左到右建置。假設 S、R 和 T 依次代表縮放、旋轉和轉換矩陣,則 SRT (依此順序) 的結果是先縮放、再旋轉,然後轉換所產生的複合變換矩陣。SRT 產生的矩陣和 TRS 產生的矩陣不同。
順序很重要的原因之一是,旋轉和縮放這類的變換是根據座標系統的原點來進行。縮放中心位於原點的物件所產生的結果,與縮放已從原點移開的物件不同。同樣地,旋轉中心位於原點的物件所產生的結果,也會與旋轉已從原點移開的物件不同。
下列範例組合了縮放、旋轉和轉換 (依此順序),形成複合變換。傳遞至 RotateTransform 方法的 MatrixOrder.Append 引數指出旋轉將在縮放之後進行。同樣地,傳遞至 TranslateTransform 方法的 MatrixOrder.Append 引數也指出轉換將在旋轉之後進行。Append 和 Prepend 都是 MatrixOrder 列舉型別 (Enumeration) 的成員。
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)
[C#]
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)
[C#]
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);
使複合變換中個別變換的順序顛倒的方式之一,就是將一系列方法呼叫的順序顛倒。控制作業順序的第二種方式是變更矩陣順序引數。下列範例與上述範例相同,只不過是將 Append 變更為 Prepend。矩陣乘法是依照 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)
[C#]
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);
最後這個範例的結果與這個主題中的第一個範例相同。這是因為我們同時將方法呼叫的順序和矩陣乘法的順序都顛倒了。