DIN A4-Funktionsplotter

Programme zur Darstellung dreidimensionaler Funktionen gibt es in grober Menge - aber nur die wenigsten arbeiten mit einer Auflösung von 2000*1440 Punkte. Das im folgenden besprochen Programm hat nicht nur diese Eigenschaft, es vermittelt zudem eine plastische Vorstellung der darzustellenden Funktion durch die Berücksichtigung der Helligkeitsverteilung auf der Oberfläche infolge einer (fiktiven) Lichtquelle.

Das Programm arbeitet im hochauflösenden Modus des Atari ST und ermöglicht die Ausgabe der dreidimensionalen Grafik im DIN A4 Format am NEC P6 (und ähnlichen 24 Nadel-Druckern). Bei der Besprechung des Programmes wird zuerst auf die dreidimensionale Darstellung einer gegebenen Funktion am Bildschirm eingegangen. Anschließend wird gezeigt, wie diese Grafik in hoher Auflösung relativ einfach gedruckt werden kann.

Überblick

Um die Funktion zu zeichnen, wird sie in zahllose kleine Dreiecke zerlegt. Zu jedem Punkt dieser Dreiecke wird aus den X- und Y-Koordinaten mit der darzustellenden mathematischen Funktion die dazugehörige Z-Koordinate berechnet. Jeweils 3 solche Koordinatenpunkte bilden ein kleines Dreieck.

Damit die Funktion in richtiger Sichtbarkeit dargestellt wird, werden die Dreiecke Zeile um Zeile von hinten beginnend gezeichnet - wenn die Fläche wegen einer Wölbung weiter hinten befindliche Teile verdeckt, dann werden diese ohne aufwendige Untersuchung einfach durch die neuen Dreiecke überdeckt und so unsichtbar. Um darüber hinaus einen plastischen Eindruck der Ebene zu vermitteln, wird der Einfallswinkel von Lichtstrahlen auf die Fläche in Form von Grauschattierungen der Dreiecke berücksichtigt.

Die Details

Im Programm werden zu Beginn einige Variablen mit Startwerten belegt: die Bedeutung von SCALE und LINIEN-STAERKE wird etwas weiter unten besprochen. BASE bestimmt die Größe eines Dreiecks - je kleiner dieser Wert gewählt wird, desto genauer wird die Darstellung, desto länger die Rechenzeit und desto größer der Speicherbedarf. Der Beleuchtungsvektor gibt die Richtung an, unter der eine Lichtquelle in unendlich großer Entfernung (damit fallen die Lichtstrahlen parallel ein) Licht aussendet. Dieser Vektor wird durch seine Länge dividiert, sodaß sich (ohne Veränderung der Richtung) seine Länge auf 1 reduziert - dies ist zur Berechnung der Helligkeit am günstigsten.

Sodann wird der Bereich für X- und Y-Koordinaten festgelegt, in dem die Ebene dargestellt wird. Die Werte sind hier so gewählt, daß das letzte (rechte) Achtel des Bildschirms nicht genutzt wird - der Grund dafür liegt im gebräuchlichen Papier-Format, das nicht ganz den Proportionen des Bildschirms entspricht. Nach einigen Feld-Dimensionierungen wird das Unterprogramm GRAUTON aufgerufen: darin werden aus DATA-Zeilen insgesamt 32 Grau-Schattierungen in ein String-Feld gelesen, wobei der Aufbau der Zeichenketten dergestalt ist, daß sie zur Definition eines eigenen Füllmusters mit DEFFILL verwendet werden können. Die Schattierungen werden durch die Besetzung von einer zunehmenden Anzahl von Punkten in einer 8*8 Matriz erzeugt. Diese Schattierungsmuster ermöglichen einen kontinuierlichen Farb-Übergang zwischen Weiß und Schwarz.

