Come si disegna una linea retta tra due punti in una bitmap?


17

Sto giocando con le mappe di altezza (bitmap), provando a crearne alcune nel mio gioco e per questo ho bisogno di implementare alcuni metodi di disegno di base. Mi sono presto reso conto che disegnare linee rette non è così semplice come pensavo.

È semplice se i tuoi punti condividono una coordinata X o Y o se sono allineati in modo da poter tracciare una linea perfettamente diagonale. Ma in tutti gli altri casi è più complicato.

Quale algoritmo usi per determinare quali pixel devono essere colorati affinché diventi una linea "dritta"?

Risposte:



21

L'algoritmo di linea di Bresenham può essere utilizzato per determinare quali punti in una griglia raster tracciare al fine di ottenere un'approssimazione visiva appropriata di un segmento di linea.

L'algoritmo copre la rasterizzazione di una linea definita dall'origine e dai punti finali in uno spazio di coordinate in cui l'origine è in alto a sinistra. Si presume che le coordinate intere si associno ai pixel centre. In particolare, la forma di base dell'algoritmo copre solo un ottante del cerchio: quello in cui la linea ha coordinate X e Y crescenti ma una pendenza negativa con un valore assoluto inferiore a 1. Tutti gli altri ottanti possono essere derivati ​​come semplici trasformazioni di questo ottante di base.

In psuedocode, questa forma di base appare come:

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

Il sito Web del codice Rosetta ha una raccolta di implementazioni concrete in una varietà di lingue .

Potresti anche essere interessato all'algoritmo di linea di Wu , che consente l'antialiasing.


3
Voglio solo avvertire i passanti di non togliere lo pseudocodice incluso dal contesto, poiché non funzionerà immediatamente. Funziona solo per un ottante specifico (leggi il resto della risposta). Se stai cercando il codice da copiare / incollare, prova il link al sito Web del codice Rosetta.
congusbongus,

1
Per chiunque volesse dare un'occhiata alla versione c dell'algoritmo di linea di Wu, vorrei avvertirvi che è incompleta. Nella _dla_changebrightness quando si cambia la luminosità è necessario cambiare da: to->red = br * (float)from->red;a questo segue: to->red = (br * (float)from->red) + ((1-br) * (float) to->red);. Fai lo stesso per il verde e il blu rispettosamente
Fredrik Boston Westman,

2

Ecco un modo estremamente semplice per disegnare linee. La funzione può essere facilmente modificata per essere utilizzata nei progetti.

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;
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.