Gráficos vectoriales con Visual Basic .NET

Marzo 2003

Cipriano Valdezate Sayalero y Manuel Valdezate Sayalero

 


 

Transformaciones

 

Transformar una forma, un GraphicsPath, una región o todo el objeto Graphics consiste en modficar su posición o su tamaño. En realidad la transformación no se aplica al dibujo, sino a su eje de coordenadas. Técnicamente, una transformación es una personalización aplicada al eje de coordenadas de mundo. Básicamente las tranformaciones son tres: rotacón, traslación y escalado.

 

 

Rotación

 

Consiste en el giro del eje de coordenadas sobre sí mismo en el sentido de las agujas del reloj. El eje del giro es el origen de coordenadas (0, 0).

 

En el ejemplo siguiente dibujamos un rectángulo y después giramos el eje de coordenadas 45º. El método que rota el eje de coordenadas se llama RotateTransform.

 

Private Sub Rotación()

        Dim i As Short

        Dim Lienzo As Graphics = Me.CreateGraphics

 

        Dim TRAYECTO1 As New GraphicsPath()

        Dim Esquina As New Point(250, 50)

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

 

        'Esta línea une el origen de coordenadas (0,0)

        'con la forma. Se comprueba en el resultado

        'que las dos líneas (la original y la transformada)

        'forman un ángulo de 45º

        TRAYECTO1.AddLine(New Point(0, 0), Esquina)

        Dim Lápiz1 As New Pen(Color.LightGreen, 8)

        Lápiz1.EndCap = LineCap.ArrowAnchor 'le añadimos una flecha

 

        'Encapsulamos la línea en un GraphicsPath

        'y el rectángulo en una región

        'en vez de encapsular ambos en el mismo objeto

        'para poder dibujarlos con colores diferentes

        Dim Trayecto2 As New GraphicsPath()

        Trayecto2.AddRectangle(New Rectangle(Esquina, Tamaño))

        Dim Región1 As New Region(Trayecto2)

 

        For i = 0 To 1

            Lienzo.DrawPath(Lápiz1, Trayecto1) 'Dibujamos la línea

 

            'Combinamos el GraphcsPath con la región

            'para que la transformación se aplique

            'a los dos objetos en conjunto

            Región1.Union(Trayecto1)

 

            'Dibujamos la región completa

            Lienzo.FillRegion(Brushes.Blue, Región1)

 

            'y aplicamos la transformación:

            'rotación del eje de coordenadas

            '45º en el sentido de las agujas del reloj

            Lienzo.RotateTransform(45)

            ‘Después de personalizar el eje de coordenadas

            ‘hay que dibujar la forma, path o región

            ‘para que la transformación tenga efecto.

            ‘este bucle dibuja una región

            ‘aplicándole transformaciones sucesivas

        Next

 

        Trayecto1.Dispose()

        Trayecto2.Dispose()

        Región1.Dispose()

        Lienzo.Dispose()

 

    End Sub

 

 

 

Traslación

 

Esta transformacón traslada (de ahí su nombre) el origen de coordenadas a otro lugar, convirtiéndolo en el nuevo origen de coordenadas (0, 0). El método se llama TranslateTransform y toma como parámetro el nuevo punto que servirá de origen. Técnicamente hablando, TranslateTransform mueve el origen de coordenadas de mundo a un deteminado punto definido por el eje de coordenadas de página.

 

En el capítulo dedicado al GraphicsPath aprendimos a dibujar un eje cartesiano sobre una página milimetrada. Ahora que sabemos mover el origen de coordenadas (0,0), vamos a trazar la gráfica de la funcón seno sobre un eje de coordenadas cuyo origen es el centro del formulario:

 

Private Sub Traslación()

        DibujaGrid() 'Llamamos al método expuesto más arriba

 

        Dim Lienzo As Graphics = Me.CreateGraphics

        Dim Trayecto1 As New GraphicsPath()

 

        Dim m As Integer = 36 'Aleatorio

 

        'el eje de abcisas (x) tendrá

        '36 puntos negatvos y 36 positivos

        'En este array almacenaremos

        'los puntos que forman la gráfica de la función

        Dim Puntos(m * 2) As Point

 

 

        Dim i As Short

 

        For i = -m To m

'Hemos alterado un poco las coordenadas X e Y de los puntos

'para que la gráfica ocupe toda la pantalla y se aprecie mejor,

‘por tanto las unidades de medida de la rejilla y de la gráfica

‘no coinciden, pero eso ahora no tiene importancia.

 

'El valor Y lo multiplicamos por -1

'porque, si bien hemos movido el origen de coordenadas (0,0),

'no hemos alterado la disposición de los valores positivos y negativos.

'Queremos que los valores negativos del eje de ordenadas (y)

'aumenten hacia abajo, no hacia arriba, cual es el caso por defecto.

'Por eso tenemos que multiplicar el componente Y por -1

'en la función seno no se aprecia la diferencia,

'pero en otras la diferencia es obvia.

            Puntos (i + m) = New Point(m / 3 * i, -m * 6 * Math.Sin(i))

        Next

 

        'Construimos la línea curva

        'y se la entregamos al GraphicsPath con AddBeziers

        Trayecto1.AddBeziers(Puntos)

 

        'Aquí movemos el eje de coordenadas

        'al punto central del área cliente del formulario