Es folgen nun recht kompliziert wirkende Funktions-Definitionen: mit ihnen wird aus gegebenen X- und Y-Koordinaten die Z-Koordinate der Funktion berechnet. Dazu verwendet die Hauptfunktion Z() eine Unterfunktion, die den Sinus-Wert einer rechnerischen Kombination der X-und Y-Koordinaten bestimmt. Durch die Überlagerung mehrerer solcher Funktionen durch Addition ergeben sich zahllose Möglichkeiten, interessante Flächen zu bilden. Der Wertebereich einer eigenen Funktions-Definition sollte zwischen +/-35 liegen, damit die Bildschirmgrenzen nicht überschritten werden. Zwei weitere Beispiele für Funktionsdefinitionen (für Abb. 5 und 6):

Deffn Z(X,Y)=Sin((X-250)*(Y-160)/
	2000)*20+Sin((X+Y*2)/30)*8 
Deffn Z(X,Y)=@Ufl(X-250,Y-150)*10+@Uf2(X-200,Y-200)*8 
Deffn Uf1(A,B)=Sin(Sqr(A^2+B^2)/10) 
Deffn Uf2(A,B)=Sin((A+2*B)20)+Sin(Sqr(A^2+B^2)/16)*1.4+Sin(A*B/3000)

Es sollte noch erwähnt werden, daß das verwendete Koordinatensystem ein 'Links-System’ ist (Abb. 1), während in der Mathematik gewöhnlich ein ‘Rechts-System’ verwendet wird, bei dem die Y-Koordinate in die entgegengesetzte Richtung zeigt. Wenn es also von Bedeutung ist, daß die Funktion nicht spiegelverkehrt dargestellt wird, dann muß bei der Funktionsdefinition die Y-Koordinate jeweils mit negativem Vorzeichen verwendet werden.

Bild 1: Das verwendete Koordinatensystem

In zwei einfachen Schleifen werden sodann die Z-Koordinaten zu Punkten in einem quadratischen XY-Raster berechnet und in einem Feld gespeichert (um Rechenzeit zu sparen). Die Subtraktion von 35 gewährleistet, daß die Dreiecks-Flächen nicht über den oberen Bildschirmrand hinausragen. Wie sich aus diesen Koordinatenwerten Dreiecke ergeben, wird in Abb. 2 gezeigt.

Es folgt eine weitere geschachtelte Schleife, in der die Dreiecke zeilenweise am Bildschirm ausgegeben werden. Dabei wird die Helligkeit der einzelnen Flächen mit der HELLIGKEIT-Funktion bestimmt: diese Funktion ermittelt den Cosinus-Wert des Winkels zwischen dem Beleuchtungsvektor und dem Normalvektor auf ein einzelnes Dreieck. Dieser Wert wird durch die Bildung des skalaren Produktes und anschließender Division durch die Länge des Normalvektors gebildet. Der Wert ist ein Maß für die Helligkeit der Fläche [1].

Bild 2: Die Fläche wird durch viele Dreiecke dieser Art angenähert

Jetzt muß nur noch geklärt werden, wie der Normalvektor auf eine Dreiecksfläche gebildet wird. Die Vorgangsweise wird am Beispiel des linken der zwei Dreiecke in Abb.2 demonstriert: es werden dabei die zwei Vektoren zwischen den Punkten mit der Höhe Z1 und Z2 bzw. Z1 und Z3 verwendet, die folgendermaßen aussehen:

		{BASE }				{0    }
vek13=	{0    }		vek12=	{BASE }
		{Z2-Z1} 			{Z2-Z1}

Der Normalvektor, der auch in Abb.2 zu sehen ist(‘Nvec’), ergibt sich durch kreuzweises Multiplizieren der Komponenten dieser Vektoren:

				{ 0-BASE*(Z2-Z1)}			{Z1-Z2}
vek13 x vek12 =	{ 0-BASE*(Z3-Z1)} = BASE *	{Z1-Z3)
				{ BASE*BASE-0   }			{BASE }

Mit diesem Vektor wird die Helligkeitsfunktion aufgerufen, wobei der gemeinsame Faktor BASE nicht berücksichtigt wird. In analoger Weise wird auch die Helligkeit des anderen Dreiecks berechnet. Um die Farbe bei der Ausgabe am Drucker nicht nochmals berechnen zu müssen, wird sie ebenfalls in Feldern gespeichert.

Ein Dreieck zeichnen

