19 Funciones para el trazado de líneas

El GDI dispone de un repertorio de funciones para el trazado de líneas bastante completo

Función Tipo de línea
MoveToEx Actualiza la posición actual del cursor gráfico, opcionalmente obtiene la posición anterior.
LineTo Traza una línea desde la posición actual del cursor al punto indicado.
ArcTo Traza un arco de elipse.
PolylineTo Traza uno o más trazos de líneas rectas.
PolyBezierTo Traza una o más curvas Bézier.
AngleArc Traza un segmento de arco de circunferencia.
Arc Traza un arco de elipse.
Polyline Traza una serie de segmentos de recta que conectan los puntos de un array.
PolyBezier Traza una o más curvas Bézier.
GetArcDirection Devuelve la dirección de arco del DC actual.
SetArcDirection Cambia la dirección del ángulo para el trazado de arcos y rectángulos.
LineDDA Traza una línea, pero permite a una función de usuario decidir qué pixels se mostrarán.
LineDDAProc Función callback de la aplicación que procesa las coordenadas recibidas de LineDDA.
PolyDraw Traza una o varias series de líneas y curvas Bézier.
PolyPolyLine Traza una o varias series de segmentos de recta conectados.

La mayoría de éstas funciones no requieren mayor explicación, sobre todo las que trazan arcos y líneas rectas.

Trazado de arcos, función Arc

Para trazar un arco mediante la función Arc, se parte de una circunferencia inscrita en el rectángulo de borde. Los puntos de inicio y final del arco se obtienen de los cortes de los radios definidos por los puntos de radio de inicio y final:

Arc
Arc

La función ArcTo es idéntica, salvo que se traza una línea desde la posición actual del cursor gráfico hasta el punto de inicio del arco.

Curvas Bézier

Las curvas Bézier son una forma de definir curvas irregulares mediante métodos matemáticos. Para definir una curva Bézier sólo se necesitan cuatro puntos: los puntos de inicio y final, y dos puntos de control.

En el gráfico se representa una curva Bézier y las líneas auxiliares, que sólo se muestran como ayuda. El punto de inicio y el punto de control 1 refinen una recta que es tangente a la curva en el punto de inicio. La curva tiende a aproximarse al punto de control 1.

Análogamente, el punto de final y el punto de control 2 refinen otra recta, que es tangente a la curva en el punto de final. La curva también tiende a acercarse al punto de control 2.

Las ecuaciones que definen la curva no son demasiado complejas, pero escapan al objetivo de este curso, se estudiaran las curvas de Bézier con detalle en un artículo separado.

Bezier
Bezier

Funciones Poly<tipo>

Todas las funciones con el prefijo Poly trabajan de un modo parecido. Se basan en un array de puntos para definir un conjunto de líneas que se trazan una a continuación de otra.

Polyline o PolylineTo trazan un conjunto de segmentos rectos, PolyBezier y PolyBezierTo, un conjunto de curvas Bézier. PolyDraw, varios conjuntos de líneas y curvas Bézier, y PolyPolyline, varios conjuntos de líneas rectas.

Función LineDDA y funciones callback LineDDAProc

LineDDA nos permite personalizar el trazado de segmentos de líneas rectas. Mediante la definición de funciones propias del tipo LineDDAProc, podemos procesar cada punto de la línea y decidir cómo visualizarlo. Podemos cambiar el color, ignorar ciertos puntos, y en general, aplicar la modificación que queramos. Esto nos permite trazar líneas de varios colores o con distintas tramas, etc.

Veamos un ejemplo sencillo, definiremos una función LineDDAProc para trazar líneas que alternen 10 pixels rojos y 10 verdes.

struct DatosDDA1 {
   int cuenta;
   HDC hdc;
};

VOID CALLBACK FuncionDDA1(int X, int Y, LPARAM datos)
{
   struct DatosDDA1 *dato = (struct DatosDDA1 *)datos;

   // Función que pinta líneas con 10 pixels alternados rojos y verdes
   dato->cuenta++;
   if(dato->cuenta >= 20) dato->cuenta = 0; // Mantenemos cuenta entre 0 y 19
   if(dato->cuenta < 10)
     SetPixel(dato->hdc, X, Y, RGB(0,255,0));
   else
     SetPixel(dato->hdc, X, Y, RGB(255,0,0));
}

Hemos definido una función callback para que muestre cada punto en función de los datos almacenados en una estructura DatosDDA1, diseñada por nosotros. En ella almacenamos un valor "cuenta" que nos ayuda a decidir el color de cada pixel, y un manipulador de DC para poder activar pixels, usando SetPixel, en la ventana:

...
   struct DatosDDA1 datos = {0, hDC};

   LineDDA(10,10, 240,180, FuncionDDA1, (LPARAM)&datos);
...

Ahora podemos llamar a la función LineDDA, indicando los puntos de inicio y final de la línea, la función que usaremos para decidir el color de cada punto, y un puntero a la estructura de datos que esa función necesita.

Línea trazada con LineDDA
Línea trazada con LineDDA

Ejemplo 17

Basándonos en el último programa de ejemplo, vamos a hacer otro que muestre cada una de éstas funciones y cómo se usan.

Añadiremos un menú para poder ver cada función por separado.

Nota:

Algunas de las funciones del API usadas en el ejemplo no están disponibles en Windows 95 y Win32s, por ejemplo: PolyDraw, ArcTo y AngleArc. Esto no impide que el programa se pueda compilar y ejecutar, pero algunas funciones no funcionarán.

Nombre Fichero Fecha Tamaño Contador Descarga
Ejemplo 17 win017.zip 2004-01-18 3532 bytes 635