You are on page 1of 16

Programacion en visual basic

 
Matrices
 
Introducción
 
Transformar figuras consiste, como hemos visto, en rotar, trasladar y/o escalar su
eje de coordenadas. Intuitivamente, sin embargo, no operamos con ejes de
coordenadas, sino con los dibujos mismos. Podríamos, por tanto, definir
transformación como un mapeado de puntos, tal que a cada punto de la figura
original le correspondiera un punto en la figura transformada o final. El punto de la
figura final se obtendría aplicando una operación al de la figura inicial, de tal modo
que, si realizáramos una transformación determinada a una figura, todos los puntos
de la figura final se obtendrían aplicando la misma operación a sus
correspondientes puntos de la figura inicial. Esta operación es una multiplicación
y/o suma de matrices, lo cual es lógico, pues podemos considerar un punto como
una matriz [x,y] compuesta de una fila y dos columnas.
 
No nos vamos a adentrar en teoría de matrices ni pretendemos ser rigurosos en las
definiciones, ni mucho menos nos preocuparemos aquí de demostrar nada
algebráicamente, sino que nos limitaremos a exponer la mínima teoría
imprescindible para entender el funcionamiento del objeto Matrix, que nos será de
gran utilizad para personalizar nuestras transformaciones.
 
Una matriz es un conjunto de valores dispuestos en filas y columnas. En esto, una
matriz es lo mismo que un array. Igual que los arrays, las matrices tienen
dimensones. Las transformaciones de figuras bidimensionales utilizan matrices de
dos dimensiones, es decir, compuestas de filas y columnas. He aquí un ejemplo de
una matriz de dos filas y dos columnas:

Esta es, precisamente, una de las matrices que se utilizan para obtener los puntos
de la figura transformada. Cada elemento de la matriz se define por su posición,
así, por ejemplo, m(1,2) es el elemento situado en la primera fila y segunda
columna. Ésta es una matriz de orden (2,2), que significa que tiene dos filas y dos
columnas. Las matrices cuyo número de filas es igual al número de columnas se
llaman matrices cuadradas de orden n, por consiguiente nos podemos referir a esta
matriz como una matriz cuadrada de orden 2.
 
La diferencia entre los arrays y las matrices radica en que sobre la matriz se
definen determinadas propiedades y operaciones que la convierten en un array
especial. Expondremos a continuación las operaciones que se aplican en el
mapeado de puntos, que, como ya hemos dicho, son la suma y el producto de
matrices.

Operaciones con matrices


 
Suma de matrices
Sólo se pueden sumar matrices del mismo orden. La matriz suma es otra matriz del
mismo orden que se obtiene sumando los elementos de las dos matrices situados
en la misma posición. Por ejemplo:

Aunque, como veremos más adelante, el objeto Matrix realiza todas las operaciones
que necesitemos por nosotros, vamos a escribir, a título meramente ilustrativo, una
función que halle la suma de dos matrices. Le entregaremos un par de arrays de
tipo Decimal y de la misma dimensión que harán de matrices, y devolverá otro
array cuyos elementos serán la matriz suma:

Public Function Suma(ByVal Matriz1(,) As Decimal, ByVal Matriz2(,) As


Decimal) As Decimal(,)
'Comprobamos que las dos matrices son del mismo orden,
'es decir, que las dos tienen igual número de filas
'e igual número de columnas
If Not Matriz1.GetUpperBound(0) = Matriz2.GetUpperBound(0) AndAlso _
Matriz1.GetUpperBound(1) = Matriz2.GetUpperBound(1) Then Exit Function
 
'Creamos la matriz suma
Dim MatrizSuma(Matriz1.GetUpperBound(0), Matriz1.GetUpperBound(1)) As
Decimal
 
Dim i, j As Short
'Y sumamos las matrices
For i = 0 To Matriz1.GetUpperBound(0)
For j = 0 To Matriz1.GetUpperBound(1)
MatrizSuma(i, j) = Matriz1(i, j) + Matriz2(i, j)
Next
Next
 