... ist gar nicht so einfach: dem Unterprogramm Dreieck werden die dreidimensionalen Koordinaten der drei Eckpunkte übergeben. Daraus werden zweidimensionale Bildschirmkoordinaten berechnet. Zu X wird ein Drittel von Y addiert, damit die Fläche schräg im Raum steht. Außerdem wird Z von Y subtrahiert (weil sonst wegen des Bildschirm-Koordinatensystems positive Z-Werte nach unten gezeichnet würden). Diese Berechnungsweise entspricht im wesentlichen einer etwas vereinfachten Zentral-Projektion. Darüber hinaus werden sämtliche Koordinatenwerte mit SCALE multipliziert. Dieser Faktor ist für die Ausgabe am Bildschirm 1, für die Ausgabe am Drucker wird er später auf 3.6 erhöht.

Es folgt eine nicht ganz leicht verständliche Schleife, in der nach identischen Y-Koordinaten von je zwei Eckpunkten des Dreiecks gesucht wird. Falls solche Punkte existieren, werden die Koordinaten um 1 verkleinert, wenn sie kleiner als der Y-Wert des dritten Punktes sind, andernfalls um 1 vergrößert. Der Grund für diese komplizierte Prozedur liegt in einem Fehler der POLYFILL Routine (TOS von Diskette): dieser Fehler wird nur dann bemerkbar, wenn die Flächen ohne Umrandung gezeichnet werden. Es treten dann gelegentlich weiße Streifen zwischen zwei aneinanderliegenden Flächen auf.

Insgesamt gibt es drei Möglichkeiten, die Flächen zu zeichnen: ohne Rand (LINIENSTAERKE=0), mit dünnem Rand (L=1) und mit etwas dickerem Rand (L=2). Die Abbildungen 4 bis 6 zeigen die sich dadurch ergebenden Grafiken. Gewöhnlich werden die Dreiecke mit einem ihrer Helligkeit entsprechendem Muster angefüllt, es ist aber natürlich auch möglich, alle Flächen einfach weiß anzufüllen - dazu wird die Funktion HELLIGKEIT als konstant 1 definiert:

Deffn Helligkeit (X,Y,Z)=1

Der beste plastische Eindruck ergibt sich, wenn auf eine Umrandung der Flächen verzichtet wird, Details der Gestalt der Fläche werden aber besser sichtbar, wenn die Dreiecke zwar umrandet, aber dafür ohne Graustufen dargestellt werden (besonders bei sehr komplizierten Funktionen ratsam).

Noch kurz einige Worte zur Rechenzeit: sie ist sehr klein, wenn die Funktion nur am Bildschirm (und nicht am Drucker) gezeichnet wird - bei BASE=5 (relativ hohe Auflösung - die Funktion wird durch -12000 Dreiecke angenähert) dauert dieser Vorgang im compilierten Programm keine zwei Minuten.

Die Ausgabe am Drucker

Der einfachste Weg, die bisher erzeugte Grafik zu Papier zu bringen wäre eine direkte Hardcopy; dabei würde aber die Auflösung unverändert bleiben, was ein entscheidender Nachteil ist - der NEC P6 kann auf einer DIN A4 Seite fast 3 Millionen Punkte (in 180 DPI) darstellen - das ist etwa das 12 fache der Auflösung des Atari SW-Monitors. Es wird daher ein Weg gesucht, diese hohe Auflösung möglichst einfach zu nutzen.

Die Funktion wird am Drucker längs ausgedruckt (damit hat der Ausdruck ein ähnliches Format wie der Bildschirm). Sie wird dazu um den Faktor 3.6 vergrößert - damit werden aus 400 vertikalen Punkten am Bildschirm 1440 Punkte horizontal am Drucker, womit die gesamte Breite des Druckers genutzt wird.

Um die Grafik in der hohen Auflösung zeichnen zu können, wird sie in Segmente zerlegt, die am Atari Bildschirm dargestellt werden können. Die Grafik wird in 4 Streifen geteilt, die nacheinander gedruckt werden. Jeder dieser Streifen besteht wiederum aus 4 Segmenten (siehe Abb. 3).

Abbildung 3: auf einem Endlos-Blatt wird schematisch die Aufteilung der hochauflösenden Grafik in Segmente gezeigt

