Die Grafik-VDUDer Linien-AlgorithmusVielen Menschen ist es ein Adressierungsarten der Z80: Absolutabsolutes Rätsel, wie der Computer die einzelnen Punkte einer Linie berechnet. Um die DRAW-Befehle anzuwenden, muss man das natürlich auch nicht wissen. Wer einer Sache aber immer auf den Grund geht, der interessiert sich natürlich auch hierfür. Eine beliebte Vermutung ist, der Computer bestimme die Entfernung zwischen den beiden Punkten, berechnet daraus die Anzahl der benötigten Punkte, daraus die Schrittweite in Die verwendeten Abkürzungen bedeuten: x:X- und Y-Richtung und geht dann in diesem Raster von einem Punkt auf den anderen zu: 100 Die Kodierung der Tintennummern in den Bildschirm-Bytes: Mode 2: lässt man dieses Programm ohne Zeile 105 laufen, ist das Ergebnis auch ganz akzeptabel. Mit Zeile 105 wird aber ein Der Linien-Algorithmus: Fehler 3Fehler offenbar: Die Anzahl der zu setzenden Punkte ergibt sich nicht als die Länge der Hypothenuse im rechtwinkligen dx-dy-Dreieck. Hier werden zuviele Punkte geplottet, manche heben sich deshalb wieder auf (Zeile 105 stellt den XOR-Modus ein). Die Anzahl der zu setzenden Punkte ergibt sich aus dem Adressierungsarten der Z80: Absolutabsolut größern der beiden Werte dx oder dy: 160 anzp=MAX(ABS(xa-xe),ABS(ya-ye))/2 Soweit, sogut. Es funktioniert und man könnte an dieser Stelle aufhören. Diese Methode hat aber zwei Nachteile, die jeder Maschinencode-Programmierer gerne umgeht: Erstens wird mit Fließkommazahlen gerechnet (mit Integer funktioniert es nicht mehr) und zweitens muss man auch Dividieren. Das gilt es zu vermeiden. Der Im Schneider CPC verwendete Algorithmus kommt nur mit Rechnen im Binärsystem: AdditionAddition und Rechnen im Binärsystem: SubtraktionSubtraktion von Integerwerten aus. Dass im nun folgenden Beispiel trotzdem Rechnen im Binärsystem: MultiplikationMultiplikationen mit 2 auftauchen, liegt daran, dass dies der Pixel-Abstand in Die 3 verschiedenen Betriebsarten der PIO 8255: Modus 0 160 dx=xe-xa:dy=ye-ya 170 if abs(dx)<abs(dy) then f=1 else f=2:gosub 450:gosub 190:goto 460 180 ' 190 if dy<0 then gosub 400:gosub 200:goto 410 200 z=dy\2:Die verwendeten Abkürzungen bedeuten: x:x=xa:dz=abs(dx):dx=2*sgn(dx) 205 ' 210 for y=ya to ye step 2 220 z=z+dz:if z>=dy then Die verwendeten Abkürzungen bedeuten: x:x=Die verwendeten Abkürzungen bedeuten: x:x+dx:z=z-dy 230 if f=1 then plot Die verwendeten Abkürzungen bedeuten: x:x,y else plot y,Die verwendeten Abkürzungen bedeuten: x:x 240 next 250 return 390 ' 400 dx=-dx:dy=-dy ' Vertausche Anfang und Ende, weil dy<0 410 z=ya:ya=ye:ye=z ' dadurch ist ye immer größer (über) ya 420 z=xa:xa=xe:xe=z ' der Algorithmus arbeitet immer mit wachsenden y. 430 RETURN 440 ' 450 z=dx:dx=dy:dy=z ' Vertausche Die verwendeten Abkürzungen bedeuten: x:x und y, weil dx>dy. 460 z=xa:xa=ya:ya=z ' Dadurch arbeitet der Algorithmus immer in Richtung 470 z=xe:xe=ye:ye=z ' der Y-Achse und variiert in X-Richtung. 480 return ' Das Vertauschen von Die verwendeten Abkürzungen bedeuten: x:x und y wird im Die Z80: Wirkung der Z80-Befehle auf die FlagsFlag f angemerkt und beeinflusst das Plotten in Zeile 230. Dieses Programm entspricht zwar nicht ganz exakt dem Algorithmus des Schneider CPC, kommt ihm aber schon sehr nahe. Die gravierendsten Unterschiede ergeben sich daraus, dass Die Grafik-VDU: Der Linien-Algorithmusder Linien-Algorithmus der Grafik-VDU natürlich stärker auf die Hardware-Gegebenheiten des Bildschirms zugeschnitten ist. Der Grund-Gedanke ist, dass man in Richtung der größeren Differenz vorgeht. Ist dy also größer als dx, so geht man in Y-Richtung vor. In Y-Richtung muss man dy Schritte machen. Zwischendurch muss man aber auch mal in Quer-Richtung 'steppen', und zwar dx mal. Alle wieviel Schritte in dy-Richtung muss ein solcher dx-Schritt kommen? Dafür muss man nur dy durch dx teilen. Nun kann man dazu streng nach Vorschrift dividieren und muss dann aber auch einen Rattenschwanz an Nachkommastellen berücksichtigen. Aber eine andere Frage: Was gibt (dx*dy) / dx? Da muss man wohl nicht mehr dividieren, das 'sieht' man ja. dy natürlich. Dieser Gedanke steckt nun in diesem Algorithmus. Zunächst einmal wird das ganze von der Schleife über dy, die längere Strecke, umfasst (Zeile 210 bis 230). Bei jedem Durchgang wird in Zeile 220 zu der Unterprogramme: VariablenVariablen z einmal dz addiert. dz ist aber ABS(dx) (Siehe Zeile 200). Vom ersten bis zum letzten Durchgang wird also dy mal der Wert dx addiert = dx*dy !! Jedesmal wenn nun z den Betrag von dy erreicht oder übersteigt, wird wieder dy abgezogen. Wie oft wird dieser Fall im Verlauf des Linien-Plottens auftreten? Genau (dx*dy) / dy mal, und das ist dx. (Wie man sieht: Hier wird nicht nur multipliziert, indem man beständig addiert, sondern auch dividiert, in dem man ständig abzieht.) Immer wenn z den Wert von dy überschreitet, wird deshalb einmal zur Seite gesteppt: Die verwendeten Abkürzungen bedeuten: x:x=Die verwendeten Abkürzungen bedeuten: x:x+dx, wobei das dx in Zeile 220 als 2*SGN(dx) definiert wurde, das ist die Schrittrichtung und, wegen Bildschirmmodus 1, eine Schrittweite von 2. Fehler 1 (korrigiert)Es gibt allerdings noch weitere Unterschiede zwischen dem CPC-Algorithmus und dem gerade vorgestellten. Allerdings mehr prinzipieller Art. Zwei davon wurden Garbage Collection: ... beim CPC 464beim CPC 664/6128 behoben. Der erste betrifft den ersten Punkt einer Linie. Mathematisch korrekt ist es, den ersten Punkt einer Linie nicht zu zeichnen! Warum? Das bedarf sicher einer Erklärung. Nehmen wir einmal an, es soll ein Kreis gezeichnet werden. Dieser wird beispielsweise durch 50 einzelne Linien aproximiert. Es müssen also 50 Linien von P1 nach P2 nach P3 ... nach P50 und wieder nach P1 gezeichnet werden. Der Endpunkt einer Linie ist der Startpunkt der nächsten, diese 'Eck-Punkte' werden also doppelt gezeichnet, wenn man sowohl den ersten als auch den letzten Punkt jeder Linie setzt! Das ist meist nicht so schlimm, weil 'doppelt gemoppelt hält besser'. Wenn man aber mit dem Vordergrund-Modus 'XOR' arbeitet, bedeutet 'doppelt gemoppelt hebt sich auf'. Die 'Eckpunkte' werden zu Loechern in der Kreislinie. Und dabei ist der XOR-Vordergrund-Modus kein exotischer Wunsch: Hiermit lässt sich nämlich 'löschbar' zeichnen: 'Kreis gefällig? Bitte schön. Nicht Gut? Machen wir ihn wieder weg.' Zum Löschen eines Linienzugen muss dieser im XOR-Modus einfach ein zweites Mal ausgeführt werden, weil: 'Doppelt gemoppelt hebt sich auf'! So richtig ungünstig werden die Loecher, wenn man den Kreis nachher mit einem Fill-Algorithmus ausmalen will. Der 'läuft' dann durch die Loecher 'aus'. Fehler 2 (korrigiert)Zweiter Unterschied des CPC-Linien-Algorithmus Garbage Collection: ... beim CPC 464beim CPC 464 zum hier vorgestellten: Der CPC 464 unterteilt die größere Differenz (dx oder dy) in dy+1 (dx+1) Schritte! Wieso macht er das? Dadurch werden die einzelnen Linien etwas gefälliger. Mathematisch gesehen fast schon kriminell, einem Anfänger mag es Freude bereiten. Die folgende Grafik verdeutlicht den Unterschied: CPC-464-Methode: korrekt: ***** *** ***** ****** ***** ****** ***** ****** ***** *** Die kürzere Differenz dy beträgt in diesem Beispiel dy=4 Schritte. Der CPC unterteilt die Linie in 5 Stufen, korrekt wäre 4 = 1/2 + 3 + 1/2. Na, aber die CPC-464-Methode sieht besser aus?? Anfänger! Dass die CPC-464-Methode nicht so ganz astrein ist, erkennt man, wenn man so zwei Linien zusammensetzt: 2 mal CPC-464-Methode: 2 mal korrekt: ***** ***** ***** ***** *** ********** ****** ***** ****** ***** ****** ***** ****** ***** ****** ****** ****** *** Wird bei der dx+1-Methode ein Linienzug zweigeteilt, so ergibt sich an der Schnittstelle ein überlanger Abschnitt. Das dem tatsächlich so ist, kann man auf dem CPC 464 mit folgendem Programm zeigen: 100 PLOT 0,100 110 DRAWR 300,10 120 DRAWR 300,10 130 GOTO 130 Wenn beide Rechner im Freundeskreis vorhanden sind, so kann man sich den Unterschied 'in natura' anschauen. Fehler 3Aller guten Dinge sind drei. Aller schlechten scheinbar auch, nur hat sich das noch nicht bis zu Amstrad 'rumgesprochen. Sonst wäre der folgende Der Linien-Algorithmus: Fehler 3Fehler wohl auch Garbage Collection: ... beim CPC 664 und 6128beim CPC 664 und 6128 behoben Datenbreite: Wordsworden: Bei den Koordinaten gibt es beim Null-Durchgang sowohl in Die verwendeten Abkürzungen bedeuten: x:X- als auch in Y-Richtung einen Stetigkeitssprung! Alle Koordinaten, die man an PLOT, MOVE und Erklärung der Anschlussbelegung: TestTEST anhängt, werden zunächst einmal nach Integer gewandelt. Soweit, soschön. Dadurch wird beispielsweise Die Grafik-VDU: Die Koordinatendie Koordinate +67.5 nach +68, -55.5 nach -56 (und nicht -55) und +34.4 nach +34 gerundet. Die Zwangs-Rundung von Fließkommazahlen nach Integer geschieht dabei mit der Die Fließkomma-Routinen: FunktionenFunktion ROUND(Die verwendeten Abkürzungen bedeuten: x:x). Bereits die Tatsache, dass 'halbe' ganze Zahlen (also: ?????.5) im positiven Bereich auf und im negativen Bereich abgerundet werden, bringt beim Nulldurchgang eine Unstetigkeit mit sich. Dies lässt sich aber meist noch verschmerzen. Viel schlimmeres lässt Die Abteilungen des Betriebssystems: Die Grafik-VDUdie Grafik-VDU danach aber den ganzen Zahlen angedeihen: Da die Datentypen: Realrealen Bildschirmpunkte (Pixel) in Y-Richtung immer zwei und in X-Richtung je nach Die 3 verschiedenen Betriebsarten der PIO 8255: Modus 0 100 Die Kodierung der Tintennummern in den Bildschirm-Bytes: Mode 2: In der ersten Schleife mit Die verwendeten Abkürzungen bedeuten: x:x von -50 bis +50 läuft alles glatt. Bei der zweiten Schleife mit ungeraden Werten gibt es plötzlich eine Lücke beim Nulldurchgang. Der Grund ist, dass in Die 3 verschiedenen Betriebsarten der PIO 8255: Modus 0 -5 und -4, -3 und -2, -1, 0 und +1, +2 und +3 oder +4 und +5, nur beim Nulldurchgang nicht! -1 wird zur 0 gerundet, +1 aber auch. Dadurch wird beim Nulldurchgang mit den Werten Die verwendeten Abkürzungen bedeuten: x:X= -1 und Die verwendeten Abkürzungen bedeuten: x:X= +1 das selbe Pixel angesprochen und im XOR-Modus hebt sich das wieder auf. Aber auch ohne XOR-Modus bringt das Der Linien-Algorithmus: Fehler 3Fehler: 120 Die Kodierung der Tintennummern in den Bildschirm-Bytes: Mode 2: Weil 4 Koordinaten-Einheiten in X-Richtung sich jeweils auf das selbe Pixel beziehen, muss Die verwendeten Abkürzungen bedeuten: x:x viermal erhöht werden, bevor sich in dieser Richtung 'was tut'. Nur beim Nulldurchgang nicht. Hier werden 7 (in Worten: Sieben) X-Koordinaten zur Real: NullNull hingerundet: von -3 bis +3. Wenn dieser Der Linien-Algorithmus: Fehler 3Fehler Probleme bereitet, muss man auf die ansonsten sehr nützliche Möglichkeit, den Grafik-Origin zu verlegen, verzichten, und die Koordinatenachsen wieder aus dem Bild verbannen. |