Return MatrizSuma
End Function
 
Podemos utilizar este procedimiento para porbar la función:
 
Private Sub Prueba_de_Suma()
Dim A As Array = New Decimal(,) {{2, 3}, {4, 1}}
Dim B As Array = New Decimal(,) {{1, 2}, {3, 4}}
Dim R As Decimal(,) = Suma(A, B)
 
MessageBox.Show(String.Format("{0} {1}" _
& ControlChars.CrLf & "{2} {3}", _
R(0, 0), R(0, 1), R(1, 0), R(1, 1)))
 
End Sub

El resultado es la misma matriz que obtuvimos arriba.

Producto de matrices
Sólo se pueden multiplicar dos matrices si el número de columnas de la primera
coincide con el número de filas de la segunda. El resultado es una matriz de tantas
filas como tiene la primera y tantas columnas la segunda. Además, esta operación
no es conmutativa, es decir, el orden de los factores sí altera el producto.
Expresado algebraicamente:
 
A(m,n) x B(n,p) = R(m,p)
 
De ello se deduce que para que dos matrices se puedan multiplicar en los dos
sentidos, es decir, para que podamos efectuar A x B y B x A, las matrices deben ser
cuadradas. Ahora bien, la matriz resultante en cada caso sería diferente, porque no
es lo mismo A x B que B x A. Esto, como veremos más adelante, tiene una
importancia crucial en GDI+, y veremos que variando el orden en que
multipliquemos las matrices obtendremos transformaciones diferentes.
 
Los elementos de la matriz producto R no se calculan multiplicando los
correspondientes de las matrices A y B, como es el caso de la suma. Requiere
alguna cuenta más. Hemos preparado un pequeño truco fácil de seguir que,
además de calcular el producto de matrices, nos servirá de guía para escribir, al
igual que hemos hecho en el apartado anterior, una función en Visual Basic que,
dadas dos matrices cualesquiera que cumplan los requisitos arriba expuestos, nos
calculará su matriz producto.
 
Vamos a multiplicar las siguientes matrices A x B y obtendremos la matriz R, cuyo
número de filas es igual al número de filas de A (2) y cuyo número de columnas es
igual al número de columnas de B (2). Asímismo, el número de filas de A coincide
con el de columnas de B (2). Puesto que vamos a basarnos en este truco para
escribir una función en Visual Basic, numeraremos los índices de cada elemento en
base 0.
 

 
El truco siguiente halla uno a uno los elementos de la matriz producto R.
Hallaremos, para ejemplificarlo, el elemento R(1,0).
 
Primero escribirmos:
 
A( , ) * B( , )
 
Y lo repetimos tantas veces como el número de columnas de la matriz A = número
de filas de la matriz B = 3
 
A( , ) * B( , )
A( , ) * B( , )
A( , ) * B( , )
 
El primer índice del elemento que estamos hallando R(1,0) será el primer índice de
todos los elementos de A, y el segundo índice R(1,0) será el segundo índice de
todos los elementos B:
 
A(1, ) * B( ,0)
A(1, ) * B( ,0)
A(1, ) * B( ,0)
 
Añadimos los índices que faltan empezando por cero (o por 1, si hubiésemos
definido los índices en base 1) e incrementándolos en una unidad de arriba a abajo:
 
A(1,0) * B(0 ,0)
A(1,1) * B(1 ,0)
A(1,2) * B(2 ,0)
 
Localizamos el valor de cada elemento en las matrices A y B, efectuamos las
multiplicaciones y sumamos los resultados:
 
A(1,0) * B(0 ,0) = 3 * 1 = 3
A(1,1) * B(1 ,0) = 2 * 3 = 6
A(1,2) * B(2 ,0) = 1 * 2 = 2
 
R(1,0) = 3 + 6 + 2 = 11
 
Aplicando este sencillo truco a cada uno de los elementos de R obtenemos la matriz
producto R = A x B:
 

 
He aquí la función:
 