Lienzo.TranslateTransform(Me.ClientSize.Width / 2, Me.ClientSize.Height / 2)

 

        'Y dibujamos la gráfica

        Lienzo.DrawPath(New Pen(Color.Blue, 4), Trayecto1)

 

        Trayecto1.Dispose()

        Lienzo.Dispose()

End Sub

 

 

 

Escalado

 

Escalar consiste en aumentar o disminuir la distancia entre valores consecutivos de la unidad de medida de los ejes de coordenadas. Técnicamente, el escalado es una operación realizada sobre la unidad de medida definida para las coordenadas de página y asumida por las coordenadas de mundo que consiste en la multiplicación de esta unidad de medida por un número, obteniendo otra unidad de medida totalemente personalizada. Además, pueden definirse unidades de medida diferentes para el eje de abcisas (X) y para el de ordenadas (Y). El efecto resultante son formas proporcionalmente más grandes o más pequeñas.

 

El método se llama ScaleTransform, y toma como parámetros los factores por los que se multiplican las unidades de medida vigentes para los ejes X e Y de las coordenadas de mundo. Visualmente es como si se multiplicaran por esos factores la base y la altura, respectivamente, del rectángulo que circunscribe el dibujo.

 

El escalado, además, no afecta sólo al tamaño de las formas, sino también al grosor del lapicero.

 

En definitiva, se puede comprobar que, puesto que la transformación se aplica a los ejes de coordenadas y no a las formas, aunque éstas varíen de tamaño, los valores que las miden no varían.

 

El siguiente ejemplo muestra un rectángulo escalado dos veces. Si observa el lector los valores que devuleven las propiedades Width y Height del rectángulo, comprobará que no varían:

 

Private Sub Escalado)

        Dim Lienzo As Graphics = Me.CreateGraphics

        Dim Trayecto1 As New GraphicsPath()

        Dim Región1 As New Rectangle(10, 10, 100, 50)

        Trayecto1.AddRectangle(Región1)

 

Lienzo.DrawPath(Pens.Blue, Trayecto1) 'Dibujamos un rectángulo sin transformar

MsgBox(Región1.Width) ’200

 

Lienzo.ScaleTransform(2.0F, 2.0F)

‘Una unidad en los dos ejes ha aumentado el doble

'El efecto es como si multiplicáramos

‘base y anchura del rectángulo por 2

 

Lienzo.DrawPath(New Pen(Color.Blue, 2), Trayecto1)

MsgBox(Región1.Width) ’200

 

Lienzo.ScaleTransform(3.0F, 4.0F)

‘Una unidad en el eje X ha aumentado el triple

‘Una unidad en el eje Y ha aumentado el cuádruple

'Efecto: multiplicar base por 3 y altura por 4.

Lienzo.DrawPath(New Pen(Color.Blue, 2), Trayecto1)

MsgBox(Región1.Width) ’200

 

‘Se ve claramente en el dibujo

‘que el escalado también afecta al grosor del lapicero

End Sub

 

 

 

 

 

Ámbito de las transformaciones

 

Los tres ejemplos expuestos muestran transformaciones aplicadas a todo el área de dibujo, es decir, al objeto Graphics. Son las llamadas transformaciones globales o de mundo. Como dijimos al principio, las transformaciones también se pueden aplicar a regiones, GraphicsPath, o incluso brochas: son las transformaciones locales, que afectan sólo a un determinado objeto y no al resto. Veamos un ejemplo en el que dibujamos un pedazo de tarta y la tarta sin el pedazo, y aplicamos transformaciones diferentes a cada figura. Y aprovechamos el ejemplo para introducir el objeto Matrix:

 

Private Sub TexturaPredeterminada_Click()

        Dim Lienzo As Graphics = Me.CreateGraphics

        Dim Brocha As TextureBrush = New TextureBrush(PictureBox1.Image)

 

        Dim Trayecto1 As New GraphicsPath(),Trayecto2 As New GraphicsPath()

 

        Dim Radio As Integer = 200

 

‘Definimos el punto central del formulario

Dim Centro As Point = _

New Point(Me.ClientSize.Width / 2, Me.ClientSize.Height / 2)

 

        'Trasladamos el origen de coordenadas al centro del lienzo

        'Esta transformación es global porque

        'afecta a todo lo que dibujemos a partir de aquí

        Lienzo.TranslateTransform(Centro.X, Centro.Y)

 

        'Añadimos la tarta sin el pedazo

        Trayecto1.AddPie(DameCuadrado(New Point(0, 0), Radio), 90 * 0, 90 * 3)

        'y le aplicamos una transformación local

  ‘(Hemos importado System.Math)

Trayecto1.Transform(New Matrix(Cos(45), Sin(45), -Sin(45), Cos(45), 0, 0))

 

        'Añadimos el pedazo

        Trayecto2.AddPie(DameCuadrado(New Point(0 + 20, 0 - 20), Radio), 90 * 3, 90)

        'y le aplicamos otra transformación local

Trayecto2.Transform(New Matrix(Cos(45), Sin(45), -Sin(45), Cos(45), 100, 25))

 

        'Explicamos el objeto Matrix en el siguiente capítulo

 

        Lienzo.FillPath(Brocha, Trayecto1) 'Aquí dibujamos

        Lienzo.FillPath(Brocha, Trayecto2) 'cada GraphicsPath

 

        Brocha.Dispose()

        Lienzo.Dispose()

End Sub

 

 


Índice del curso GDI+
 

la Luna del Guille o... el Guille que está en la Luna... tanto monta...