¿Cómo se dibuja una línea recta entre dos puntos en un mapa de bits?

17

Estoy jugando con mapas de altura (mapas de bits), tratando de crear algunos propios en mi juego, y para eso necesito implementar algunos métodos básicos de dibujo. Rápidamente me di cuenta de que dibujar líneas rectas no es tan básico como pensaba.

Es simple si sus puntos comparten una coordenada X o Y, o si están alineados para que pueda dibujar una línea perfectamente diagonal. Pero en todos los demás casos es más complicado.

¿Qué algoritmo utiliza para determinar qué píxeles deben colorearse para que se convierta en una línea "recta"?

Fredrik Boston Westman
fuente

Respuestas:

21

El algoritmo de línea de Bresenham se puede usar para determinar qué puntos de una cuadrícula de trama se deben trazar para lograr una aproximación visual adecuada de un segmento de línea.

El algoritmo cubre la rasterización de una línea definida por el origen y los puntos finales en un espacio de coordenadas donde el origen está en la esquina superior izquierda. Se presume que las coordenadas enteras se asignan a centros de píxeles. Notablemente, la forma básica del algoritmo solo cubre un octavo del círculo: aquel en el que la línea tiene coordenadas X e Y crecientes pero una pendiente negativa con un valor absoluto menor que 1. Todos los demás octantes pueden derivarse como simples transformaciones de este octante básico

En psuedocode, este formulario básico se ve así:

void DrawLine(Point origin, Point endpoint, Bitmap surface) {
    deltaX = endpoint.X - origin.X
    deltaY = endpoint.Y - origin.Y
    error = 0

    // Note the below fails for completely vertical lines.
    deltaError = absoluteValue(deltaY / deltaX)

    Y = origin.Y
    for (X from origin.X to endpoint.X) {
        surface.PlotPixel(X, Y)
        error = error + deltaError 
        if (error >= 0.5) {
            ++Y;
            error -= 1.0
        }
    }
}

El sitio web de Rosetta Code tiene una colección de implementaciones concretas en una variedad de idiomas .

También te puede interesar el algoritmo de línea de Wu , que permite el suavizado.

Ken Williams
fuente
3
Solo quiero advertir a los transeúntes que no saquen el pseudocódigo incluido fuera de contexto, ya que no funcionará de la caja. Solo funciona para un octante específico (lea el resto de la respuesta). Si está buscando código para copiar / pegar, pruebe el enlace al sitio web de Rosetta Code.
congusbongus
1
Para cualquiera que quiera ver la versión c del algoritmo de línea de Wu, me gustaría advertirle que está incompleto. En el _dla_changebrightness cuando cambia el brillo que necesita para cambiarlo de: to->red = br * (float)from->red;a este siguiente: to->red = (br * (float)from->red) + ((1-br) * (float) to->red);. Haga lo mismo para el verde y el azul respetuosamente
Fredrik Boston Westman
2

Aquí hay una forma extremadamente simple de dibujar líneas. La función se puede cambiar fácilmente para ser utilizada en proyectos.

void draw_line(float x0, float y0, const float& x1, const float& y1)
{
    float x{x1 - x0}, y{y1 - y0};
    const float max{std::max(std::fabs(x), std::fabs(y))};
    x /= max; y /= max;
    for (float n{0}; n < max; ++n)
    {
        // draw pixel at ( x0, y0 )
        x0 += x; y0 += y;
    }
}
cppxor2arr
fuente