Dieser Zerstückelungs-Vorgang wird vom Unterprogramm NEC_PRINT gesteuert. Die Größe eines Segmentes ist 360 Punkte vertikal (360*4=1440) und 63 Bytes=504 Punkte horizontal (die Byteanzahl muß ein Vielfaches von 3 sein, da beim NEC-Drucker immer 24 Punkte (=3 Byte) zugleich gedruckt werden). Mit 4 Streifen ergeben sich am Drucker vertikal 2016 Punkte - damit wird eine DIN A4 Seite weitgehend gefüllt.

Der Druck eines Streifens erfolgt auf folgende Weise: es werden mit dem Unterprogramm PLOT_SEGMENT 4 Segmente mit unterschiedlichem Koordinaten-Ursprung gezeichnet. Der Koordinatenursprung kann problemlos durch Veränderung zweier Werte im WINDTAB Feld, das Daten für den Bildschirmaufbau enthält, verlegt werden. Damit ist das Unterprogramm leicht nachzuvollziehen. Es hat nur einen Nachteil: es ist relativ langsam, weil ja ein Großteil der gezeichneten Dreiecke außerhalb des am Bildschirm sichtbaren Segementes liegen. Jedes der vier so gezeichneten Segmente wird in einer String-Variable durch GET gespeichert. Zu beachten ist hierbei nur, daß die obersten zwei Bildschirmzeilen nicht verwendet werden dürfen - dort treten ebenfalls Fehler der POLYFILL-Routine auf, wenn Polygone über den oberen Bildschirmrand hinausragen.

Sind die 4 Segmente somit in Zeichenketten gesichert, dann werden sie im Unterprogramm HARDCOPY gedruckt. Der Ausdruck erfolgt zeilenweise, wobei vertikale Streifen des Bildschirms am Drucker horizontal ausgedruckt werden. Da das Datenformat für die NEC Drucker wegen des 24-Nadel-Kopfes einen sehr einfachen Aufbau hat (3 Byte ergeben die 24 Druckelemente), können die Daten direkt mit PEEK vom Bildschirm gelesen werden, was natürlich der einfachste und schnellste Weg ist.

Die 1440 Punkte ergeben sich nun dadurch, daß zuerst 360 Spalten zu 24 Punkten aus dem 4. Segement gedruckt werden, dann 360 Spalten aus dem 3. Segment,.. Dieser Segmentwechsel ist sehr leicht zu realisieren, weil die Segmente nun mit PUT sehr schnell am Bildschirm projeziert werden können. Wichtig ist, daß die Segmente in verkehrter Reihenfolge und auch innerhalb der Segmente die Daten von unten nach oben gelesen und gedruckt werden - andernfalls wäre der Ausdruck spiegelverkehrt!

Dieser Vorgang wiederholt sich vier mal bis die gesamte Grafik am Papier ist - der Vorgang dauert mit einem compilierten Programm bei BASE=5 etwa 20 Minuten.

Noch einige Details zur Druckersteuerung: es wird mit 180 Dots per Inch (DPI) gedruckt. Dies ist nicht die höchste Auflösung des P6, ein Arbeiten mit 360 DPI wäre aber sinnlos, weil der Abstand zweier Punkte viel kleiner als die Größe eines einzelnen Punktes wäre. Auch bei 180 DPI wird eine Fläche, bei der nur jeder 2. Punkt schwarz ist, am Papier als vollkommen schwarze Fläche dargestellt (weswegen die Grafiken am Bildschirm viel heller als am Drucker aussehen). Jede Zeile wird doppelt gedruckt, um eine höhere Qualität (besonders bei etwas älteren Farbbändern) zu erreichen. Dies kann mit Steuercodes sehr einfach erreicht werden: [27 86 n] gibt den Beginn eines Datenblocks an, der n mal gedruckt werden soll, [27 86 0] das Ende dieses Datenblocks. Schon im Unterprogramm NEC-PRINT wird der Zeilenvorschub mit [28 51 47] auf 47/360 Zoll eingestellt - d.h. das sich je zwei Zeilen um 1/360 Zoll überlappen (eine Zeile hat die Breite 24/ 180 Zoll). Dadurch werden helle Streifen zwischen den Zeilen weitgehend vermieden, die auftretende Verzerrung des Bildes ist nicht wahrnehmbar.