Public Function Producto(ByVal A(,) As Decimal, ByVal B(,) As Decimal)
As Decimal(,)
 
'Comprobamos que las matrices cumplen los requisitos
If A.GetUpperBound(1) <> B.GetUpperBound(0) Then
Exit Function
End If
 
Dim i, j, k As Short
'Creamos la matriz producto
Dim R(A.GetUpperBound(0), B.GetUpperBound(1)) As Decimal
 
'Este array de dos columnas
'es meramente operativo
'equivale a las dos columnas
'que hemos creado en el ejemplo:
'A(1,0) * B(0 ,0)
'A(1,1) * B(1 ,0)
'A(1,2) * B(2 ,0)
Dim T(A.GetUpperBound(1), 1) As Decimal
 
'Los dos primeros bucles For
'sirven para ir visitando
'todas las posiciones de la matriz R
For i = 0 To R.GetUpperBound(0)
For j = 0 To R.GetUpperBound(1)
 
'i contiene el primer índice de R
'que colocamos en todas las posiciones
'A(i, ) de los elementos de la primera matriz
'A la vez, en la segunda posción A( ,k)
'vamos aumentando el índice desde cero
'hasta el número de columnas de A,
'que coincide con el de filas de B
'igual que hemos hecho en el ejemplo
For k = 0 To A.GetUpperBound(1)
T(k, 0) = A(i, k)
Next
 
'j contiene el segundo índice de R
'que colocamos en todas las posiciones
'B(,j) de los elementos de la segunda matriz
'A la vez, en la primera posción B(k, )
'vamos aumentando el índice desde cero
'hasta el número de filas de B,
'que coincide con el de columnas de A
'igual que hemos hecho en el ejemplo
For k = 0 To B.GetUpperBound(0)
T(k, 1) = B(k, j)
Next
 
'Ya tenemos definidos todos los elementos.
'Multiplicamos cada pareja del array T
'y vamos acumulando los resultados.
'El resultado final lo colocamos en su posición
'en la matriz producto R
'exactamente igual que en el ejemplo
For k = 0 To T.GetUpperBound(0)
R(i, j) += T(k, 0) * T(k, 1)
Next
 
Next
Next
 
Return R
 
End Function
 
Pruebe el lector a multiplicar las matrices del ejemplo:
 
Private Sub Prueba_de_producto()
Dim A(,) As Decimal = {{1, 2, 3}, {3, 2, 1}}
Dim B(,) As Decimal = {{1, 2}, {3, 1}, {2, 1}}
 
Dim R(,) As Decimal = Producto(A, B)
 
MessageBox.Show(String.Format("{0} {1}" _
& ControlChars.CrLf & "{2} {3}", _
R(0, 0), R(0, 1), R(1, 0), R(1, 1)))
 
End Sub

Tipos de matrices
 
Ahora que sabemos operar con matrices, vamos a tipificar las matrices que generan
las tres transformaciones básicas (traslación, rotación y escalado) y otras para las
que VSNET no ofrece implementación ad hoc.
 
El método que genera transformaciones multiplicando todos los puntos de la figura
origen por la matriz que recibe como parámetro se llama Transform(Matrix). El
constructor de la clase Matrix espera 6 parámetros: cuatro de ellos representan la
matriz cuadrada que multiplicada por todos los puntos de la figura origen genera
diversos tipos de transformaciones, incluida la rotación que acabamos de ver, y los
otros dos representan la matriz de una fila y dos columnas que sumada a todos los
puntos de la figura origen genera, como también hemos visto más arriba, la figura
trasladada. Incluimos en su lugar dentro de las matrices los nombres de los
parámetros para que el lector los identifique
 
Matriz generadora de transformaciones multiplicando por ella los puntos de la figura

origen:

Matriz que sumada a cada punto de la figura origen genera su traslación: [dx, dy]

La sintáxis del constructor del objeto Matrix es la siguiente:

New Matrix(m11, m12, m21, m22, dx, dy)

