Importancia del orden de transformación
Actualización: noviembre 2007
Un único objeto Matrix puede almacenar una transformación o una secuencia de transformaciones. Ésta última se denomina transformación compuesta. La matriz de una transformación compuesta se obtiene multiplicando las matrices de las transformaciones individuales.
Ejemplos de transformación compuestas
En una transformación compuesta, es importante el orden de cada una de las transformaciones. Por ejemplo, si primero se gira, después se cambia el tamaño y después se traslada, el resultado será distinto que si primero se traslada, después se gira y después se cambia el tamaño. En GDI+, las transformaciones compuestas se generan de izquierda a derecha. Si S, R y T son matrices de cambio de tamaño, giro y traslado respectivamente, el producto SRT (en ese orden) es la matriz de la transformación compuesta que primero cambia el tamaño, luego gira y después traslada. La matriz que se obtiene con el producto SRT es distinta a la que se obtiene con el producto TRS.
Una razón por la que el orden es importante es que las transformaciones como el giro y el cambio de tamaño se hacen en relación con el origen del sistema de coordenadas. Cambiar el tamaño de un objeto que está centrado en el origen tiene un resultado diferente a cambiar el tamaño de un objeto que se ha alejado del origen. De forma similar, girar un objeto que está centrado en el origen tiene un resultado diferente a girar un objeto que se ha alejado del origen.
En el ejemplo siguiente se combina el cambio de tamaño, el giro y el traslado (en ese orden) para formar una transformación compuesta. El argumento Append que se pasa al método RotateTransform indica que el giro seguirá al cambio de tamaño. Igualmente, el argumento Append que se pasa al método TranslateTransform indica que la traducción seguirá a la rotación. Append y Prepend son miembros de la enumeración 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);
En el ejemplo siguiente se hacen las mismas llamadas a métodos que en el anterior, pero se invierte el orden de las llamadas. El orden resultante de las operaciones es primero traslado, después giro y después cambio de tamaño, lo cual genera un resultado muy diferente a primero cambiar el tamaño, luego girar y después trasladar.
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);
Una manera de invertir el orden de las transformaciones en una transformación compuesta consiste en invertir el orden de una secuencia de llamadas a métodos. Otra forma de controlar el orden de las operaciones es cambiar el argumento de orden de la matriz. El ejemplo siguiente es igual que el ejemplo anterior, sólo que Append se ha cambiado a Prepend. La multiplicación de la matriz se hace en el orden SRT, donde S, R y T son las matrices de cambio de tamaño, giro y traslado, respectivamente. El orden de la transformación compuesta es primero el cambio de tamaño, después el giro y después el traslado.
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);
El resultado del ejemplo precedente es el mismo que el del primer ejemplo de este tema. Esto es así por que se han invertido el orden de las llamadas a métodos y el orden de la multiplicación de la matriz.