Sollten die Druckergebnisse dennoch nicht zufriedenstellend sein, dann sollte überprüft werden, ob die Andruckstärke der Nadeln richtig eingestellt ist (siehe Handbuch des Druckers).

Wie aus der Beschreibung hervorgeht, müssen die vier Segmente zwischengespeichert werden, wofür etwa 100 KByte notwendig sind. Wenn dieser Speicher nicht vorhanden ist, dann kann die Breite der Segmentgröße verkleinert werden: es muß jedoch die Byte-Anzahl ein Vielfaches von 3 sein, weil ja immer 24=3*8 Punkte zugleich gedruckt werden. Je kleiner BREITE gewählt wird, desto größer ist die Zahl der notwendigen Streifen (und damit auch die Rechenzeit). Eine möglicher Wert wäre 42 - die Schleife für STREIFEN muß dann von 0 bis 5 laufen (Speicherbedarf ~ 70 Kbyte).

Das Programm läuft in der compilierten Version auch auf Minimalrechnern (512 KByte, Disketten-TOS) bis BASE=5; wer allerdings außerdem auf einen Compiler verzichten muß, muß die obige Verkleinerung der Segmente durchführen, damit das Programm läuft.

Variationen

Die Idee dieses Druckverfahren ist grundsätzlich für jeden Computer und jeden Drucker (theoretisch auch für LASER-Drucker !) zu realisieren. Es ist allerdings nur für Grafiken geeignet, die einigermaßen rasch in beliebiger Vergrößerung vollständig gezeichnet werden können (das ist in der Regel nur für solche Grafiken der Fall, die durch eine begrenzte Zahl von Flächen oder Linien aufgebaut werden kann - z.B. das Resultateines Hiddens-Surface Algorithmus).

Eine Grafik dieser Art wird durch Multiplikation der Bildschirm-Koordinaten vergrößert, in Segmenten gezeichnet, zwischengespeichert und sodann gedruckt. Ein wesentlicher Vorteil ist, daß dazu keine speziellen Zeichen-Routinen geschaffen werden brauchen - es muß lediglich der Koordinatenursprung verlegt werden (was natürlich auch rechnerisch für jeden einzelnen Punkt möglich wäre, wenn das Betriebssystem eine solche Möglichkeit nicht bietet).

In einem Punkt muß das Programm allerdings geändert werden, wenn ein Drucker mit 9 oder 18 Nadeln oder eine andere Auflösungstufe verwendet wird: es können dann die Daten für den Drucker nicht mehr einfach vom Bildschirm ‘gepeekt’ werden - sie müssen Punkt für Punkt durch POINT gelesen werden und rechnerisch zu Daten im dem Drucker genehmen Format umgewandelt werden, was zwar nicht kompliziert, aber relativ langsam ist. Die Größe der Segmente wird sich natürlich nach der Auflösung des verwendeten Druckers richten; abgesehen davon ist es aus Zeitgründen natürlich sinnvoll, die Segmente möglichst groß zu machen -Voraussetzung dazu ist aber ein ausreichender Speicher.

Quellen:

[I] David F. Rogers: Procedural Elements For Computer Graphics, 1985 McGraw Hill

Abbildung 4-6: Beispielausdrucke, die die 3 Arten zeigen, in der Grafiken dargestellt werden können.

Abbildung 4-6: Beispielausdrucke, die die 3 Arten zeigen, in der Grafiken dargestellt werden können.