Traslación
Se obtiene sumando a cada punto una matriz, obviamente compuesta de una fila y
dos columnas:

Punto: [x, y]
Matriz de traslación: [dx, dy]

Matriz final: [x, y] + [dx, dy] = [x+dx, y+dy]

El valor dx representa el movimiento por el eje de abcisas X y dy el movimiento por


el eje de ordenadas Y.
 
En el apartado anterior hemos visto que el objeto Matrix incluye la matriz de
traslación [dx, dy]. Si queremos, por tanto, aplicar una sólo traslación mediante
matrices, los elementos mxx han de representar la matriz identidad, que
explicamos a continuación. Por ejemplo, si queremos mover una figura 15 píxeles
por el eje X y 10 por el eje Y, la línea quedaría así: ("Trayecto" representa un
Graphicspath)
 
Trayecto.Transform(New Matrix(1, 0, 0, 1, 15, 10))
 
Identidad
Transformación identidad es aquella que genera una figura exactamente igual, en la
misma posición, tamaño y orientación que la original, y se obtiene entregando
como parámetro al método Transform la matriz identidad:

1 0
0 1 
 

Rotación
Consiste en el giro de los ejes de coordenadas. Se genera entregando al método
Transform la matriz siguiente:
 cos( ) sin( ) 
 sin( ) cos( )
 

