Wir werden zunächst den Fall diskutieren, bei dem die Steigung in
liegt und später verallgemeinern.
Wie oben erwähnt, weicht die gezeichnete Linie für gewöhnlich von der idealen Linie ab:
Die Größe dieser Abweichung läßt sich ausnutzen, um zu entscheiden, ob
man für die nächste
-Koordinate die aktuelle
-Koordinate
beibehalten kann oder ob man die
-Koordinate um
erhöhen muß.
Diese Art der Implementation ist aus dem Jahr 1965 und stammt von Jack
Bresenham. Der Algorithmus berechnet
den jeweils
nächsten
-Wert aus dem vorherigen und hält dabei
den momentanen Fehler nach.
public void drawBresenhamLine1(CGCanvas cgc) {
int x, y, dx, dy;
double s, error;
dy = y2 - y1; // Hoehenzuwachs berechnen
dx = x2 - x1; // Schrittweite
x = x1; // Koordinaten retten
y = y1;
error = 0.0; // momentaner Fehler
s = (double) dy / (double) dx; // Steigung
while (x <= x2) { // fuer jede x-Koordinate
cgc.setPixel(x, y); // setze Pixel
x++; // naechste x-Koordinate
error += s; // Fehler aktualisieren
if (error > 0.5) { // naechste Zeile erreicht?
y++; // neue y-Koordinate
error-- ; // Fehler anpassen
}
}
}
|
Man kann die verbleibende Gleitkommaarithmetik vermeiden, indem man zur
Fehlerbestimmung und zur Entscheidung, ob die
-Koordinate angepasst
werden muß, eine zweite (wesentlich steilere) Gerade verwendet. Die
Steigung dieser neuen Geraden berechnet sich folgendermaßen:
Für ein ganzzahliges
würde bereits die Multiplikation mit
genügen. Da wir aber auch den Fahler ganzzahlig machen wollen, müssen wir
zusätzlich mit
multiplizieren:
public void drawBresenhamLine2(CGCanvas cgc) {
int x, y, dx, dy, error, delta;
dy = y2 - y1; // Hoehenzuwachs berechnen
dx = x2 - x1; // Schrittweite
x = x1; // Koordinaten retten
y = y1;
error = 0; // momentaner Fehler
delta = 2*dy; // 'Steigung'
while (x <= x2) { // fuer jede x-Koordinate
cgc.setPixel(x, y); // setze Pixel
x++; // naechste x-Koordinate
error += delta; // Fehler aktualisieren
if (error > dx) { // naechste Zeile erreicht?
y++; // neue y-Koordinate
error -= 2*dx; // Fehler anpassen
}
}
}
|
Um nochmals etwas Zeit zu sparen, vergleichen wir error mit 0 und verwenden die Abkürzung schritt für -2*dx:
public void drawBresenhamLine3(CGCanvas cgc) {
int x, y, dx, dy, error, delta, schritt;
dy = y2 - y1; // Hoehenzuwachs berechnen
dx = x2 - x1; // Schrittweite
x = x1; // Koordinaten retten
y = y1;
error = -dx; // momentaner Fehler
delta = 2*dy; // 'Steigung'
schritt = -2*dx; // Fehlerschrittweite
while (x <= x2) { // fuer jede x-Koordinate
cgc.setPixel(x, y); // setze Pixel
x++; // naechste x-Koordinate
error += delta; // Fehler aktualisieren
if (error > 0) { // naechste Zeile erreicht?
y++; // neue y-Koordinate
error += schritt; // Fehler anpassen
}
}
}
|
Geraden in den anderen 7 Oktanten (Steigung
)
müssen durch Spiegelung und/oder
Vertauschen von
und
auf den 1. Oktanten zurückgeführt werden:
Bresenham-Algorithmus für Linien