' PLOTTER - dreidimensionale Funktionen am Bildschirm darstellen und 
' wahlweise im DIN A4 Format am NEC P6 ausdrucken
'
' Variablen belegen. Felder dimensionieren
'
Scale=1	! Vergrößerungsfaktor Für Ausgabe
Linienstaerke=1 ! Linienstärke der Umrandung der Dreiecke
Dpoke Intin,Sgn(Linienstaerke) ! Umrandung bei POLYFILL ein/aus 
Dpoke Contrl*2,0	! mit der VDI-Funktion Set_Fill_
Dpoke Contrl*6,1	! Perimeter_Visibi1ity
Vdisys 104
Base=10	! Basislänge einer einzelnen Dreiecksfläche
Lx=5	! Beleuchtungsvektor: zeigt vom unter-
Ly=-4	! suchten Punkt in Richtung einer
Lz=9	! unendlich weit entfernten Lichtquelle
Llen=Sqr(Lx^2*Ly^2*Lz^2)	! diesen Vektor auf Länge 1 verkürzen
Div Lx,Llen 
Div Ly,Llen 
Div Lz,Llen
Xreso=445	!Koord.bereich der dargestellten Ebene
Yreso=330
Line 560,0,560,400	!bis zu dieser Linie wird Grafik gedruckt
Dim X%(3),Y%(3)	!Feld zum Zeichen der Dreiecke
Dim Z(Xreso/Base,Yreso/Base)	! Feld für Funktionswerte der Fläche
Dim Farbe%(Xreso/Base,Yreso/Base,1) !Feld für Farben der einzelnen Dreiecke
Dim Grauton$(J2)	!Feld für Graustufen-Muster
©Grauton	!die Daten für Schattierungen einlesen
'
' Funktion und Unterfunktionen, die die dreidimensionale Ebene bilden 
Deffn Z(X,Y)=@Uf(X-250,Y-180)*15*@Uf(X-170,Y-80)*15 
Deffn Uf(A,B)=Sin(Sqr(A^2*B^2)/16)
'
' die Funkionswerte der Fläche erechnen und in Feld speichern 
For Y=0 To Yreso Step Base 
	For X=0 To Xreso Step Base 
		Z(X/Base,Y/Base)=@Z(X,Y)-35	!vom Funktionswert 35 subtrahieren.
	Next X	! damit Funktion nicht über den oberen
Next Y	!	Bildschirmrand hinausragt
'
' Funktion zur Helligkeits-Berechnung eines Dreiecks 
Deffn Helligkeit(X,Y,Z) = (Lx*X+Ly*Y+Lz*Z)/Sqr(X^2*Y^2*Z^2)
'
' Fläche am Bildschirm ausgeben, dabei Farbe der Dreiecke speichern 
For Y=0 To Yreso-Base Step Base 
	For X=0 To Xreso-Base Step Base 
		X%=X/Base	! Index auf Feld für Funktionswerte
		Y%=Y/Base
		Z1=Z(X%,Y%)	! die 4 Funktionswerte ergeben die
		Z2=Z(X%*1,Y%)	! Z-Koordinaten für die Eckpunkte
		Z3=Z(X%,Y%+1)	! zweier Dreiecksflächen
		Z4=Z(X%+1,Y%+1)
		Farbe1=Max(@Helligkeit(Z1-Z2,Z1-Z3,Base)*Farbanzahl,0)
		Farbe2=Max(©Helligkeit(Z3-Z4.Z2-Z4,Base)*Farbanzahl,0) 
		Farbe%(X%,Y%,0)=Farbe1	! Farbe der Flächen in Feld speichern
		Farbe%(X%,Y%,1)=Farbe2
		©Dreieck(X,X+Base,X,Y,Y,Y+Base,Z1,Z2,Z3,Farbe1)
		©Dreieck(X,X+Base,X+Base,Y+Base,Y+Base,Y,Z3,Z4,Z2,Farbe2)
	Next X 
