Eine erste, offensichtliche Möglichkeit verwendet
die Geradengleichung
y = s · x + c :
Der resultierende Fehler pro Position (Abweichung des errechneten Punktes von der Ideal-Linie) wird in Abbildung 3.4 ersichtlich.
Unter Verwendung einer Klasse Point mit den Integer-Koordinaten x und y entsteht:
void plot_line(Point P, Point q) { double s, c; Point p = new Point(P); s = (double) (q.y-p.y) / (double) (q.x-p.x); c = (double) (p.y*q.x - q.y*p.x) / (double) (q.x - p.x ); while (p.x <= q.x) { p.y = (int)(s*p.x + c + 0.5); set_pixel(p); p.x++; } } |
Das Verfahren hat zwei Nachteile:
Als Lösung bietet sich der Bresenham-Algorithmus an, der den jeweils nächsten y -Wert aus dem vorherigen berechnet und dabei den momentanen Fehler nachhält.
Zunächst betrachten wir Geraden im 1. Oktanten (d.h. Steigung < 1):
void bresenham_linie_1(Point P, Point q) { int dx, dy; double s, e; Point p = new Point(P); dx = q.x - p.x; dy = q.y - p.y; e = 0.0; s = (double) dy / (double) dx; while (p.x <= q.x) { set_pixel(p); p.x++; e += s; if (e > 0.5) { p.y++; e-- ; } } } |
Eliminiere Gleitkommazahlen durch Multiplikation von s mit 2*dx:
void bresenham_linie_2(Point P, Point q) { int dx, dy, error, delta; Point p = new Point(P); dx = q.x - p.x; dy = q.y - p.y; error = 0; delta = 2*dy; while (p.x <= q.x) { set_pixel(p); p.x++; error += delta; if (error > dx) { p.y++; error -= 2*dx; } } } |
Vergleiche error mit 0 und verwende Abkürzung schwelle für -2*dx:
void bresenham_linie_3(Point P, Point q) { int dx, dy, error, delta, schwelle; Point p = new Point(P); dx = q.x - p.x; dy = q.y - p.y; error = -dx; delta = 2*dy; schwelle = -2*dx; while (p.x <= q.x) { set_pixel(p); p.x++; error += delta; if (error > 0) { p.y++; error += schwelle; } } } |
Geraden in den anderen 7 Oktanten müssen durch Spiegelung und/oder Vertauschen von x und y auf den 1. Oktanten zurückgeführt werden (siehe folgendes Listing).
/*************************************************************************************/ /* */ /* Bresenham-Algorithmus zum Zeichnen einer Linie */ /* */ /*************************************************************************************/ void bresenham_linie(Point P, Point q) // zeichnet Linie von P nach q { Point p = new Point(P); int error, delta, schwelle, dx, dy, inc_x, inc_y; dx = q.x - p.x; dy = q.y - p.y; if (dx>0) inc_x= 1; else inc_x=-1; if (dy>0) inc_y= 1; else inc_y=-1; if (Math.abs(dy) < Math.abs(dx)) { // flach nach oben oder flach nach unten error = -Math.abs(dx); delta = 2*Math.abs(dy); schwelle = 2*error; while (p.x != q.x) { set_pixel(p); p.x+=inc_x; error = error + delta; if (error >0) { p.y+=inc_y; error = error + schwelle;} } } else // steil nach oben oder steil nach unten { error = -Math.abs(dy); delta = 2*Math.abs(dx); schwelle = 2*error; while (p.y != q.y) { set_pixel(p); p.y+=inc_y; error = error + delta; if (error >0) { p.x+=inc_x; error = error + schwelle;} } } set_pixel(q); } |