Udostępnij za pośrednictwem


Dlaczego kolejność przekształcania jest znacząca

Pojedynczy obiekt Matrix może przechowywać pojedynczą transformację lub sekwencję przekształceń. Ten ostatni jest nazywany transformacją złożoną. Macierz przekształcenia złożonego jest uzyskiwana przez pomnożenie macierzy poszczególnych przekształceń.

Przykłady transformacji złożonej

W transformacji złożonej kolejność poszczególnych przekształceń jest ważna. Jeśli na przykład najpierw obrócisz, potem skalujesz, a na końcu przesuniesz, uzyskasz inny wynik niż w przypadku, gdy najpierw przesuniesz, potem obrócisz, a na końcu skalujesz. W GDI+ przekształcenia złożone są tworzone od lewej do prawej. Jeśli macierze S, R i T są odpowiednio skalowane, obracane i translacyjne, wówczas produkt SRT (w tej kolejności) jest macierzą transformacji złożonej, która najpierw skaluje, a następnie obraca, a następnie tłumaczy. Macierz wygenerowana przez produkt SRT różni się od macierzy produkowanej przez produkt TRS.

Jednym z powodów, dla których kolejność jest istotna, jest to, że przekształcenia, takie jak rotacja i skalowanie, są wykonywane w odniesieniu do początku układu współrzędnych. Skalowanie obiektu, który jest wyśrodkowany na początku, powoduje inny wynik niż skalowanie obiektu, który został przeniesiony z punktu początkowego. Podobnie obracanie obiektu, który jest wyśrodkowany na początku, powoduje inny wynik niż obracanie obiektu, który został przeniesiony z punktu początkowego.

Poniższy przykład łączy skalowanie, rotację i tłumaczenie (w tej kolejności) w celu utworzenia złożonej transformacji. Argument Append przekazany do metody RotateTransform wskazuje, że rotacja będzie podążać za skalowaniem. Podobnie argument Append przekazany do metody TranslateTransform wskazuje, że tłumaczenie będzie podążać za rotacją. Append i Prepend są członkami wyliczenia MatrixOrder.

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)

W poniższym przykładzie wywołania metody są takie same jak w poprzednim przykładzie, ale kolejność wywołań jest odwrócona. Wynikowa kolejność operacji to najpierw translacja, potem obrót, a następnie skalowanie, co daje zupełnie inny wynik niż najpierw skalowanie, potem obrót, a na końcu translacja.

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)

Jednym ze sposobów odwrócenia kolejności poszczególnych przekształceń w transformacji złożonej jest odwrócenie kolejności wywołań metod. Drugim sposobem kontrolowania kolejności operacji jest zmiana argumentu kolejności macierzy. Poniższy przykład jest taki sam jak w poprzednim przykładzie, z tą różnicą, że Append została zmieniona na Prepend. Mnożenie macierzy odbywa się w kolejności SRT, gdzie S, R i T są macierzami do skalowania, obracania i translacji. Kolejność transformacji złożonej to najpierw skalowanie, potem obracanie, a następnie przesuwanie.

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)

Wynik bezpośrednio poprzedniego przykładu jest taki sam jak w wyniku pierwszego przykładu w tym temacie. Dzieje się tak, ponieważ odwracaliśmy zarówno kolejność wywołań metody, jak i kolejność mnożenia macierzy.

Zobacz też