Next Y
'
' Ausgabe der Grafik am Drucker 
Print "Ausdruck starten ? (J/N)"
A=Inp(2)
If A=Asc("j") Or A=Asc(”J")
	Scale=3.6	! Vergrößerungsfaktor für Ausgabe am NEC P6
	@Nec_print 
Endif
'
Procedure Dreieck(X1,X2,X3,Y1,Y2,Y3,Z1,Z2.Z3,Farbe%)
' Unterprogramm, das aus den dreidimensionalen Eckpunktkoordinaten einer 
' dreieckigen Fläche diese am Bildschirm (zweidimensional) darstellt 
X%(0)=(X1+Y1/3)*Scale ! Umrechnung in zweidimensionale Koordinaten: 
X%(1)=(X2+Y2/3)*Scale ! zur X-Koordinate wird ein Drittel der 
X%(2)-(X3+Y3/3)*Scale ! Y-Koordinate addiert - dadurch kommt die 
Y%(0)=(Y1-Z1)*Scale	! Schrägstellung der Fläche zustande ; die
Y%(1)=(Y2-Z2)*Scale	! Y-Koord. wird um die Z-Koord. verkleinert;
Y%(2)=(Y3-Z3)*5cale	! alle Koord. werden Scale multipliziert
If Linienstaerke=8 
	For A%=0 To 2	! (Fehler der POLYFILL-Routine auffangen: wenn
		B%=(A%+1) Mod 3	! ein Dreieck gezeichnet werden soll, bei dem
		C%=(A%+2) Mod 3	! eine Linie horizontal verläuft, so wird
		If Y%(A%)=Y%(B%)	! diese horizontale Linie nicht mit dem Muster
			If Y%(A%)<Y%(C%)	! angefüllt; deshalb werden in diesem Fall die
				Dec Y%(A%)	! entsprechenden Y-Koord.werte um 1 erhöht
				Dec Y%(B%)	! oder vermindert; dieser Fehler ist nur dann
			Else	! bemerkbar, wenn die Routine ohne Umrandung
				Inc Y%(A%)	! der zu zeichnenden Fläche verwendet wird
				Inc Y%(B%)
			Endif 
		Endif 
	Next A% 
Endif
X%(3)-X%(0)	! für Umrandung mit POLYLINE muß ein
Y%(3)=Y%(0)	! geschlossener Linienzug vorhanden sein

Deffill ,Grauton$(Farbe%) ! Farbe% bestimmt den Grauton 
Polyfill 3,X%(),Y%()	! Fläche zeichnen
If Linienstaerke=2	! gegebenenfal1s auch dickere Umrandung
	Polyline 4,X%(),Y%() Offset 8,1 ! zeichnen (durch horizontale und 
	Polyline 4,X%(),Y%() Offset 1,0 ! vertikale Versetzung des Linien-
	Polyline 4,X%(),Y%() Offset 1,1 ! Zuges)
Endif
Return
' ############### Ausgabe am Drucker
Procedure Nec_print
	' Haupt-Unterprog. zur großformatigen Ausgabe am NEC P6 
	' Zellenabstand: nur 47/360 Zoll, um horizontale Streifen zu vermeiden 
	Lprlnt Chr$(28)+Chr$(51)+Chr$(47);
	Bildanzahl=4	! Zahl der Bildsegmente
	Dim Bild$(Bildanzahl) ! Felder für Bild-Daten
	Hoehe=360	! Zahl der Punkte (vertikal) pro Bildsegment
	Breite=63	! Zahl der Bytes (horizontal) pro Bildsegment
	Hidem	! Maus stört nur
	For Streifen=0 To 3	! 4 Streifen erfassen 63*8X4=2016 Punkte
		For Bi1d=0 To Bildanzahl-1	! pro Streifen vier
			@Plot_segment(Streifen*Breite*8,Hoehe*Bild) ! Segmente zeichnen 
			Get 0,2,Breite*8.2+Hoehe,Bild$(Bild*l)	! und speichern
		Next Bild
		©Hardcopy(Breite,Hoehe,Bildanzahl) ! den gesamten Streifen drucken 
	Next Streifen 
	Showm
	Lprint Chr$(27)+Chr$(50)	! normaler Zeilenabstand P6
	Lpoke Windtab+64,0	! Koordinatenursprung Mieder nach (0,0)
Return
'
Procedure Plot_segment(Xoffset,Yoffset)
	' Bildschirmsegement am Bildschirm zeichnen, in String speichern 
	Cls
	Dpoke Windtab+64,-Xoffset	IKoordinatenursprung verlegen
	Dpoke Windtab*66,-Yoffset
	For Y=0 To Yreso-Base Step Base ! die dreidimensionale Fläche zeichnen, 
		For X=0 To Xreso-Base Step Base ! wobei die früher berechneten Farb-
			X%=X/Base	! Werte verwendet werden:
			Y%=Y/Base	! es wird die gesamte Fläche
			Z1=Z(X%,Y%)	! gezeichnet, durch die Verlegung
			Z2=Z(X%+1,Y%)	! des Koordinatenursprungs
			Z3=Z(X%,Y%+1)	! und den Vergrößerungsfaktor
			Z4=Z(X%+1,Y%+1)	! (scale) entstehen die
			Farbe1=Farbe%(X%,Y%,0)	! gewünschten Segmente
			Farbe2=Farbe%(X%,Y%,1)
			©Dreieck(X.X+Base,X,Y,Y,Y+Base,Z1,Z2,Z3,Farbe1)
			©Dreieck(X,X+Base,X+Base,Y+Base,Y+Base,Y,Z3,Z4,Z2,Farbe2)
		Next X 
	Next Y 
Return
Procedure Mardcopy(Breite,Hoehe,BiIdanzahl)
	' einen horiz. Streifen ausdrucken (bestehend aus 4 Bild-Segmenten)
	' Hoehe ... Zahl der Punkte vertikal am Bildschirm 
	' Breite ... Zahl der zu übertragenden Bytes; muß Vielfaches von 3 sein 
	Spalten=Hoehe*Bildanzahl	! Druckspalten am Drucker (1440)
	Adr%=Xbios(2)	! Adresse des Bildschirmspeichers
	Cls
	For X%=0 To Breite-1 Step 3	! X-Koord. am Bildschirm (in Byte)
		Lprint Chr$(27)+Chr$(86)+Chr$(2); (jede Zeile doppelt drucken 
		' Grafikmodus (180 DPI)
		Lprint Chr$(27)+Chr$(42)+Chr$(39)+Chr$(Spalten)+Chr$(Spalten\256);
		For Bi1d=Bildanzahl Downto 1	! die Bildsegmente der Reihe nach
			Put 0,0,Bild$(Bild)	! projezieren und eine Zeile zu
			For Y%=Hoehe*80-80 To 0 Step -80 ! 24 Punkten drucken;
				Out 0,Peek(Adr%*Y%*X%)	! dabei die Daten direkt vom
				Out 0,Peek(Adr%*Y%*X%+1)	! Bildschirm lesen (von unten
				Out 0,Peek(Adr%*Y%*X%+2)	! oben, damit Ausdruck nicht
			Next Y%	! spiegelverkehrt)
		Next Bild
		Lprint Chr$(13)	! (Wagenrücklauf
		Lprint Chr$(27)+Chr$(86)+Chr$(0)	! Daten-Ende für Mehrfach-Druck
	Next X% 
Return
'
Procedure Grauton 
	Restore Grauton_data 
	Farbanzahl=32
	Dim Bit%(7)	! Hilfsfeld  das binär das 8*8
	For Grau_ton=Farbanzahl Downto 0	! Punkte-Muster enthält, das aus
		Clr Bit$	! den DATA Zeilen gelesen und
		For I=0 To 7	! anschließend in Zeichenketten
			Bit$=Bit$+Mki$(Bit%(I)+Bit%(I)*256) ! umgewandelt wird, die für den
		Next I	! DEFFILL Befehl geeignet sind;
		Grauton$(Grau_ton)=Bit$+Bit$	! die DATA-Werte enthalten die
		Read A,B	! Koordinaten jenes Punktes
		Bit%(A)=Bit%(A) Or 2^B	! innerhalb der 8*8 Matrix, die
	Next Grau_ton	! gesetzt werden
	Erase Bit%()	! Hilfsfeld wieder löschen
	Grauton_data:
	Data 0,0, 4,4, 5,1, 1,5, 2,2, 6,3, 6,6, 8,4, 2,7, 5,7, 0,3, 4,6
	Data 7,2, 3,5, 4,2, 1,1, 1,3, 0,7, 6,5, 7,8, 2,3, 3,1, 7,4, 5,6
	Data 6,1, 3,6, 5,4, 7,7, 1,6, 3,3, 4,8, 0,2, 0,0
Return

Michael Kofler
Aus: ST-Computer 07 / 1988, Seite 68

Links

Copyright-Bestimmungen: siehe Über diese Seite