donde a representa los grados de giro medidos en radianes. Los radianes miden la
longitud del arco cortado por los dos radios de longitud = 1 que distan entre sí los
grados especificados. Como la circunferencia mide 2pr y r=1, entonces 360º = 2p
radiantes, o lo que es lo mismo, 180º son p radiantes, y por tanto 1 grado =
p/180 radianes, de modo que si queremos expresar la matriz en grados, para así
utilizar la misma unidad de medida que entregábamos al método RotateTransform,
la matriz de rotación nos queda así:

   
 cos( * 180 sin( *
180 
   
 sin(  * cos( * 
 180 180 

Aplicando esta matriz obtenemos una figura girada g grados en el sentido de las
agujas del reloj.

A continuación presentamos un ejemplo:

Private Sub Rotación_con_y_sin_matriz()


Dim i As Short
Dim Lienzo As Graphics = Me.CreateGraphics

'Movemos el eje de coordenadas a un lugar cercano al


centro
del formulario
Lienzo.TranslateTransform(Me.ClientSize.Width / 2, _
Me.ClientSize.Height / 2 - 100)

'Medidas del rectángulo


Dim Esquina As New Point(100, 0)
Dim Tamaño As New Size(150, 50)

'Dibujamos una línea desde el origen de coordenadas


'hasta el vértice superior izquierdo del rectángulo
Dim Trayecto1 As New GraphicsPath()
Trayecto1.AddLine(New Point(0, 0), Esquina)
Dim Lápiz1 As New Pen(Color.LightGreen, 8)
Lápiz1.EndCap = LineCap.ArrowAnchor
Lienzo.DrawPath(Lápiz1, Trayecto1)

'Dibujamos el rectángulo
Dim Trayecto2 As New GraphicsPath()
Trayecto2.AddRectangle(New Rectangle(Esquina, Tamaño))
Lienzo.FillPath(Brushes.Blue, Trayecto2)

'Construimos la matriz. Queremos rotar el rectángulo 90


grados
'y no queremos trasladar la figura, por eso
'los valores dx y dy son cero.
Dim D As Single = 90.0R * PI / 180
Dim Matriz As Matrix = New Matrix(Cos(D), Sin(D), -Sin(D),
Cos(D), 0.0F, 0.0F)
'Rotar el objeto Graphics mediante el método
RotateTransform
...
Lienzo.RotateTransform(90) 'Inhabilita esta línea si
quieres ver
'los métodos Trayecto1.Transform(M) y
Trayecto2.Transform(M)
en acción
'... es lo mismo que entregar al método Tranform de los
GraphicPath
'la matriz M arriba definida
Trayecto1.Transform(Matriz) 'Inhabilita estas dos líneas
si
quieres
Trayecto2.Transform(Matriz) 'ver el método
Lienzo.RotateTransform(90) en acción

'Dibujamos las figuras encapsuladas en los dos


GraphicsPath.
'No hay que perder de vista que toda transformación se
ejecuta
sobre
'el eje de coordenadas, no sobre las figuras mismas.
'Por tanto, tras transformar los ejes de coordenadas,
'debemos dibujar "manualmente" las figuras.
Lienzo.DrawPath(Lápiz1, Trayecto1)
Lienzo.FillPath(Brushes.Blue, Trayecto2)

Trayecto1.Dispose()
Trayecto2.Dispose()
Lienzo.Dispose()
End Sub
El ejemplo siguiente genera esta misma transformación “manualmente” utilizando
nuestra función de multiplicación de matrices. Multiplicaremos cada uno de los
cuatro vértices del rectángulo por la matriz, y el resultado serán sido los cuatro
vértices del rectángulo girado 90º que vemos en el dibujo. De hecho, todas las
tranformaciones expuestas en este capítulo pueden simularse manualmente
utilizando nuestras funciones Suma y Producto de matrices.

Private Sub Rotación_manual_Click()


Dim i As Short
Dim Lienzo As Graphics = Me.CreateGraphics

'Movemos el eje de coordenadas a un lugar cercano al


centro
del formulario
Lienzo.TranslateTransform(Me.ClientSize.Width / 2, _
Me.ClientSize.Height / 2 - 100)

'Medidas del rectángulo


Dim Esquina As New Point(100, 0)
Dim Tamaño As New Size(150, 50)

'Dibujamos una línea desde el origen de coordenadas


'hasta el vértice superior izquierdo del rectángulo
Dim Lápiz1 As New Pen(Color.LightGreen, 8)
Lápiz1.EndCap = LineCap.ArrowAnchor
Lienzo.DrawLine(Lápiz1, New Point(0, 0), Esquina)

'Dibujamos el rectángulo original


Lienzo.FillRectangle(Brushes.Blue, New Rectangle(Esquina,
Tamaño))

'Hallamos los vértices del rectángulo


Dim N1 As Point = Esquina 'Noroeste
Dim N2 As Point = New Point(N1.X + Tamaño.Width, N1.Y)
'Noreste
Dim N3 As Point = New Point(N2.X, N2.Y + Tamaño.Height)
'Sureste
Dim N4 As Point = New Point(N1.X, N3.Y) 'Suroeste

'Construimos la matriz de rotación.


'Queremos rotar el rectángulo 90 grados
Dim D As Single = 90.0R * PI / 180
Dim Matriz As Array = New Decimal(,) {{Cos(D), Sin(D)}, {-
Sin(D), Cos(D)}}

'Hallamos los vértices del rectángulo transformado


'Primero hallamos las matrices producto
Dim K1(,) As Decimal = Producto(New Decimal(,) {{N1.X,
N1.Y}},
Matriz)
Dim K2(,) As Decimal = Producto(New Decimal(,) {{N2.X,
N2.Y}},
Matriz)
Dim K3(,) As Decimal = Producto(New Decimal(,) {{N3.X,
N3.Y}},
Matriz)
Dim K4(,) As Decimal = Producto(New Decimal(,) {{N4.X,
N4.Y}},
Matriz)

'y luego las convertimos en puntos


Dim T1 As Point = New Point(K1(0, 0), K1(0, 1))
Dim T2 As Point = New Point(K2(0, 0), K2(0, 1))
Dim T3 As Point = New Point(K3(0, 0), K3(0, 1))
Dim T4 As Point = New Point(K4(0, 0), K4(0, 1))

'y por fin dibujamos el rectángulo transformado "a mano"


Lienzo.FillPolygon(Brushes.Blue, New Point() {T1, T2, T3,
T4})
'y la flecha
Lienzo.DrawLine(Lápiz1, New Point(0, 0), T1)
Lienzo.Dispose()
‘El resultado es exactamente el mismo obtenido con la
función anterior
End Sub

Deformación
La deformación ocurre cuando giramos el eje X k grados y el eje Y l grados y k
<> l. Es decir, cada eje gira independientemente del otro. El ángulo que forma
cada brazo del eje con su contiguo deja de ser necesariamente de noventa grados,
y por tanto los ángulos de la figura se alteran. Esta es la matriz:

   
 cos( * 180 sin( *
180 
   
 sin(  * cos( * 
 180 180 

Donde k son los grados que gira el eje X y l los gradpos que gira el eje Y.

Veamos un ejemplo:

Private Sub Deformación()


Dim Lienzo As Graphics = Me.CreateGraphics
'Trasladamos el origen de coordenadas
'cerca del centro del formulario
Lienzo.TranslateTransform(Me.ClientSize.Width / 2 - 50, _
Me.ClientSize.Height / 2 - 100)

'Dibujamos los ejes de coordenadas


Dim h As Integer = 350
Dim lápiz As New Pen(Color.Black, 2)
lápiz.DashStyle = DashStyle.Dot
Lienzo.DrawLine(lápiz, -h, 0, h, 0)
Lienzo.DrawLine(lápiz, 0, h, 0, -h)

'Dibujamos un rectángulo
Dim Trayecto1 As New GraphicsPath()
Trayecto1.AddRectangle(New Rectangle(0, 0, 250, 100))
Lienzo.FillPath(Brushes.LightGreen, Trayecto1)

'Creamos la matriz de transformación


'el eje X lo giramos 5 grados
'y el eje Y lo giramos 60 grados
Dim GiroX As Integer = 5
Dim GiroY As Integer = 60
Dim Radián As Decimal = PI / 180
Dim R As Matrix = New _
Matrix(Cos(GiroX * Rad), Sin(GiroX * Rad), _
-Sin(GiroY * Radián), Cos(GiroY * Radián), _
0.0F, 0.0F)

'Ejecutamos la transformación
'y dibujamos el rectángulo transformado
Trayecto1.Transform(R)
Lienzo.FillPath(Brushes.Blue, Trayecto1)
End Sub

En el dibujo que genera este código podemos apreciar la alteración de los ángulos
de la figura causada por la diferencia de giro de cada eje de coordenadas:

Simetría
Si cambiamos ceros por unos y viceversa en la matriz identidad obtenemos la
figura reflejada en un espejo colocado sobre la bisectriz de los ejes de coordenadas,
es decir, sobre la línea que divide en dos partes iguales la superficie delimitada por
los ejes +X y +Y. Lo veremos más claro en el ejemplo:

0 1 
1 0
 
Private Sub Simetría()
Dim i As Short
Dim Lienzo As Graphics = Me.CreateGraphics

'Medidas del rectángulo


Dim Esquina As New Point(250, 50)
Dim Tamaño As New Size(250, 100)

'Dibujamos la bisectriz
Dim Lápiz As New Pen(Color.Black, 4)
Lápiz.DashStyle = DashStyle.Dot
Lienzo.DrawLine(Lápiz, 0, 0, Me.ClientSize.Height, _
Me.ClientSize.Height)

'Dibujamos el rectángulo
Dim Trayecto1 As New GraphicsPath()
Trayecto1.AddRectangle(New Rectangle(Esquina, Tamaño))
Lienzo.FillPath(Brushes.Blue, Trayecto1)

'Construimos la matriz de simetría.


Dim Matriz As Matrix = _
New Matrix(0.0F, 1.0F, 1.0F, 0.0F, 0.0F, 0.0F)

'Ejecutamos la transformación
Trayecto1.Transform(Matriz)

'y dibujamos el rectángulo transformado


Lienzo.FillPath(Brushes.Blue, Trayecto1)

Trayecto1.Dispose()
Lienzo.Dispose()
End Sub
Si unimos un vértice de un rectángulo con la bisectriz formando una línea
perpendicular y hacemos lo mismo con el mismo vértice del rectángulo reflejado,
entonces las dos líneas se encuentran formando una sola, y la distancia entre el
vértice y la bisectriz es la misma para las dos.

Escalado
Como ya sabemos, el efecto del escalado es el aumento o disminución del tamaño
de la figura por los ejes X y/o Y. La matriz de escalado es la siguiente:

X 0
0 Y 

X = número de veces que escalamos el eje X


Y = número de veces que escalamos el eje Y

Es lo mismo, por ejemplo,

ScaleTransform(3.0F, 2.0F)

Que
Transform(New Matrix(3.0F, 0.0F, 0.0F, 2.0F, 0.0F, 0.0F)

Escalado de figura simétrica

0 X
Y 0 

Es decir, los valores de escalado X e Y los colocamos en el lugar que ocupan tras
convertir la matriz identidad en simétrica. El lector puede fácilmente probar esta
matriz sustituyendo la línea

Dim Matriz As Matrix = New Matrix(0.0F, 1.0F, 1.0F, 0.0F, 0.0F, 0.0F)

Del ejemplo de las figuras simétricas por, por ejemplo, esta:

Dim Matriz As Matrix = New Matrix(0.0F, 0.5F, 0.5F, 0.0F, 0.0F, 0.0F)

Que reduce el tamaño del rectángulo simétrico a la mitad.

Combinación de transformaciones

Otra consecuencia del hecho de que las transformaciones se aplican al eje de


coordenadas y no al gráfico es que cada transformación se acumula a la anterior.
Dos son los tipos posibles de acumulación: suma y multiplicación.
Traslación con el resto de transformaciones

Como vimos más arriba, la traslación se calcula sumando a la matriz punto [x, y] la
matriz de traslación [dx, dy] (VSNET llama a esta matriz “Offset”), resultando
=[x+dx, y+dy]. Puesto que la suma de matrices es conmutativa, es decir, M + N =
N + M, no es imprescindible un objeto específico para la matriz [dx, dy]. De hecho,
y dado que, además, es indiferente ejecutar primero la transformación y después la
traslación o primero la traslación y después la transformación, dx y dy forman
parte, como vimos más arriba, de los elementos del objeto Matrix. Así resulta que
Matrix, en realidad, contiene dos matrices, y es capaz de ejecutar las dos
transformaciones (traslación y cualquier otra) a la vez. Todo lo que tenemos que
hacer es, como venimos haciendo en los ejemplos, dar valores a los elementos
m11, m12, m21, m22 pertenecientes a la matriz de transformación y a los
elementos dx y dy pertenecientes a la matriz de traslación. Se efectuarán las dos
transformaciones.

Ahora bien, si queremos que la figura se mueva y no ejecute


ninguna otra transformación, entonces los valores de m11, m12, m21 y m22 deben
formar la matriz identidad. Por ejemplo:

Trayecto1.Transform(New Matrix(1, 0, 0, 1, 100, 50))

Mueve la figura 100 pixels por el eje de abcisas y 50 por el de ordenadas sin
modificarla. Sólo si también damos valores a mXX entonces se ejecutan las dos
transformaciones a la vez.

Multiplicación de transformaciones
Si ejecutamos una serie de transformaciones en la misma figura aplicando la
matrices M1, M2, M3, … Mn-1, Mn, entonces podemos evitarnos aplicarlas todas y
aplicar sólo una matriz R obteniendo el mismo resultado, y la hallaríamos
multiplicando todas en el mismo orden: R = M1 x M2 x M3 x … x Mn-1 x Mn. Para ello
utilizamos el método Multiply(Matrix, MatrixOrder), como vemos en el siguiente
ejemplo:

Private Sub Combinación()


Dim Lienzo As Graphics = Me.CreateGraphics

'Este procedimiento dibuja (casi) todos los pasos


'de una serie de transformaciones
'aplicadas a un GraphicsPath
'Movemos el eje de coordenadas al centro del formulario
Lienzo.TranslateTransform(Me.ClientSize.Width / 2,
Me.ClientSize.Height / 2)

'Dibujamos un círculo en el centro


'por pura estética
Dim Trayecto0 As New GraphicsPath()
Dim Lápiz As Pen = New Pen(Color.Violet, 4)
Dim Rectángulo As Rectangle = New Rectangle(-25, -25, 50,
50)
Trayecto0.AddEllipse(Rectángulo)
Lienzo.DrawPath(Lápiz, Trayecto0)

'Encapsulamos un cuadrado en un GraphicsPath


'pero no lo dibujamos todavía
Dim Trayecto1 As New GraphicsPath()
Trayecto1.AddRectangle(Rec)

'antes de dibujarlo lo transformamos:


'multiplicamos por dos su tamaño
Trayecto1.Transform(New Matrix(2, 0, 0, 2, 0, 0))

'y lo giramos 45 grados


Dim Ángulo As Decimal = 45 * PI / 180
Trayecto1.Transform(New _
Matrix(Cos(Ángulo), Sin(Ángulo), -Sin(Ángulo),
Cos(Ángulo), 0, 0))
Lienzo.DrawPath(Lápiz, Trayecto1) 'ahora sí lo dibujamos

Dim i As Short : For i = 0 To 3


'Aplicamos cuatro transformaciones seguidas
'con la misma matriz
Trayecto1.Transform(New Matrix(1.5, 0, 0, 1, 0, 0))
Lienzo.DrawPath(Lápiz, Trayecto1)
Next

Trayecto0.Dispose()
Trayecto1.Dispose()
Lienzo.Dispose()
End Sub

Private Sub Multiplicación()


'Este procedimiento ejecuta
'las mismas transformaciones que el anterior
'pero sólo dibuja el resultado final.
'En vez de ir aplicando todas las matrices una a una
'las multiplica, y sólo aplica la matriz producto

Dim Ángulo As Decimal = 45 * PI / 180


Dim M1 As New Matrix(2, 0, 0, 2, 0, 0)
Dim M2 As New _
Matrix(Cos(Ángulo), Sin(Ángulo), -Sin(Ángulo),
Cos(Ángulo), 0, 0)
Dim M3 As New Matrix(1.5, 0, 0, 1, 0, 0)

M1.Multiply(M2, MatrixOrder.Append)
'M1.Multiply(M2, MatrixOrder.Append) = M1 * M2
'M1.Multiply(M2, MatrixOrder.Prepend) = M2 * M1

Dim i As Short : For i = 0 To 3


'Multiply no es una función,
'no devuleve la matriz producto
'sino que sustituye los valores de M1
'por el resultado de la operación
'es decir: M1 = M1 * M3
M1.Multiply(M3, MatrixOrder.Append)
Next

Dim Lienzo As Graphics = Me.CreateGraphics


'Movemos el eje de coordenadas al centro del formulario
Lienzo.TranslateTransform(Me.ClientSize.Width / 2,
Me.ClientSize.Height / 2)

Dim Trayecto0 As New GraphicsPath()


Dim Rectángulo As Rectangle = New Rectangle(-25, -25, 50,
50)
Trayecto0.AddEllipse(Rectángulo) 'dibujamos un circulito
por
mera estética

Dim Lápiz As Pen = New Pen(Color.Blue, 4)


Lienzo.DrawPath(Lápiz, Trayecto0)
Dim Trayecto1 As New GraphicsPath()
Trayecto1.AddRectangle(Rectángulo)

'ejecutamos sólo una transformación


'aplicando la matriz obtenida de multiplicar
'M1 * M2 * M3 * M3 * M3 * M3
Trayecto1.Transform(M1)
Lienzo.DrawPath(Lápiz, Trayecto1)

Trayecto0.Dispose()
Trayecto1.Dispose()
Lienzo.Dispose()
End Sub

Gracias eso es todo …………………

You might also like