Como você desenha uma linha reta entre dois pontos em um bitmap?

17

Estou brincando com mapas de altura (bitmaps), tentando criar alguns dos meus no meu jogo, e para isso preciso implementar alguns métodos básicos de desenho. Eu rapidamente percebi que desenhar linhas retas não é tão básico quanto eu pensava.

É simples se seus pontos compartilham uma coordenada X ou Y ou se estão alinhados para que você possa desenhar uma linha perfeitamente diagonal. Mas em todos os outros casos é mais complicado.

Qual algoritmo você usa para determinar quais pixels precisam ser coloridos para se tornar uma linha "reta"?

Fredrik Boston Westman
fonte

Respostas:

25

Eu acho que o que você precisa é o algoritmo de linha de Bresenham .

Pelo que me lembro, é usado para determinar qual ponto deve ser colorido, e não quanto cada ponto deve ser colorido.

Vaillancourt
fonte
21

O algoritmo de linha de Bresenham pode ser usado para determinar quais pontos em uma grade raster devem ser plotados para obter uma aproximação visual apropriada de um segmento de linha.

O algoritmo abrange a rasterização de uma linha definida pela origem e pontos finais em um espaço de coordenadas em que a origem está no canto superior esquerdo. Presume-se que as coordenadas inteiras mapeiam para os centros de pixel. Notavelmente, a forma básica do algoritmo cobre apenas um octante do círculo: aquele em que a linha tem coordenadas X e Y crescentes, mas uma inclinação negativa com um valor absoluto menor que 1. Todos os outros octantes podem ser derivados como simples transformações desse círculo. octante básico.

No psuedocode, este formulário básico se parece com:

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
        }
    }
}

O site do Código Rosetta tem uma coleção de implementações concretas em uma variedade de idiomas .

Você também pode estar interessado no algoritmo de linha de Wu , que permite anti-aliasing.

Ken Williams
fonte
3
Só quero avisar os transeuntes para não tirar o pseudocódigo incluído do contexto, pois ele não funcionará imediatamente. Funciona apenas para um octante específico (leia o restante da resposta). Se você estiver procurando por código para copiar / colar, tente o link para o site do Código Rosetta.
precisa saber é o seguinte
1
Para quem quiser conferir a versão c do algoritmo de linha de Wu, gostaria de avisar que está incompleta. No _dla_changebrightness quando você alterar o brilho que você precisa para alterá-lo a partir de: to->red = br * (float)from->red;a este a seguir: to->red = (br * (float)from->red) + ((1-br) * (float) to->red);. Faça o mesmo para respectivly verde e azul
Fredrik Boston Westman
2

Aqui está uma maneira extremamente simples de desenhar linhas. A função pode ser facilmente alterada para ser usada em projetos.

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
fonte