Gráficos vectoriales con Visual Basic .NET

Marzo 2003 (revisado Sep 2003)

Cipriano Valdezate Sayalero y Manuel Valdezate Sayalero

 


 

Formas Básicas

 

Punto

 

Un punto es un objeto compuesto por un par de valores de tipo Integer que representan las coordenadas X e Y en el eje de coordenadas. Se construye así (para un punto situado en x=10 y y=10:

 

Dim MiPunto As Point = New Point(10, 10)

 

No hemos encontrado ningún método que dibuje un punto en una superficie en blanco. Un buen truco es dibujar una línea cuyos extremos inicial y final sean tan cercanos que parezca un punto, o también pintar un círculo muy muy pequeñito.

 

Otra cosa es cambiar u obtener el color de un pixel de un bitmap. Aquí tenéis un buen ejemplo de ello.

 

Las formas primitivas que explico a continuación se dibujan invocando métodos de la clase Graphics.

 

Línea

 

Una línea se define por dos puntos y el trazo que los une. El método que dibuja líneas se llama DrawLine:

 

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

Dim Punto1 As Point = New Point(10, 10)

Dim Punto2 As Point = New Point(100, 100)

Lienzo.DrawLine(p, t1, t2)

 

Utilizando la notación sin variables intermedias quedaría así:

 

Lienzo.DrawLine(New Pen(Color.Blue, 10), New Point(10, 10), New Point(100, 100))

 

Junto con el método DrawLine disponemos del método DrawLines. En vez de dos puntos, DrawLines recibe un array de puntos y dibuja una línea quebrada compuesta por todas las líneas rectas que unen los puntos del array. Si queremos, sin embargo, que la unión entre todos los puntos forme una línea curva, disponemos del método DrawBeziers, que también toma como parámetro un array de puntos. Este método es ideal para trazar gráficas de funciones. El siguiente ejemplo traza un tramo de la gráfica de la función y=2x2+2x+2

 

Dim i As Short

Dim Puntos(100) As Point

For i = 0 To 100

     Puntos.SetValue(New Point(i + 100, 2 * i ^ 2 + 2 * i + 2), i)

Next

Lienzo.DrawBeziers(Pens.Black, Puntos)

 

Observe el lector que el lapicero no ha sido construido, sino que se ha recurrido a la enumeración Pens.

 

Ahora que sabemos dibujar líneas podemos profundizar en el objeto lapicero.

 

Una línea puede ser continua (valor por defecto) o discontinua. Los diferentes modelos de discontinuidad se seleccionan llamando a la enumeración DashStyle:

 

Lápiz.DashStyle = DashStyle.DashDotDot

 

Podemos crear modelos de discontinuidad personalizados asignando a la propiedad DashPattern del objeto Pen un array de valores de tipo Single. El número de elementos de este array ha de ser par. Veamos un ejemplo:

 

Dim Modelo() As Single = {2, 8, 1, 9, 3, 8}

Lápiz.DashPattern = Modelo

 

'Dibuja un círculo

Lienzo.DrawEllipse(Lápiz, New Rectangle(200, 200, 200, 200))

‘Más abajo explico el método DrawEllipse

 

Este código genera el siguiente dibujo:

 

Cada par de elementos del array representa una proporción entre un tramo pintado y el contiguo en blanco. En el dibujo siguiente he señalado las proporciones:

 

 

Además de trazar líneas discontínuas, el objeto Pen puede modificar los extremos de las líneas para convertirlas en flechas. La propiedad StartCap personaliza el origen de la flecha y la propiedad EndCap el final. Ambas esperan un valor de la enumeración LineCap. El código siguiente convierte una recta en la flecha siguiente:

 

Dim Lápiz As New Pen(Color.DarkOrange, 10)

Lápiz.StartCap = LineCap.SquareAnchor

Lápiz.EndCap = LineCap.ArrowAnchor

Lienzo.DrawLine(p2, 280, 30, 500, 30)

 

 

 

 

Rectángulo

 

Para VSNET, un rectángulo es un polígono de cuatro lados tal que, dado un lado cualquiera, existe otro paralelo a él, y además todos los vértices forman un ángulo recto. Un cuadrado, por tanto, sólo es un caso particular de rectángulo que se distingue porque todos sus lados miden lo mismo.

 

El objeto Rectangle se compone de las coordenadas de su vértice superior izquierdo, la anchura y la altura. Para dibujarlo invocamos al método DrawRectangle que acepta como parámetros el lapicero y un objeto Rectangle:

 

Lienzo.DrawRectangle(Lápiz, New Rectangle(100, 100, 200, 100))

 

Similar a DrawLines, disponemos del método DrawRectangles, que espera un array de rectángulos y los dibuja todos a la vez.

 

 

Elipse

 

El método DrawEllipse toma los mismos argumentos que el método DrawRectangle, pero en vez de dibujar un rectángulo, dibuja una elipse circunscrita en él. Para dibujar un círculo, por tanto, hay que definir un cuadrado:

 

'Dibuja una elipse circunscrita en el rectángulo anterior

Lienzo.DrawEllipse(Lápiz, New Rectangle(100, 100, 200, 100))

 

'Dibuja un círculo

Lienzo.DrawEllipse(Lápiz, New Rectangle(200, 200, 200, 200))

 

El método natural de trazado de un círculo no es, sin embargo, su circunscripción en un rectángulo, sino el trazado de una línea equidistante en todos sus puntos de un punto central. Escribiremos, por tanto, una función que devuelva un rectángulo a partir del punto central y sus ejes mayor y menor, que además nos servirá para definir no sólo el círculo, sino cualquier elipse a partir del punto central y sus dos ejes:

 

 

Private Function DameRec(ByVal PuntoCentral As Point, _

                             ByVal EjeMayor As Integer, _

                             ByVal EjeMenor As Integer) _

As Rectangle

Rem Devuelve un rectángulo a partir de su punto central y sus dos ejes

Dim Punto As Point = New Point(PuntoCentral.X - EjeMayor, PuntoCentral.Y - EjeMenor)

        Dim Tamaño As Size = New Size(EjeMayor * 2, EjeMenor * 2)

        Return New Rectangle(Punto, Tamaño)

 

End Sub

 

Private Sub DibujaElipse(ByVal Lienzo As Graphics, _

                             ByVal Lápiz As Pen, _

                             ByVal Punto As Point, _

                             ByVal EjeMayor As Integer, _

                             ByVal EjeMenor As Integer)

 

 

        Lienzo.DrawEllipse(Lápiz, DameRec(Punto, EjeMayor, EjeMenor))

 

End Sub

 

Private Sub DibujaCírculo(ByVal Lienzo As Graphics, _

                              ByVal Lápiz As Pen, _

                              ByVal Punto As Point, _

                              ByVal Radio As Integer)

 

        DibujaElipse(Lienzo, Lápiz, Punto, Radio, Radio)

End Sub

 

 

Arco

 

Dibujar un arco es igual que dibujar un círculo, añadiéndole dos argumentos más: el punto inicial del arco y el ángulo que forma girando en el sentido de las agujas del reloj, ambos medidos en grados. El método se llama DrawArc:

 

gr.DrawArc(New Pen(Color.Red, 10), New Rectangle(250, 250, 250, 250), 0, 90)

 

es decir, estamos dibujando un arco cuyo punto inicial es el punto 00 y se extiende 900 en el sentido de las agujas del reloj, como muestra el siguiente esquema:

 

 

 

 

 

Polígono

 

El método DrawPolygon recibe, además del lapicero, un array de puntos, y los une con rectas. Hasta aquí es igual al método DrawLines. La diferencia está en que DrawPolygon une el primer punto con el último del array formando así un polígono cerrado. El siguiente ejemplo dibuja un rombo:

 

Lienzo.DrawPolygon(Lápiz, New Point() {New Point(200, 50), New Point(300, 100), New Point(200, 150), New Point(100, 100)})

 

 

 

Curva Bézier

 

Una curva Bézier está compuesta por sus puntos inicial y final y dos puntos de control. La función de los puntos de control no es que la curva pase por ellos, sino influenciar su dirección. Lo veremos con un ejemplo. La línea de color azul es la curva Bézier. Cada punto de control está unido por una línea imaginaria con su punto: el primero, con el inicial de la curva, y el segundo con el final. Pues bien, la curva inicia su recorrido en la dirección de la primera línea imaginaria, pero, a medida que avanza, rectifica su dirección para adecuarse a la que le marca la segunda línea imaginaria. Así es como se forma la curva. El dibujo del ejemplo está trazado a mano, por ello quizá no sea exacto. Lo mejor para entender las curvas Bézier es experimentar con ellas.

 

El método que dibuja curvas Bézier se llama DrawBezier. Toma como parámetros, además del lapicero, los cuatro puntos: el punto inicial de la curva, el primer punto de control, el segundo punto de control y el final de la curva:

 

Lienzo.DrawBezier(New Pen(Color.Red, 10), New Point(10, 30), New Point(100, 20), New Point(140, 190), New Point(200, 200))

 


 

Curvas cardinales

 

Se llaman así las curvas definidas por un valor numérico llamado “tensión” que mide la flexibilidad de la curva. Imaginemos dos puntos unidos por una recta. Si esta recta se convierte en curva, la longitud del arco y, por tanto, la “profundidad” de la curva aumentan según aumente la “flexibilidad” de la línea. Una línea recta equivale a una tensión máxima representada por el valor 0, y una línea curva disminuye su tensión y aumenta su flexibilidad hasta un valor de 2. Lo mejor para entenderlo es experimentar. El método que dibuja líneas cardinales se llama DrawCurve. El dibujo muestra el resultado del siguiente código:

 

Dim Puntos() As Point = {New Point(100, 100), New Point(400, 400), New Point(450, 130), New Point(650, 200)}

Dim tensión As Single 'tensión

For tensión = 0 To 2 Step 0.5

    Lienzo.DrawCurve(New Pen(Color.Magenta, 2), Puntos, tensión)

Next

 

Según el valor de la tensión se acerca 2, la línea se va curvando más.

 

 


Índice del curso GDI+
 

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