Seite 1
Grafik ( Teil 2 )
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
1. Einleitung..................................................................... 1
2. Koordinatensysteme................................................... 2
2.1 Welt - und Gerätekoordinaten .................................. 3
2.2 Ein Beispiel: Funktionsplotter................................... 6
2.3 Mandelbrotmenge .................................................... 10
2.3.1 Komplexe Zahlen...................................................... 10
2.3.2 Applet zur Darstellung der Mandelbrotmenge ... 13
2.3.3 Beispiele ..................................................................... 21
3. Transformationen in der Ebene .............................. 25
3.1 Matrizen, Definition ................................................. 26
Matrizenmultiplikation............................................ 27
3.2 Vektoren und 2x2 Matrizen ..................................... 28
3.3 Transformationen in der Ebene .............................. 29
3.4 Homogene Koordinaten .......................................... 32
3.4.1 Beispielrechnungen .................................................. 33
3.4.2 Beispielapplet ............................................................ 36
3.4.3 Klassen im Applet..................................................... 39
3.4.4 Beispielbilder............................................................. 42
1. Einleitung :Standards in Computergrafik
Erst 1985 wurden international zum ersten Mal Standards für Computergrafik festgelegt, das
GKS ( Graphical Kernel System ). Man darf nun nicht annehmen, dass danach auf allen Syste-
men in allen Programmiersprachen mit den gleichen Befehlen gearbeitet wurde. Für den "nor-
malen" Anwender, zu denen auch Lehrer und Schüler gehören, hat sich aber seit 1986 eine Men-
ge verändert, denn man muss sich heute beim Wechsel der Systeme und der Programmierspra-
chen kaum noch umstelllen, da in der Tat die meisten Grafikelemente standardisiert wurden.
Es geht aber auch heute noch um solche Standardisierungsprobleme bei 3D-Grafik (GKS-3D)
und bei den Übergängen von geräteunabhängigen zu geräteabhängigen Softwaresystemen
(CGI= Computer Graphics Interface).
In diesem Bereich wird es in naher Zukunft sicher noch weitere Veränderungen geben.1
Uns werden im Folgenden aber nur einzelne Aspekte interessieren, die auch für den Unterricht
relevant sind.
Die einfachsten Darstellungselemente sind Punkte und Linien, aus denen dann komplexere
Grafikobjekte zusammengesetzt werden können. Aus Punkten lassen sich z.B. in festgelegten
Zeichenmatrizen Buchstaben darstellen. Allerdings könnte man Buchstaben auch über Vektoren
definieren, also etwa als einen Polygonzug. Dazu muss man dann aber Linien darstellen können.
Die aber werden sich am Bildschirm doch wieder aus (nicht wirklich miteinander verbundenen )
Punkten zusammensetzen. Dabei tauchen schon die ersten Probleme auf. Wenn eine Linie von
einem Punkt mit den Koordinaten ( x1,y1) zu einem Punkt (x2,y2) verläuft und dazwischen eine
gewisse Anzahl von Bildschirmpunkten liegt, welche dieser Punkte sollen dann aufleuchten ?
Genauso wäre zu entscheiden, ob Punkt am Bildschirm und Punkt z.B. auf einem Plotter dassel-
be sein soll. Über diese Fragen findet man in der Literatur ausreichend Informationen.2
1 siehe auch: W.D.Fellner, Computergrafik, BI-Wissenschaftsverlag, Kap.12 und Kapitel 5, Seite 76 ff
(x1/y1)
(x2/y2)
(x1/y1)
(x2/y2)
Graphical Kernel System
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
Seite 2
Uns soll zuerst ein Teilaspekt beschäftigen:
2. Koordinatensysteme
Immer, wenn man Grafiken am Bildschirm darstellen will, muss man dessen Koordinatensystem
kennen und beachten. Bis jetzt hat uns das nicht sehr interessiert, weil nicht mit Koordinaten ge-
rechnet wurde. Wir haben zwar punktgenau Objekte plaziert, oder auch mit der Turtlegrafik
Figuren in das Bildschirmkoordinatensystem gezeichnet, aber es hat uns gereicht, zu wissen,
dass die Y-Achse "verkehrt" herum liegt. Je nach Größe des Bildschirms standen uns in x - und
y-Richtung unterschiedlich viele Punkte zur Verfügung und glücklicherweise sind die Betreibs-
systeme so freundlich zu uns, nicht zu meckern, wenn auch mal außerhalb des Bildschirms ge-
malt wird.
Probleme tauchen aber sofort auf, wenn man z.B. den Graphen einer rationalen Funktion am
Bildschirm zeichnen lassen will. Stellt man auf dem Papier den Graphen der Funktion f mit der
Funktionsgleichung f(x) = x2 dar und wählt dafür den Bereich von xmin=0 bis xmax= 4, dann er-
hält man für die y-Achse ymin= 0 und ymax=16. Würde das 1:1 auf Bildschirmkoordinaten über-
tragen, wäre das Ergebnis doch wohl etwas zu klein, da man offensichtlich auf eine Fläche von
4x 16 Punkten nicht viel zu sehen bekommt.
Es muss eine geeignete Koordinatentransformation her !
Die Koordinatenwerte, die auf dem Blatt Papier oder in der Wertetabelle vorhanden sind, heißen
Weltkoordinaten, weil sie aus der "wirklichen" Welt stammen. Sie sollen umgerechnet werden in
Gerätekoordinaten - also in unserem Fall in Koordinaten des Bildschirms.
Weltkoordinaten Gerätekoordinaten
xWmaxxWmin
yWmax
yWmin
Koordinatensysteme
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
(xW/yW) (xG/yG)
xGmaxxGmin
yGmin
yGmax
(0/0)
Seite 3
xW – xWmin xG – xGmin
Der gesamte Ausschnitt aus dem Weltkoordinatensystem, der abgebildet werden soll, heißt
Window und der Ausschnitt aus dem Gerätekoordinatensystem, in den hinein abgebildet wird,
ist der Viewport.
Es sollen folgende Festlegungen gelten:
Das bedeutet, dass der Bereich ∆xW auf den Bereich ∆xG ab-
gebildet wird und der Bereich ∆yW auf ∆yG.
Die Zuordnungen yWmin ---> yGmax und yWmax ---> yGmin
haben ihren Sinn, weil die y-Achse in den Grätekoordianten
nach unten zeigt.3
Für die Umrechnung eines Punktes mit den Koordinaten (xW/yW) gilt , dass die Strecke
( xW – xWmin) aus dem Window auf die Strecke (xG – xGmin) im Viewport abgebildet wird. Ge-
nauso wird eine entsprechende Strecke in y-Richtung abgebildet.
Dabei ist in der Formel für die Umrechnung der y-Werte bedacht worden, dass die Y-Achse am
Bildschirm nach unten verläuft und daher die positiven y-Werte aus den Weltkoordinaten in pas-
sende Werte für die Gerätekoordianten umgerechnet werden.
Ein kleiner Auschnitt aus einer Tabellenkalkulation zeigt die Richtigkeit für die Parabelfunktion.
Es sein xWmin = – 1, xWmax = 3, yWmin = 0, yWmax = 10, xGmin = 50, xGmax = 450,
yGmin = 50, yGmax = 300 und damit ∆xG = 400, ∆yG = 250, ∆xW = 4 und ∆yW = 10.
3 Man kann in den Gerätekoordinaten auch yGmax "oben" lassen und yGmin "unten" . Wenn dann etwa yGmax=50 und yGmin = 400 ist, dann hat man ∆yG = 50 - 400 = – 350. Dann kann man in der Umrechnungsfor-mel für die y-Werte auf das Minuszeichen verzichten, weil es ja schon in ∆yG steckt.
2.1 Weltkoordinaten und Gerätekoordinaten
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
Seite 4
obere Grenze des Darstellungsbereichs x-Achseuntere Grenze des Darstellungsbereichs x-Achse
Weltkoordinaten GerätekoordinatenxWmaxxWmin
xGmaxxGmin
obere Grenze des Darstellungsbereichs y-Achseuntere Grenze des Darstellungsbereichs y-AchseKorrdinaten eines Punktes
yWmaxyWmin
yGminyGmax
xW / yW xG / yG
xG= xGmin + ∆xG∆xW
⋅ ( xW – xWmin ) yG = yGmax – ∆yG∆yW
⋅ ( yW – yWmin )
∆yG= yGmax – yGmin∆yW = yWmax – yWmin∆xG= xGmax – xGmin
∆xW = xWmax – xWmin
Ganz zufrieden sein können wir aber für den Fall des Graphen einer Parabelfunktion aber noch
nicht. Im Weltkoordinatensystem besteht der Graph ja nicht aus einzelnen Punkten sondern ist
eine durchgezogenen Linie mit unendlich vielen Punkten.
Durch eine Umrechnung können wir aber immer nur eine endliche Anzahl von Punkten in die
Gerätekoordianten übertragen und erhalten damit in jedem Falle nur ein Abbild unserer Kurve,
dass durch die Anzahl der darstellbaren Punkte am Bildschirm begrenzt ist. Es könnte also sein,
dass eine Art Polygonzug am Bildschirm entsteht, wenn mit einem Zeichenbefehl wie drawLine
die berechneten Punkte am Bildschirm zu einer durchgehenden Kurve verbunden werden sol-
len. Wie fein muss man eine Wertetabelle im Window einteilen, damit im Viewport alle horizontal
zur Vefügung stehenden Punkte komplett ausgenutzt werden können ?
Wenn die Tabelle der x-Werte beginnend mit xWmin jeweils in Schritten dx fortschreitet, und
diese Zunahme um dx jeweils um 1 Punkt im Viewport weiterführen soll, dann gilt :
Für die Wertetabelle oben ergäbe sich dann dx = 4/400 = 0,01 und folgender Ausschnitt:
Darin kann man sehen, dass es in xG tatsächlich immer um einen Punkt vorangeht. Die Werte
für yG müssen dann noch gerundet werden. Ein besseres Ergebnis kann man für eine
Seite 5
Koordinatentransformationen
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
dx = ∆xW∆xG
xW yW ∆∆∆∆xG/∆∆∆∆xW ∆∆∆∆yG/∆∆∆∆yW xG yG
-10
10
100100
2525
50150
275300
23
49
100100
2525
350450
20075
xW yW ∆∆∆∆xG/∆∆∆∆xW ∆∆∆∆yG/∆∆∆∆yW xG yG round(yG)
-1-0,99
10,9801
100100
2525
5051
275275,4975
275275
-0,98-0,97-0,96-0,95
0,96040,9409
100100
0,92160,9025
100100
2525
5253
2525
5455
275,99276,4775
276276
276,96277,4375
277277
-0,94 0,8836 100 25 56 277,91 278
Bildschirmausgabe nicht erwarten. Die Frage, wie es z.B. mit der Ausgabe auf einem Plotter aus-
sieht , werden wir hier nicht beantworten, wir bleiben vorerst bei Monitoren, deren Ausgabe in
einer Punktmatrix erfolgt.
Ein kleines Java-Programm soll das nun veranschaulichen. Es geht um die Darstellung einer
ganzrationalen Funktion. Man soll xWmin, xWmax, yWmin und yWmax angeben können. Die
Festlegungen für die Begrenzungen des Viewport werden wir vorgeben.
//// Funktionplotter1.java// Funktionplotter1//// Hans-Georg Beckmann Sun Nov 24 2002.// Ein Funktionsplotter zur Demonstration der Umrechnung von Weltkoordinaten// in Gerätekoordinaten// Es soll nur ein einfache Funktion gezeichnet werden// eingeben kann man untere und obere Grenzen der Weltkoordinaten die Grenzen// der Gerätekoordinaten werden fest vorgegeben. Eine Kontrolle auf // Fehleingaben ist erst einmal nicht vorgesehen//
import java.awt.*;import java.applet.*;import java.awt.event.*; // für den ActionListener
public class Funktionplotter1 extends Applet implements ActionListener{ Button myButton1; // Der startet die Zeichenroutine Label[] myLabels=new Label[4]; // 4 Label String[] beschriftungen= {" min x-Wert"," max x-Wert"," min y-Wert"," maxy-Wert"}; TextField[] werte = new TextField[4]; // Edit-Felder für die Werteeingabe
// Nun kommen die konstanten Werte für die Gerätekoordinaten final static int xGmin=40; final static int xGmax=440; final static int yGmin= 40; final static int yGmax=540; final static int deltaxG=400; final static int deltayG=500; // die beiden Werte müssen nicht gleich sein // Nun die Variablen, die sich erst noch ergeben werden double xWmin,xWmax,yWmin,yWmax,deltaxW, deltayW; double xW,yW; // die Welt-Koordinaten int xG,yG; // die zugehörungen Gerätekoordinaten double dx; // das Stück , um das in der Wertetabelle vorangegangen wird boolean start=false;
public void init() { setLayout (null);
Seite 6
2.2 ein Funktionenplotter
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
myButton1= new Button("Start"); // Knopf mit Beschriftung myButton1.setForeground(Color.red); myButton1.setBounds(460,460,140,25); myButton1.addActionListener(this); // er bekommt einen Listener add(myButton1); // rein mit dem Knopf for ( int i=0;i<4;i++) { myLabels[i]= new Label(beschriftungen[i]); // neues Label mit
// Beschr. aus Liste myLabels[i].setBackground(Color.lightGray); // grauer Hintergrund myLabels[i].setForeground(Color.blue); // blaue Schrift myLabels[i].setFont(new Font("Arial",0,12)); myLabels[i].setBounds(460,150+i*50,80,25); add(myLabels[i]); werte[i]= new TextField(8); werte[i].setBounds(550,150+i*50,80,25); werte[i].setBackground(Color.lightGray); add(werte[i]); } } //********************************************************************* // Nun eine einfache Funktionsgleichung // //********************************************************************* public int getfunktionswert(double x) { double fvonx; fvonx=x*x*x-0.5*x; // eine einfache Funktion 3.Grades als Beispiel return(int)(Math.round(yGmax-(deltayG/deltayW)*(fvonx-yWmin)));
// round liefert long und (int) macht // daraus ein integer }//********************************************************************** public void paint(Graphics g) { int xGalt,yGalt; // wir ziehen Linien von alten zu neuen Koordinaten int xG0,yG0; // es sollen x - und y-Achse gezeichnet werden if(start==true) // wenn Startknopf geklickt- im ActionListener { // Umrandung zeichnen g.drawLine(xGmin,yGmin,xGmax,yGmin); g.drawLine(xGmin,yGmin,xGmin,yGmax); g.drawLine(xGmin,yGmax,xGmax,yGmax); g.drawLine(xGmax,yGmin,xGmax,yGmax); // Nun Werte aus den TextEdit-Feldern holen xWmin=Double.parseDouble(werte[0].getText()); xWmax=Double.parseDouble(werte[1].getText()); yWmin=Double.parseDouble(werte[2].getText()); yWmax=Double.parseDouble(werte[3].getText()); xW=xWmin; // Start beim kleinsten Wert
Seite 7
2.2 Funktionsplotter
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
deltaxW=xWmax-xWmin; // Auflösung in x-Richtung deltayW=yWmax-yWmin; // Auflösung in y-Richtung dx=deltaxW/deltaxG; // Schrittweite in der Wertetabelle für die x-Werte // jetzt ersteinmal x-Und y-Achse einzeichnen xG0=xGmin+(int)((1/dx)*(0-xWmin)); yG0=getfunktionswert(0); g.drawLine(xG0,yGmin,xG0,yGmax); // y-Achse g.drawLine(xGmin,yG0,xGmax,yG0); // x-Achse xGalt=xGmin+(int)((1/dx)*(xW-xWmin)); // erster Punkt aus der Wertetabelle
// wird Startpunkt der Zeichnung yGalt=getfunktionswert(xW); xW=xW+dx; // jetzt einen Schritt voran,
// um den ersten neuen Wert zu ermitteln // nun beginnt die Schleife, in der die ganze Tabelle durchlaufen wird do { xG=xGmin+(int)((1/dx)*(xW-xWmin)); yG=getfunktionswert(xW); if((yG<yGmax)&&(yG>yGmin)) // innerhalb des Rahmens --> dann malen... g.setColor(Color.blue); else g.setColor(Color.white); // ... sonst nicht g.drawLine(xGalt,yGalt,xG,yG); xW=xW+dx; // ein Schritt voran in der Wertetabelle xGalt=xG; yGalt=yG; } while(xW < xWmax); } }// Ende von paint
//*****************************************************************//// Nun kommt die Methode actionPerfomed////***************************************************************** public void actionPerformed(ActionEvent e) { Object welcherKnopf; // ein Objekt welcherKnopf=e.getSource(); //die Quelle des Ereignisses ist der Knopf if( welcherKnopf==myButton1) { start=true; repaint(); } }// Ende von actionperformed }
Insgesamt ein recht einfaches Programm, das folgende Ausgabe erzeugt:
Seite 8
Funktionsplotter
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
Man könnte hier nun sehr viel Mühe investieren , um folgende Verbesserungen anzugehen:
- Achseneinteilungen und Achsenbeschriftungen
- freies Zoomen in den Funktionsgraphen hinein
- eine Eingabemethode für Funktionsterme mit Fehlerabfrage etc.
- eine Ausgabe in eine Datei
( siehe auch : Küchlin, Weber: Einführung in die Informatik, Seite 228 ff )
Wenn sie viel Zeit im Unterricht haben oder sehr selbstständige Schülerinnen und Schüler, dann
können sie das alles machen. Es besteht aber die Gefahr, dass die Mathematik hier die Informatik
erschlägt.
Wir wollen noch ein weitere Programm betrachten, bei dem es um diese sehr schlichte Behand-
lung von Koordinatentransformation geht und das einen Ausblick auf ein sehr schönes Teilge-
biet der Mathematik und der Informatik liefert, das einfach beim Thema Grafik nicht fehlen darf:
2.3 Die Mandelbrotmenge
Es geht dabei um die Darstellung einer rekursiven Funktion in den komplexen Zahlen.
Komplexe Zahlen werden in der komplexen Zahlenebene dargestellt. Dabei sind entlang der
x-Achse die Realteile der komplexen Zahlen aufgetragen und entlang der y-Achse die imaginä-
Seite 9
Funktionsplotter
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
ren Teile der Zahlen. Zahlen in der Ebene lassen sich dann als z= a + b*i schreiben.
Dabei ist i = √-1 also die Wurzel aus -1, die in den reellen Zahlen nicht existiert. Für diese kom-
plexen Zahlen gelten besondere Rechenregeln auf deren Herleitung hier verzichtet wird. Man
kann Informationen darüber in vielen Mathe-
matikbücher finden.
Die Länge des Pfeils vom Ursprung bis zu ei-
ner Zahl z in der Zahlenebene entspricht dem
Betrag der kompexen Zahl und wird noch von
Interesse sein.
Wie in den rellen Zahlen, kann man auch in
den komplexen Zahlen Funktionen definieren
und Funktionswerte errechnen. Allerdings hat
man es mit der bildlichen Darstellung von
Funktionen etwa schwer, da der Funktions-
graph im 4-dimensionalen Raum existiert und nicht ohne Weiteres zu veranschaulichen ist.
Die Funktion, die betrachtet werden soll ist:
Dabei sind zn+1, zn und c komplexe Zahlen. Man setze für c eine beliebige komplexe Zahl ein,
für z0 wählt man die Zahl 0 + 0*i und damit ist z1 = z02 – c = (0 + 0*i)2 + c und weiter ist dann
z2= z12 + c und so fort. Es soll also eine Iteration erfolgen, bei der der ermittelte Funktionswert
wieder als Argument in die Funktion eingesetzt wird. Eine Art rekursives Einsetzen. Die Werte
für zn "springen" in der Ebene hin und her. Uns interssiert aber ein besonderer Aspekt der Zah-
len zn, nähmlich ihr Betrag. Je nach dem, welchen Startwert für c man wählt, divergiert der Be-
trag von zn sehr schnell und geht offensichtlich gegen unendlich. Für andere Werte aber bleibt
der Betrag endlich und wächst nicht über eine bestimmte Grenze hinaus an.
Ähnlich verhält sich die Funktion auch, wenn man c fest vorgibt und dann für z0 unterschiedli-
che Werte aus der Zahlenebene einsetzt. Diese Variante wurde schon während des 1.Weltkrieges
von dem französischen Mathematiker Julia untersucht ( ohne Computer ). Die Version mit fe-
stem Startwert z0= 0 + 0*i und veränderlichen Werten für c wurde in den 70er Jahren von
Seite 10
2.3 Mandelbrotmenge
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
a
b*i
Realteil
Imaginärteilz = a + b*i
zn+1 = zn2 – c
B. Mandelbrot , einem Mathematiker bei IBM , untersucht und durch ihn berühmt.
Man stelle sich nun fogendes Verfahren vor:
-Wähle nacheinander alle Punkte in der kompexen Zahlenebene und setze sie als Zahl c in die
Funktionsgleichung ein, wobei immer mit z0 = 0 + 0*i begonnen wird.
- Untersuche , ob nach 100 rekursiven Einsetzungen der Betrag von zn immer noch kleiner ist als
eine vorgegebene Grenze ( z.B. Grenze =5).
- Wenn das der Fall ist, glauben wir, dass der Btrag nie divergiert und malen den Punkt in der
komplexen Ebene schwarz.
- Wenn der Betrag die vorgegebene Grenze überschritten hat, gehen wir davon aus , dass der Be-
trag divergiert und malen den Punkt weiß.
Bevor wir daran gehen, das Bild zu erstellen machen wir uns kurz die Rechnungen klar.
Die Addition bzw. Subtraktion komplexer Zahlen entspricht der Addition von Vektoren:
( a1 + b1*i ) + ( a2 + b2*i ) = (a1 + a2 ) + ( b1 + b2 )*i
Es wird also komponentenweise addiert ( oder subtrahiert ) wobei dann ( a1 + a2 ) der Realteil
und ( b1 + b2 ) der Imaginärteil des Ergebnisses ist.
Die Multiplikation ist ebenfalls schnell erklärt:
( a1 + b1*i ) * ( a2 + b2*i ) = ( a1 * a2 + a1* b2*i + b1*i*a1 + b1*i*b2*i )
hier kann man nun zusammenfassen: = ( a1 * a2 + b1* b2*i*i + (a1b2 + b1a2)*i )
mit i*i = –1 erhalt man dann: = ( a1 * a2 – b1* b2 ) + (a1b2 + b1a2)*i
Speziell für das Quadrat einer komplexen Zahl zn = a + b*i ist dann zn2 = ( a2 – b2 ) + 2*a*b*i
Wird nun von zn2 noch eine Zahl c= cre + cimag*i subtrahiert , dann bekommt man:
zn+1 = zn2 – c = ( a2 – b2 ) + 2*a*b*i – ( cre + cimag*i ) = ( a2 – b2 ) – cre + ( 2*a*b – cimag )*i
Der Realteil von zn+1 ist damit : a2 – b2 – cre
Der Imaginärteil von zn+1 ist: 2*a*b – cimag
Der Betrag dieser Zahl ergibt sich dann als Länge der Strecke vom Ursprung der Zahlenebene zu
diesem Punkt. Der Satz des Pythagoras liefert:
| zn+1 | = SQRT ( (a2 – b2 – cre)2 + (2*a*b – cimag)2
Nun können wir eigentlich anfangen, die Zahlenbene zu erforschen. Wo sollen wir suchen ?
Seite 11
2.3.1 Mandelbrotmenge - komplexe Zahlen
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
Wie oft sollen wir das Ergebnis wieder in die Rechnung einsetzen und wo soll die Grenze liegen,
für die wir annehmen, dass der Betrag nicht mehr divergiert ?
Der Bereich, der von Interesse ist, liegt um den Ursprung herum, das nehmen wir einfach so hin
und fragen Mandelbrot und Julia nicht, wie sie das herausbekommen haben.
Als Grenze für den (Betrag)2 nehmen wir vorerst den Wert 100 und gehen davon aus, dass alles,
was diese Grenze einmal überschritten hat, gegen unendlich divergiert. Bleibt noch die Anzahl
der Iterationen festzulegen. Hier werden wir ein wenig experimentieren.
Dazu brauchen wir ein kleines Applet. Da wir jedem Bildschirmpunkt, den wir verwenden wol-
len, einen Punkt in den Weltkoordinaten zuornden wollen, müssen wir diesmal eine Koordina-
tentransformation von den Gerätekoordianten in die Weltkoordinaten vornehmen. Zu einem
vorgegebenen Koordinatenpaar ( xG/ yG) muss der Punkt ( xW/yW ) in den Weltkoordinaten
berechnet weden. Der wird dann in die oben angegebene Rechnung eingesetzt , um festzustellen,
ob der Punkt ( xG / yG ) nun schwarz zu färben ist, oder nicht.
Für die Umrechnung gilt:
Dabei werden die Bezeichnungen verwendet, die schon oben erläutert sind.
Unser Applet soll einfach sein. Allerdings wollen wir ein wenig "Luxus" erlauben, indem es
möglich sein soll, mit der Maus in einem fertigen Bild einen Bereich auszuwählen, der dann ver-
größert dargestellt wird. Der Auswahlbereich wird immer quadratisch sein, da wir Verzerrungen
des Koordiantensystems nicht zulassen werden.
Im Appletfenster sollen auch einige Informationen über den gewählten Ausschnitt aus den Welt-
koordinaten zu sehen sein und auch die aktuelle Position der Maus - in Weltkoordinaten - soll
angegeben werden. Ein Klick auf einen Button soll dann die Berechnung in Gang setzen.
xW = ∆xW∆xG
⋅ ( xG – xGmin ) + xWmin
yW = ∆yW∆yG
⋅ ( yGmax – yG) + yWmin
2.3.1 Mandelbrotmenge - komplexe Zahlen
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
Seite 12
// Mandelbrot6.java// Mandelbrot6//// Created by HGB 14.12.2002
import java.awt.*;import java.applet.*;import java.awt.event.*;
public class Mandelbrot6 extends Applet implements ActionListener,MouseListener, MouseMotionListener
{ // Zuerst einige Layoutelemente Label Ueberschrift; Label xWminLabel,xWmaxLabel,yWminLabel,yWmaxLabel,MausXLabel,MausYLabel; TextField MausPosX,MausPosY; // Mausposition in Weltkoordinaten TextField xWminFeld,xWmaxFeld,yWminFeld,yWmaxFeld; Image myoffScreenImage; // Da zeichnen wir hinein Graphics myoffScreenGraphics; // der zugehörige Grafikkontext int xdown,ydown,xdrag,ydrag,xup,yup;// Mauskoordinaten für Mausevent double xWmintemp,yWmintemp,xWmaxtemp,yWmaxtemp,xWtemp,yWtemp;
// temporäre Werte int Breite; // für das Quadrat, das mit
// der Maus ausgewählt wird Button myButton1; // Der startet die Zeichenroutine double xW,yW; // die Weltkoordinaten int xG,yG; // die Gerätekoordinaten hier
// gleich als int
Es sollen sechs TextEditfelder mit entsprechenden Labels im Appletfenster zu sehen sein. DieNamensgebung spricht für sich. Um auf dem Bild mit der Maus ein Quadrat aufziehen zu kön-nen, das das Bild nicht "zerstört", werden wir im OffScreen malen und dann in der paint-Metho-de das OffScreenImage in den Grafikkontext hineinholen. Nun kommen feste Werte für die Gerätekoordinaten und Startwerte für die komplexe Zahlenebene.
final static int xGmin=40; final static int xGmax=550; final static int yGmin= 50; final static int yGmax=560; int deltaxG,deltayG; // ergeben sich dann aus den obigen Werten //............. Nun die Ränder der Welt(koordinaten)...................... double yWmin=-1.5; double yWmax=1.5; double xWmin=-1; double xWmax=2.0; double deltaxW,deltayW; // ergeben sich dann aus den obigen Werten boolean start=false; // der Starbutton ist anfangs nicht geklickt In der nachfolgenden Init-Methode werden die einzelnen Layoutelemente im Appletfenster posi-tioniert. Dabei wurde auf automatische Anpassungen an mögliche Größen von Browserfenstern
2.3.2 Mandelbrotmenge - Applet
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
Seite 13
verzichtet. Die Objektkoordinaten sind hier fest vorgegeben. Sollte der Bildschirm nicht groß ge-nug sein, mus man hier entsprechende Anpassungen vornehmen. Auch für xGmin, xGmax, yGmin und yGmax muss man eventuell eigenen Werte wählen.
//*****************************************************************// Werte initialisieren//***************************************************************** public void init() { setLayout (null);
myButton1= new Button("Zeichnen"); // Knopf mit Beschriftung myButton1.setForeground(Color.red); myButton1.setBounds(420,10,100,25); myButton1.addActionListener(this); // er bekommt einen Listener add(myButton1); // rein mit dem Knopf Ueberschrift=new Label(" Mandelbrotmenge ");//Überschrift Ueberschrift.setBounds(50,10,440,30); add(Ueberschrift);
// Label für die 4 Koordinatenwerte, die dann in Textfeldern neben die // Label gesetzt werden
xWminLabel=new Label("Reelle Achse: xmin "); xWminLabel.setBounds(40,570,100,20); // add(xWminLabel); xWmaxLabel=new Label("Reelle Achse: xmax "); xWmaxLabel.setBounds(300,570,100,20); add(xWmaxLabel); yWminLabel=new Label("Imag. Achse: ymin "); yWminLabel.setBounds(40,595,100,20); add(yWminLabel); yWmaxLabel=new Label("Imag. Achse: ymax "); yWmaxLabel.setBounds(300,595,100,20); add(yWmaxLabel);
// hier kommen die vier Textfelder
xWminFeld=new TextField(25); xWminFeld.setBounds(145,570,150,20); add(xWminFeld); xWmaxFeld=new TextField(25); xWmaxFeld.setBounds(405,570,150,20); add(xWmaxFeld); yWminFeld=new TextField(25); yWminFeld.setBounds(145,595,150,20); add(yWminFeld); yWmaxFeld=new TextField(25); yWmaxFeld.setBounds(405,595,150,20); add(yWmaxFeld);
// Nun noch zwei Label und Felder in denen die Weltkordinaten angezeigt // werden, wenn sich die Maus im Bild befindet -- siehe Mausevents unten
MausXLabel=new Label("Position der Maus x:");
2.3.2 Mandelbrotmenge - Applet
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
Seite 14
MausXLabel.setBounds(40,620,100,20); add(MausXLabel); MausYLabel=new Label("Position der Maus y:"); MausYLabel.setBounds(300,620,100,20); add(MausYLabel); MausPosX=new TextField(25); MausPosX.setBounds(165,620,130,20); add(MausPosX); MausPosY=new TextField(25); MausPosY.setBounds(425,620,130,20); add(MausPosY); xWminFeld.setText(" "+xWmin); // Werte in die Textfelder einsetzen xWmaxFeld.setText(" "+xWmax); yWminFeld.setText(" "+yWmin); yWmaxFeld.setText(" "+yWmax); MausPosX.setText("aktiv nach Mausklick"); MausPosY.setText("aktiv nach Mausklick");
// Jetzt werden aus den oben festgelegten Koordinaten die restlichen // Werte bestimmt
xW=xWmin; // Start beim kleinsten Wert yW=yWmin; deltaxW=xWmax-xWmin; // Auflösung in Realteil-Richtung deltayW=yWmax-yWmin; // Auflösung in Imaginärteil-Richtung deltaxG=xGmax-xGmin; // Auflösung Gerätekoordinaten deltayG=yGmax-yGmin; // Nun für das Zeichnen mi OffScreen - wie schon oft gehabt
myoffScreenImage=createImage(xGmax,yGmax); myoffScreenGraphics=myoffScreenImage.getGraphics();
addMouseMotionListener(this); // für die Mausevents addMouseListener(this);
MandelBrotMalen(); // Malt zum ersten Mal } // Ende von init
Schon am Ende von init wird hier zum ersten Male die Methode aufgerufen, die das erste Bildder Mandelbrotmenge mit den vorgegebenen Startwerten malt.In vielen Appletviewern und Browsern passiert dabei etwas Unerwartetes. Es erfolgt im Applet-window überhaupt erst eine Ausgabe, wenn init ganz abgearbeitet ist. Da das Malen der Man-delbrotmenge eine Weile dauert , sieht man also nichts . Auch die vorher definierten und mitdem add - Befehl plazierten Layoutelemente sieht man nicht. Also bitte nicht den Rechner verflu-chen, sondern etwas Geduld haben. In der paint-Methode wird die boolsche Variable "start" abgefragt. Sie kann nur den Wert true er-halten haben, wenn der Button geklickt wurde ( siehe weiter unten in actionPerformed ). Wenndas der Fall ist, wird ein eventuell vorhandenes weißes Quadtrat im XOR-Modus übermalt, danndie Mandelbrotmenge mit aktuellen Werten neu berechnet und das Ergebnis wird mitg.drawImage in den Grafikkontext herein kopiert.Im Falle von start==false, wird nur das Auswahlquadrat auf das Image gemalt. Das kann so oftwiederholt werden, wie man nicht den "Zeichnen"-Button klickt.
2.3.2 Mandelbrotmenge - Applet
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
Seite 15
//******************************************************// Die Paint- Methode ist eine sehr kurz// Wenn die boolschen Variablen passend stehen, wird// neu gerechnet oder das Ursprungsbild hineinkopiert//*******************************************************public void paint(Graphics g){if(start==true) // wenn Knopf für neues Bild geklickt.. { g.setXORMode(Color.white); // Weißes Rechteck löschen... g.drawRect(xdown,ydown,Breite,Breite); // durch Übermalen im XOR -Modus MandelBrotMalen(); // neu rechnen g.drawImage(myoffScreenImage,0,0,this); // fertiges Bild zeigen start=false; // erledigt ! } // Ende von if start==trueelse { g.drawImage(myoffScreenImage,0,0,this); // fertiges Bild zeigen g.setColor(Color.white); g.drawRect(xdown,ydown,Breite,Breite); // Rechteck malen }} // Ende von paint
public void update(Graphics g) { paint(g); }//**************************************************************// Nun die eigentliche Methode zum Berechnen der Menge//************************************************************** public void MandelBrotMalen() { int anzahl; // Anzahl der Iterationen deltaxW=xWmax-xWmin; // Auflösung in Realteil-Richtung neu berechnen deltayW=yWmax-yWmin; // Auflösung in Imaginärteil-Richtung neu berechnen
for (yG = yGmin; yG < yGmax; yG++) // ... entlang der imaginären Achse { for (xG = xGmin; xG < xGmax; xG++) // ... und dabei für alle x-Werte
// entlang der reellen Achse { // Berechne die zugehörigen Weltkoordinaten xW=(deltaxW/deltaxG)*(xG-xGmin)+xWmin; yW=(deltayW/deltayG)*(yGmax-yG)+yWmin; anzahl = pruefen(xW, yW); // Prüfe den Betrag in eigener Methode
// den Bildpunkt passend Färben im Graphicsobjekt g in der Methode malen malen(xG, yG,anzahl, myoffScreenGraphics); } } }// Ende von MandelBrotMalen In der Methode MandelBrotMalen werden zwei weitere Methoden benutzt. Die Methode pruefenstellt fest, nach wieviele Interationschritten der Betrag zu groß geworden ist, bzw. ob der Betragendlich bleibt.Die Methode malen übernimmt die Iterationszahl und legt eine von dieser Anzahl abhängige
2.3.2 Mandelbrotmenge - Applet
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
Seite 16
Farbe fest.//*******************************************************************************
int pruefen (double x, double y) { double tempX = 0, tempY = 0; // zwei temporäre Variablen double tempX2,tempY2; // zwei weitere Werte int i = 0; // der Zähler
do { i++; tempX2 = tempX*tempX - tempY*tempY - x; // Realteil der komplexen Zahl tempY2 = 2*tempX*tempY + y; // Imaginärteil der Zahl tempX=tempX2; tempY=tempY2; } while (((tempX*tempX + tempY*tempY) <= 5) && (i <200));
return i; // gibt i=200 zurück, wenn der Betrag nicht zu gross wird }
In der hervorgehobenen Zeile findet man an Stelle des Betrages das Quadrat des Abstandes, wasaber im Prinzip keinen Unterschied macht. Genauso findet man die Interationszahl i, die hier alsMaximalwert 200 zuläßt. Diese Werte kann und soll man verändern, um herauszufinden, welcheWirkungen das auf die berechnete Menge hat.
//*******************************************************************// Die Methode färbt die Punkte// Sinnvoll ist es die Mandelbrotmenge selbst schwarz zu färben. // Dann die Randpunkte,die nicht zur Menge gehören kontrastreich - z.B. Gelb.// Danach ist der Phantasie freier Raum gelassen. Es gibt Farberechnungen// mit Resten und dollen Formeln. Wir nehmen hier was simples grau in grau//******************************************************************* void malen (int x, int y,int zahl, Graphics g) { Color farbe; int itzahl; // Rechenschritte aus der Methode pruefen itzahl=zahl; // Hole Zahl von aussen if (itzahl ==200) farbe = Color.black; else if (itzahl>195) farbe = new Color(250,250,250); else if (itzahl>190) farbe = new Color(200,200,200); else if (itzahl>185) farbe = new Color(150,150,150); else if (itzahl>170) farbe = new Color(200-itzahl,200-itzahl,200-itzahl); else farbe = new Color(itzahl,itzahl,itzahl); g.setColor(farbe); g.drawLine(x, y, x, y); // Punkt anmalen }
In den Bildern , die noch folgen werden , sind nicht nur Graustufendarstellungen zu sehen, son-dern viele unterschiedliche Farbabstufungen. Probieren sie ein wenig herum. Es lohnt, im hohenBereich für die Werte von itzahl verschieden große Abstufungen zu probieren. Hier waren esFünferschritte. Probieren sie größere oder kleinere Intervalle.
In der Methode actionPerformed wird der Mausklick auf den Button "Zeichnen" verarbeitet.
2.3.2 Mandelbrotmenge - Applet
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
Seite 17
Die Werte für die Ränder der Weltkoordinaten werden auf den aktuellen Stand gebracht.Die Aktualität resultiert aus den sonstigen Mausevents, die noch bearbeitet werden müssen.
//*****************************************************************//// Nun kommt actionPerformed////*****************************************************************
public void actionPerformed(ActionEvent e) { Object welcherKnopf; // ein Objekt welcherKnopf=e.getSource(); //die Quelle des Ereignisses ist der Knopf if( welcherKnopf==myButton1)// Was sonst ? { start=true; xWmin=xWmintemp; xWmax=xWmaxtemp; yWmin=yWmintemp; yWmax=yWmaxtemp; xWminFeld.setText(" "+xWmin); // Werte in die Textfelder einsetzen xWmaxFeld.setText(" "+xWmax); yWminFeld.setText(" "+yWmin); yWmaxFeld.setText(" "+yWmax); repaint(); // paint aufrufen } }// Ende von actionperformed
In der Behandlung der Mausevents sind hier nun starke Vereinfachungen vorgenommen wor-den. Wir gehen davon aus, dass bei der Wahl einen neuen Bildschirmausschnittes der Benutzerfreundlicherweise das Rechteck von links oben nach rechts unten aufzieht und damit der ersteDruck auf die Maustaste die Werte für (xWmin/yWmax) festlegen soll. Wenn dann die Mausta-ste wieder losgelassen wird, ergeben sich daraus die Koordinaten (xWmax / yWmin) . FalscheMausbewegungen sind hier einfach nicht zugelassen. Das finden sie nicht benutzerfreundlich ?Ich auch nicht. Daher machen sie sich ruhig die Mühe, alle möglichen Methoden, ein Rechteckaufzuziehen zu erfassen und Fehler abzufangen.Immerhin erlauben wir hier, ein neues Rechteck aufzuziehen, wenn die erste Wahl nicht gefällt.Bestätigen wird man die Auswahl erst mit dem Klick auf den Button "Zeichnen".Ein kleine Raffinesse ist aber doch enthalten. Wenn wir ein 1: 1 Seitenverhältnis bei der Auswahlhaben wollen, müssen wir dafür sorgen, dass in jedem Falle ein Quadrat aufgezogen wird. Dasdarf aber nicht über die Bildgrenzen hinaus ragen. Daher wird als Breite des Quadrates die klei-nere Seite des Rechtecks gewählt, das der Benutzer oder die Benutzerin mit der Maus aufzieht.
2.3.2 Mandelbrotmenge - Applet
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
Seite 18
//************************************************************// Nun die Methoden für das Mausereignis alle müssen hinein//************************************************************
public void mouseEntered(MouseEvent e) { } // leer aber Pflichtveranstaltung public void mouseExited(MouseEvent e) { } // leer aber Pflichtveranstaltung public void mouseClicked (MouseEvent e) { } // leer aber Pflichtveranstaltung//************************************************// Mausknopf wird gedrückt ...//************************************************ public void mousePressed(MouseEvent e) { xdown=e.getX(); ydown=e.getY();
// zuerst abfragen, ob überhaupt im Bild geklickt wurde if((xdown<=xGmax)&&(xdown>=xGmin)&&(ydown<=yGmax)&&(ydown>=yGmin))
// wenn im Bild dann.... { xWmintemp=(deltaxW/deltaxG)*(xdown-xGmin)+xWmin; // könnte neune xWmin sein yWmaxtemp=(deltayW/deltayG)*(yGmax-ydown)+yWmin; // könnte neune yWmax sein
MausPosX.setText (" "+xWmintemp); // aktueller Mauswert x MausPosY.setText (" "+yWmaxtemp); // aktueller Mauswert y xWminFeld.setText(" "+xWmintemp); yWmaxFeld.setText(" "+yWmaxtemp); }// Ende von if } //************************************************// mit gedrückter Maustaste gezogen ....//************************************************ public void mouseDragged (MouseEvent e) { xdrag=e.getX(); ydrag=e.getY(); // wenn im Bild dann und in richtiger Richtung gezogen , dann.... if((xdrag<=xGmax)&&(xdrag>=xGmin)&&(ydrag<=yGmax)&&(ydrag>=yGmin)&&(xdrag>=xdown)&&(ydrag>=ydown)) { if((xdrag-xdown)>(ydrag-ydown)) // kleinste Rechteckseite finden { Breite=ydrag-ydown; xdrag=xdown+Breite; } else { Breite=xdrag-xdown; ydrag=ydown+Breite; } xWmaxtemp=(deltaxW/deltaxG)*(xdrag-xGmin)+xWmin; // aktuelle Werte
2.3.2 Mandelbrotmenge - Applet
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
Seite 19
yWmintemp=(deltayW/deltayG)*(yGmax-ydrag)+yWmin; // Werte in die Textfelder einsetzen xWmaxFeld.setText(" "+xWmaxtemp); yWminFeld.setText(" "+yWmintemp); repaint(); // Malt ein passendes weißes Rechteck auf den Bildschirm }// Ende von if }
//************************************************// und Maustaste wieder losgelassen....//************************************************ public void mouseReleased(MouseEvent e) { xup=xdrag; // der letzte Wert von mousedragged ist mouseup yup=ydrag; if((xup<=xGmax)&&(xup>=xGmin)&&(yup<=yGmax)&&(yup>=yGmin)) // wenn im Bild dann.... { xWmaxtemp=(deltaxW/deltaxG)*(xup-xGmin)+xWmin; yWmintemp=(deltayW/deltayG)*(yGmax-yup)+yWmin; xWmaxFeld.setText(" "+xWmaxtemp); yWminFeld.setText(" "+yWmintemp); } }// Ende von mouseReleased //***********************************************************// Nun eine Methoden, die der MouseMotionListener// fordert und die wir auch nutzen wollen//************************************************************
public void mouseMoved(MouseEvent e) { int xmove,ymove; xmove=e.getX(); ymove=e.getY(); if((xmove<=xGmax)&&(xmove>=xGmin)&&(ymove<=yGmax)&&(ymove>=yGmin)) // wenn im Bild dann.... { xWtemp=(deltaxW/deltaxG)*(xmove-xGmin)+xWmin; yWtemp=(deltayW/deltayG)*(yGmax-ymove)+yWmin; MausPosX.setText(" "+xWtemp); MausPosY.setText(" "+yWtemp); }// Ende von if } }// Ende von applet
Zweifellos schon ein recht ansehnliches Programm, das aber noch sehr viel Erweiterungen zu-
lässt. Es gibt - wie immer - ausgezeichnete Programme im Internet, aber wohl nur wenige mit ei-
nem ausführlich beschriebenen Quellcode. Sie können nach Herzenslust erweitern und verän-
2.3.2 Mandelbrotmenge - Applet
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
Seite 20
dern. Führen sie eine Klasse complex für komplexe Zahlen ein 4, die als Methoden die Re-
chenoperationen auf den komplexen Zahlen möglich macht, oder arbeiten sie mit mehreren Hin-
tergrundbildern, so das man ohne Neuberechnung zwischen den verschiedenen Auschnitten hin
- und herschalten kann.
Geben sie die Mandelbrotmenge als Facharbeit oder Langzeitarbeit an begeisterte Schülerinnen
und Schüler. Es eröffnet sich eine unglaubliche Vielfalt an Möglichkeiten für die Beschäftigung
mit dem Chaos, den Juliamengen, fraktaler Geometrie und anderen seltsamen mathematischen
"Lebewesen". Viel Spaß dabei !
Nun aber ein Blick auf mögliche Ergebnisse unseres kleinen Programms.
Wenn die Iterationszahl sehr klein ist , erhält man noch ein sehr grobes Bild. Mit zunehmender
Grenze der Iterationzahl i wird die Struktur immer deutlicher.
Schon bei i= 25 zeigt sich das sogenannte Apfelmännchen. Es hat diesen Namen angeblich von
Mathematikern der Universität Bremen bekommen, an der die Erforschung dieses Gebildes be-
sonders spektakulär betrieben wurde (H. O. Peitgen und P. Richter, Forschungsgruppe Komlpe-
xe Dynamik ).
4 siehe auch : Küchlin, Weber: Einführung in die Informatik S. 154 ff
Iterationszahl i= 5xWmin= -1 xWmax=2yWmin= -1,5 yWmax=1,5
2-farbig
Iterationszahl i= 25xWmin= -1 xWmax=2yWmin= -1,5 yWmax=1,5
2-farbig
2.3.3 Mandelbrotmenge - Beispiele
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
Seite 21
Schiebt man die Iterationszahl weiter nach oben, werden die Strukturen immer feiner.
Schon hier stellt sich die Frage, ob die Menge zusammenhängend ist, oder ob es Satelliten um
den Hauptkörper herum gibt, die keine Verbindung zu ihm haben.
Spannend wird es, wenn man sich darstellen lässt, nach wievielen Schritten die Punkte in der
Nähe der Menge die vorgegebene Grenze des Betrags überschreiten und dann gegen unendlich
divergieren. Man findet, dass die Menge eine große Anziehungskraft auf naheliegende Punkte
hat. Je näher ein Punkt der Menge liegt, desto "länger" dauert es, bis der Betrag zu groß wird und
damit der Punkt der Mandelbrotmenge "entkommt". Die Punkte die weiter weg liegen, haben es
da viel leichter, diesem Attraktor zu entkommen. Es muss Farbe her, um das darzustellen.
Im Folgenden sind passend gefärbte Ausschnitte des Randes der Mandelbrotmenge zu sehen.
Mit unserem Programm können wir uns immer tiefer in die feinsten Strukturen vorarbeiten, so-
lange die Rechengenauigkeit uns keinen Streich spielt.
2.3.3 Mandelbrotmenge - Beispiele
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
Seite 22
Iterationszahl i= 100xWmin= -1 xWmax=2yWmin= -1,5 yWmax=1,5
2-farbig
Iterationszahl i= 200xWmin= -1 xWmax=2yWmin= -1,5 yWmax=1,5
2-farbig
Seite 23
2.3.3 Mandelbrotmenge - Beispiele
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
Iterationszahl i= 100xWmin= -1 xWmax=2yWmin= -1,5 yWmax=1,5
10-farbig
Iterationszahl i= 100xWmin= 0,61176 xWmax=0,88823yWmin= 0,01764 yWmax=0,29411
10-farbig
Iterationszahl i= 100xWmin= 0,766262 xWmax=0,81613yWmin= 0,12173 yWmax=0,171603
10-farbig
Iterationszahl i= 100xWmin= 0,78220281 xWmax=0,79295976yWmin= 0,140408 yWmax=0,151365
10-farbig
Und noch einen Schritt weiter hinein:
Gegenüber dem Ausgangsbild ist dieser Aus-
schnitt etwa um den Faktor 1330 vergrößert.
Aber auch andere Stellen am Rand der Menge
oder ander Farbgebungen führen zu sehr schö-
nen Ergebnissen.
Seite 24
Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
Iterationszahl i= 100xWmin= 0,763307 xWmax=0,761048yWmin= 0,145533 yWmax=0,147792
10-farbig
2.3.3 Mandelbrotmenge - Beispiele
© Hans-Georg Beckmann 2004
Zum Abschluss ein Bild in Graustufen, das auch sehr reizvoll ist.
3. Transformationen in der Ebene
Bevor wir uns weiter mit Koordinatensystemen befassen, brauchen wir elementare geometrische
Transformationen im IR 2 . Ein wichtiges Hilfsmittel sind dabei Matrizen.
Definition:
Mit aik seien reelle Zahlen bezeichnet, wobei die Indizees i ∈ { 1, ......, n} und k ∈ { 1, ......, m}
natürliche Zahlen sind.
Dann heißt das Zahlenschema
eine Matrix über IR . Man sagt auch : ( α ik ) ist eine ( n,m ) Matrix mit dem Zeilenindex i und
dem Spaltenindex k.
Seite 25
3 Transformationen in der Ebene
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
( αik) =
a11 a12a21 a22
a1ma2m
an1 an2 anm
Ein Beispiel :
Das ist eine 3 x 3 - Matrix ( oder auch (3,3) - Matrix ). Hier ist z.B. a12 = – 3
Wichtig ist : Der erste Index gibt die Zeilennummer an und der zweite Index die Spaltennum-
mer.
Hinweis: Das Rechnen mit Matrizen stammt u.a aus der Behandlung Linearer Gleichungsysteme.
Wenn die Zahlen in der Matrix Koeffizienten aus einem solchen Gleichungssystem sind, dann
kann man mithilfe von Determinanten, die sich aus dieser Koeffizientenmatrix ergeben, die Glei-
chungssysteme lösen ( wenn sie denn lösbar sind ).
Wenn sie nicht Mathematiklehrerin oder Mathematiklehrer sind, haben sie jetzt möglicherweise
den Verdacht, dass nun alles ganz kompliziert wird. Das soll so nicht sein. Wenn sie weiter in
den mathematischen Teil eindringen möchten, dann gehen sie doch einfach einer Fachkollegin
oder einem Fachkollegen auf die Nerven und testen damit aus, was noch aus Studienzeiten in
Erinnerung gebleiben ist.
Uns interessiert eine Rechenoperation auf Matrizen, die Multiplikation.
Hat man zwei Matrizen (αik ) und ( βkj ), wobei Spaltenzahl von ( αik ) = Zeilenzahl von ( βkj ) ,
so gilt für die Multiplikation dieser beiden Matrizen:
Das muss an einem Beispiel verdeutlicht werden:
Man habe folgende zwei Matrizen:
Dann wird zuerst Zeile 1 von ( αik ) mit Spalte 1 von ( βkj ) paarweise multipliziert und dann
die Summe gebildet. Das ergibt eine Zahl für die Ergebnismatrix:
a11 ⋅ b11 + a12 ⋅ b21 + a13 ⋅ b31
wobei i = 1 ist und j von 1 bis 3 läuft und dabei k= 1 fest bleibt.
Seite 26
3.1 Matrizen
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
( αik) = a11 a12 a13a21 a22 a23a31 a32 a33
= 12 -3 0,51,2 – 4 07 0 – 1,7
( αik) ⋅ ( βkj ) = aik ⋅ bkj∑k = 1
m
( αik) = a11 a12 a13a21 a22 a23a31 a32 a33
(βkj ) = b11b21b31
b12b22b32
Nun muss die Rechnung für i= 2 und i= 3 genauso durchgeführt werden.
Insgesamt wird also die erste Spalte von ( βkj ) mit alle Zeilen von ( αik ) komponentenweise
multipliziert und die Produkte werden addiert. Sie ergeben die Zahlen in der ersten Spalte der
Ergebnismatrix. Dann wird die zweite Spalte von ( βkj ) genauso mit allen Zeilen von ( αik ) mul-
tipliziert und man erhält die zweite Spalte der Ergebnismatrix. Die Ergebnismatrix ist eine (2,3)-
Matrix.
Zur Verdeutlichung noch einmal als Zahlenbeispiel:
Man erkennt (hoffentlich) sofort, dass bei der Matrizenmultiplikation das Kommutativgesetz
nicht gilt.
In einem Koordinatensystem läßt sich ein Punkt durch seine Koordinaten angeben. Man schreibt
dann P(x,y), was bedeutet, dass der Punkt P die Koordinaten x und y hat. Man kann den Punkt P
aber auch durch einen Vektor vom Ursprung zum Punkt angeben. Man schreibt dann
Die Schreibweise (x,y) wird dann auch als die Zeilenschreibweise des
Vektors bezeichnet. Genauso kann man aber auch (x y) als eine 1x2-
Matrix auffassen.
Was passiert, wenn man diese 1x2-Matrix mit einer 2x2-Matrix multi-
pliziert ?
Es ergibt sich folgende Rechnung:
( x y) · = ( ax + cy bx + dy ) = ( x' y' )
Seite 27
Matrizenmultiplikation
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
a11 a12 a13
a21 a22 a23
a31 a32 a33
b11 b12
b21 b22
b31 b32
a11 . b11 + a12 . b21
a21 . b11 + a22 . b21
a31 . b11 + a32 . b21
+ a13
+ a23
. b31
. b31
+ a33 . b31
a11 . b12 + a12 . b22
a21 . b12 + a22 . b22
a31 . b12 + a32 . b22
+ a13
+ a23
. b32
. b32
+ a33 . b32
=
1 4 5
2 0 4
3 3 6
5 3
1 8
5 2
1 . 5 + 4 . 1
2 . 5 + 0 . 1
3 . 5 + 3 . 1
+ 5
+ 4
. 5
. 5
+ 6 . 5
1 . 3 + 4 . 8
2 . 3 + 0 . 8
3 . 3 + 3 . 8
+ 5
+ 4
. 2
. 2
+ 6 . 2
= =34 45
30 14
48 45
OP = xy
x
y
P (x,y)
OP = ( )xy
Oa b
c d
Damit hat man einen neuen Punkt im Koordinatensystem mit den Koordinaten ( x' y').
Ein Beispiel:
( 2 2 ) · = ( 2·1 + 2·3 2·0 + 2·2 ) = ( 8 4 )
Nun hängt es von der Wahl der Zahlen in der Matrix ab, was mit einem Punkt ( oder mit mehre-
ren Punkten) passiert. Es ergeben sich folgenden elementare geometrische Transformationen:
1. Identität ( x y) · = ( 1x + 0y 0x + 1y ) = ( x y )
2. Skalierung
2a in x-Richtung:
( x y) · = ( a·x + 0·y 0·x + 1·y ) = ( a·x y )
2b in y-Richtung:
( x y) · = ( 1·x + 0·y 0·x + d·y ) = ( x d·y )
2c in beide Richtungen:
( x y) · = ( k·x + 0·y 0·x + k·y ) = (k· x k·y )
3. Spiegelung
3a an der y-Achse
( x y) · = ( -1·x + 0·y 0·x + 1·y ) = ( – x y )
3b an der x-Achse
( x y) · = ( 1·x + 0·y 0·x +(- 1)·y ) = ( x – y )
3c Punktspiegelung am Ursprung
( x y) · = ( -1·x + 0·y 0·x +(- 1)·y ) = ( – x – y )
Seite 28
3.2 Vektoren und 2x2 Matrizen, 3.3 Transformationen
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
1 0
3 2
1 0
0 1
a 0
0 1
1 0
0 d
k 0
0 k
-1 0
0 1
1 0
0 -1
-1 0
0 -1
4. Scherung
4a in y-Richtung
( x y) · = ( 1 · x + 0 · y k · x + 1 · y ) = (k· x y )
4b in x-Richtung
( x y) · = ( 1 · x + k · y 0 · x + 1 · y ) = (x + k·y y )
5. Rotation
( x y) · = ( x· cos ϕ – y · sin ϕ x · sin ϕ + y · cos ϕ)
das entspricht einer Drehung gegen den Uhrzeigersinn um den Winkel ϕ.
Das bedarf einer kleinen mathematischen Erläuterung. Es gilt :
( 1 0 ) · = (a b ) und ( 0 1 ) · = ( c d )
Das bedeutet, dass die erste Zeile der Matrix angibt, wie der
Punkt ( 1 0 ) verändert wird, und die zweite Zeile der Matrix
diese Veränderung für den Punkt ( 0 1 ) zeigt. Dreht man in
einem Koordinatensystem den Punkt ( 1 0 ) von der x-Achse
weg gegen den Uhrzeigersinn um den Winkel ϕ, dann be-
kommt man einen neuen Punkt im Koordinatensystem , der die
Koordinaten ( cos ϕ sin ϕ ) hat.
Entsprechend kann man den Punkt ( 0 1 ) um den Winkel ϕ
drehen und erhält einen Punkt mit den Koordinaten
( – sin ϕ cos ϕ ). Damit ist die oben angegebene Matrix ein we-
nig erklärt.
Nun bleibt die Frage, ob unsere Abbildungsmatrix "schlau" ist
und auch nichts verkehrt gerechnet wird.
Nach dem, was wir aufgelistet haben,
muss die nebenstehende Matrix eine Ska-
cos ϕϕϕϕ sin ϕϕϕϕ
– sin ϕϕϕϕ cos ϕϕϕϕ
Seite 29
3.3 Transformationen
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
1 k
0 1
1 0
k 1
a b
c d
a b
c d
x
y
(1 , 0 )O
1
ϕ
cos ϕ
sin
ϕ
x
y
(0 , 1 )
O
ϕ
cos
ϕ
– sin ϕ 0,5 0
0 1
lierung um den Faktor 0,5 in x-Richtung bewirken. Kann man die Zahlen nicht auch als Werte
für die Drehung auffassen ? Dann wäre cos ϕ = 0, 5 was ϕ = 30 ° ergibt und sin ϕ = – sin ϕ = 0 be-
deutet 0° und der Widerspruch taucht auf, wenn die Zahl d in der Matrix dem cos ϕ entspre-
chen soll. Denn jetzt wäre cos ϕ = 1 und damit ϕ = 0°. Wir rechnen das an einem Beispiel nach.
Man habe ein Quadrat mit den Koordinaten P1 (0/0), P2 (3/0), P3 (3/3 ) und P4 (0/3).
Dann ergeben sich die neuen Koordinaten wie folgt:
( 0 0 ) · = (0 0 ) ( 3 0 ) · = (1,5 0 )
( 3 3 ) · = (1,5 3 ) ( 0 3 ) · = ( 0 3 )
Wenn nun die Matrix geändert wird , so dass die Winkelfunkti-
ons Werte für ϕ = 30° auftreten, dann sieht die Rechnung etwas
anders aus:
( 0 0 ) · = (0 0 )
( 3 0 ) · = ( 2,598 1,5)
( 3 3 ) · = (1,098 4,098 )
( 0 3 ) · = ( -1,5 2,598)
Es klappt offensichtlich gut. Dennoch gibt es ein Problem, das weitere Überlegungen erforderlich
macht. Wenn man die Rechnung noch einmal an einem weiteren Beispiel durchführt, wird sich
zeigen, dass die Verschiebung ( Translation ) ein Abbildung ist, die wir bis jetzt eher ungewollt
erzeugen. Man habe diesmal ein Quadrat, das nicht mit einer Ecke bei (0 / 0 ) liegt und die Ma-
trix, die eine Skalierung in beide Richtungen um den Faktor 2,5 besorgt .
Seite 30
3.3 Transformationen
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
0,5 0
0 1
0,5 0
0 1
0,5 0
0 1
0,5 0
0 1
3
2
1
1 2 3 4
3
2
1
-2 -1
-1
1
-2
2 3
0,866 0.5
-0,50 0,866
0,866 0.5
-0,50 0,866
0,866 0.5
-0,50 0,866
0,866 0.5
-0,50 0,866
( 2 1 ) · = ( 5 2,5 )
( 2 2 ) · = ( 5 5 )
( -1 2 ) · = (-2,5 5 )
( -1 1 ) · = (-2,5 2,5 )
Wie man sieht, ist das Rechteck, das durch die Abbildung entsteht, nicht nur - wie erwartet - grö-
ßer, sondern auch verschoben. Das ist anschaulich vollkommen in Ordnung, denn wenn man
sich vorstellt, dass man sich z.B, zwei weit entfernten Gebäuden nähert, dann erscheinen nicht
nur diese Gebäude beim Näherkommen größer, sondern auch der Abstand zwischen ihnen. So
ist es auch hier. Der Abstand der Eckpunkte zu den Achsen oder zum Ursprung vergrößert sich
in dem Maße, in dem auch das Rechteck vergrößert wird. Zeichnet man die Vektoren vom Ur-
sprung aus durch die Ecken des Originalrechtecks bis zu den Ecken des neuen Rechtecks, dann
erkennt man Abbildung als zentrische Streckung.
Um eine Tranlation mithilfe einer Matrix durchführen zu können, werden nun einige Änderun-
gen vorgenommen.
Zu jede Punkt (X,Y) aus der Ebene wird ein Tripel ( P, Q, R) gebildet mit X= P/R und Y = Q/R.
Z.B. könnte für den Punkt ( 2 , 5 ) das Tripel ( 10, 25, 5 ) sein, denn mit R=5 ist dann X = 2 = 10/R
und Y = 5 = 25/R . R könnte aber auch jede andere beliebige Zahl sein. Der Einfachheit halber
nehmen wir R=1 , so dass aus einem Punkt (X,Y) das Tripel (X, Y, 1 ), das den Punkt jetzt als Zei-
lenvektor mit drei Komponenten darstellt. Damit wird nun auch die Matrix für die Abbildung
eine 3x3-Matrix werden.
Nach den Rechenregeln, die wir für Matrizen behandelt haben, kann man nun schnell sehen,
was eine Multiplikation von ( X, Y, 1 ) mit einer passenden Transformationsmatrix bewirkt:
Seite 31
3.3 Transformationen
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
5
4
3
-4 -3 -2 -1
2
1
-1
1 2 3 4
2,5 0
0 2,5
2,5 0
0 2,5
2,5 0
0 2,5
2,5 0
0 2,5
( X Y 1 ) · = (a · X + c · Y + h b · X + d · Y +v 1 ) = ( X' Y' 1 )
Die dritte Spalte in der Matrix ist immer gleich. Jetzt kann man aber durch die Größen h und v
die horizontale und vertikale Verschiebung vornehmen. Die Darstellung ( X Y 1 ) nennt man
auch die homogene Koordinatendarstellung. Die Matrizen, die man für die Skalierung, Translation
und Rotation verwendet werden auch oft in einer Kurzschreibsweise angegeben, die das Lesen
etwas erleichtert. 5
Mit dieser kompakten Schreibweise bedeutet dann z.B. P' = P · R(30°), dass der Punkt P' aus dem
Punkt P hervorgeht, indem P mit der Drehmatrix R(30°) multipliziert wird.
Man kann nun verschiedene Transformationen nacheinander anwenden, und muss dabei nur be-
achten , dass die Matrizenmultiplikation nicht kommutativ ist. Damit ist also beispielsweise
R(30°) · T( -2, 3) ≠ungleich T( -2, 3) · R(30°)
Betrachten wir noch einmal das Problem, dass bei einer Skalierung außer dem Fixpunkt alle
Punkte auch verschoben werden. Will man eine Skalierung mit einem anderen Fixpunkt als (0,0),
und sei dieser Fixpunkt ( Zx ,Zy ), dann muss man zuerst eine Translation T(-Zx,-Zy) ,dann die
Skalierung S (a, d ) und dann eine Translation T( Zx, Zy) vornehmen. Insgesamt also eine Multi-
plikation von drei Matrizen .6
5
W.D.Fellner, Computergrafik, BI-Wissenschaftsverlag , Seite 150 ff6
W.D.Fellner, Computergrafik, BI-Wissenschaftsverlag , Seite 157
Seite 32
3.4 homogene Koordinaten
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
a b 0
c d 0
h v 1
1 0 0
0 1 0
h v 1
= T ( h, v) eine Matrix, die nur Verschiebung bewirkt
a 0 0
0 d 0
0 0 1
= S ( a, d) eine Matrix, die nur Skalierung bewirkt
cos ϕϕϕϕ sin ϕϕϕϕ 0
– sin ϕϕϕϕ cos ϕϕϕϕ 0
0 0 1
= R (ϕ) eine Matrix, die nur Drehung bewirkt
Bevor wir alles in einem Javaprogramm ausprobieren wollen, noch einmal eine größere Beispiel-
rechnung.
Man könnte aus den vorangegangenen Seiten vermuten, dass es sofort möglich ist, eine Trans-
formationsmatrix anzugeben, die mehrere Abbildungen zusammenfasst. Wenn man aber be-
denkt, dass etwa eine Drehung und eine Skalierung auf dieselben Komponenten der Matrix zu-
rückgreifen, dann muss man sich das doch etwas genauer anschauen.
Zuerst in Einzelschritten:
Das Quadrat mit den Eckpunkten P1(0,0) , P2(1,0) , P3 (1,1) und P4 (0,1) ist bestimmt langweilig
aber für schwache Kopfrechner bestens geeignet.
Schritt 1: Verschiebung um 1 in x-Richtung und um 2 in y-Richtung entspricht T(1,2)
Schritt 2: Skalierung um den Faktor 2 in x-Richtung entspricht S(2,1). Gerechnet wird mit den
oben ermittelten Punkten:
Schritt 3: Drehung um 90° entspricht R(90°)
Seite 33
3.4.1 Beispielrechnungen
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
1 0 0
0 1 0
1 2 1
( 0,0,1 ) · = ( 1 , 2 , 1 ) = P1' ( 1,0,1 ) · = ( 2 , 2 , 1 ) =P2'
1 0 0
0 1 0
1 2 1
( 1,1,1 ) · = ( 2 , 3 , 1 ) = P3'
1 0 0
0 1 0
1 2 1
( 0,1,1 ) · = ( 1 , 3 , 1 ) = P4'
2 0 0
0 1 0
0 0 1
( 1,2,1 ) · = ( 2 , 2 , 1 ) = P1'' ( 2,2,1 ) · = ( 4 , 2 , 1 ) =P2''
2 0 0
0 1 0
0 0 1
( 2,3,1 ) · = ( 4 , 3 , 1 ) = P3''
2 0 0
0 1 0
0 0 1
( 1,3,1 ) · = ( 2 , 3 , 1 ) = P4''
1 0 0
0 1 0
1 2 1
2 0 0
0 1 0
0 0 1
0 1 0
-1 0 0
0 0 1
(2,2,1 ) · = ( -2 , 2 , 1 ) = P1''' ( 4,2,1 ) · = ( -2 , 4 , 1 ) =P2'''
0 1 0
-1 0 0
0 0 1
( 4,3,1 ) · = ( -3 , 4 , 1 ) = P3'''
0 1 0
-1 0 0
0 0 1
(2,3,1 ) · = (-3 , 2 , 1 ) = P4'''
0 1 0
-1 0 0
0 0 1
Die Matrix, die alles zusammen abbgebildet
hätte, ist T(1,2) · S(2,1) · R(90°) . Da das Assozia-
tivgesetz gilt, rechnen wir zuerst
und dann:
Nun prüfen wir das Ergebnis noch einmal:
Es wird also, deutlich, dass es sinnvoll ist, zuerst alle Transformationen mit den Matrizen durch-
zurechnen und erst am Ende die Ergebnismatrix auf die Punkte anzuwenden. Genauso ist klar
geworden, dass die Ergebnismatrix nicht mit "einem Blick" aus der Angabe der gewünschten
Transformationen zu erkennen ist. Abbildungen der geschilderten Art heißen affine Abbildungen
und kommen in der analytischen Geometrie und linearen Algebar häufig ( auch im Schulunter-
richt ) vor.
Am Ende dieser mathematischen Betrachtungen muss noch erwähnt werden, dass es auch eine
etwas andere Darstellung gibt, die nur die Reihenfolge der Multiplikation vertauscht. Stellt man
die Koordinaten eines Punktes in ihrer homogenen Form als Spaltenvektor dar, und stellt bei der
Multiplikation die Transformationsmatrix voran, dann bekommt man:
Die beiden Zahlen für die Translation stehen jetzt in den ersten beiden Zeilen am Ende.
Seite 34
3.4.1 Beispielrechnungen
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
5
4
3
-4 -3 -2 -1
2
1
-1
1 2 3 4
T(1,2)
R(90°)
1 0 0
0 1 0
1 2 1
2 0 0
0 1 0
0 0 1
=2 0 0
0 1 0
2 2 1
2 0 0
0 1 0
2 2 1
0 1 0
-1 0 0
0 0 1
=0 2 0
-1 0 0
-2 2 1
0 2 0
-1 0 0
-2 2 1
(0,0,1 ) · = ( -2 , 2 , 1 ) = P1''' ( 1,0,1 ) · = ( -2 , 4 , 1 ) =P2'''
0 2 0
-1 0 0
-2 2 1
( 1,1,1 ) · = ( -3 , 4 , 1 ) = P3'''
0 2 0
-1 0 0
-2 2 1
(0,1,1 ) · = (-3 , 2 , 1 ) = P4'''
0 2 0
-1 0 0
-2 2 1
a b h
c d v
0 0 1
X
Y
1
X'
Y'
1
=
S(2,1)
3.4.2 Ein Beispielapplet für die affinen Abbildungen
Im folgenden Programm sollen die Transformationsmatrizen angewendet werden. Wir werden
für jede der Grundabbildungen eine Matrix vordefinieren, und sie dann auf ein Objekt anwen-
den. Es läge nahe, der Einfachheit halber nur im Gerätekoordinatensystem zu arbeiten, das nur
ganzahlige Koordinaten kennt. Dort kann man mit Instanzen der Klasse Polygon arbeiten, die
auch nur ganze Zahlen kennt. Der Nachteil ist, dass wir z.B. bei der mehrfachen Anwendung ei-
ner Rotationsmatrix, in der keine ganzen Zahlen stehen werden, ein Aufschaukeln der Run-
dungsfehler befürchten müssen. Zudem müssen wir in jedem Falle eine Anpassung des Geräte-
koordinatensystems vornehmen, in dem wir den Ursprung in die Mitte des Bildschirms legen.
Da können wir auch gleich alle Berechnungen in den Weltkoordinaten mit Zahlen vom Typ float
vornehmen und erst am Ende die passenden Bildschirmkoordinaten berechnen lassen. Das be-
deutet dann aber auch, dass wir die Klasse Polygon in den Weltkoordinaten nicht verwenden
können. Im Prinzip werden die verschiedenen Koordinaten nach folgendem Schema verarbeitet.
Um alle Berechnungen durchführen zu können, werden zwei Klassen definiert:
In der Klasse Matrix werden 3x3 Matrizen verwaltet. Die Zahlenwerte stehen in einem zweidi-
mensionalen Feld. Der Konstruktor ohne Parameter erzeugt eine Einheitsmatrix, die auf der Dia-
gonalen nur "1" enthält und sonst "0".
Der zweite Konstruktor setzt die relevanten Zahlenwerte
gleich in die Matrix ein und lässt die 3. Spalte auf den Stan-
dardwerten ( 2 mal die "0" und eine "1" ).
reset erzeugt wieder die Einheitsmatrix. setScale, setTrans und
setRot setzen die Werte für die Transformationen an den pas-
senden Stellen in der Matrix ein. malPunkt und malMatrix füh-
ren eine Matrizenmultiplikation mit dem entsprechenden Er-
gebnis durch.
Die zweite Klasse, mit der wir arbeiten ist WPunkt, wodurch
ein Punkt in den Weltkoordinaten in der homogenen Darstel-
Seite 35
3.4.2 Beispielapplet
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
( xW , yW ) Matrix ( xW', yW') ( xG , yG )umrechnen
Matrix+ werte : float[3] [3]
<< Konstruktor >>
+ Matrix ( )+ Matrix ( a: float, b:float, c:float
d:float, h:float, v:float )<< Methoden >>
+ reset( )
+ setScale ( sx: float, sy:float )
+ setTrans ( tx: float, ty:float )
+ setRot ( winkel:int )
+ malPunkt ( p: WPunkt )
+ malMatrix ( m : Matrix )
lung angegeben wird. Die Klasse bekommt vorerst keine Methoden.
Der Konstruktor ohne Parameter erzeugt den Punkt (0,0,1).
Wir werden für unsere Grafik wieder die schon bekannten Grenzen
für das Window ( Weltkoordinaten ) und den Viewport ( Geräteko-
ordinaten ) festlegen. Das Objekt, das wir mit affinen Abbildungen
bearbeiten wollen, soll nicht zu kompliziert sein, daher nehmen wir
mal das klassische Monopolyhotel auf der Schlossallee.
Es soll am Anfang in der Mitte des Windows plaziert werden und
dann soll man alle möglichen Transformationen darauf anwenden
können.
Für spätere Erweiterungen schaffen wir uns dazu eine Klasse Figur,
die einem Polygon entspricht. Jedoch werden hier die Eck-
punkte nicht als ganze Zahlen gespeichert sondern als
Wpunkt bzw. als Werte vom Typ float.
Man könnte dieser Klasse auch gleich eine Methode
drawFigur hinzufügen. Hier wird darauf verzichtet, weil es
etwas unübersichtlich wird, da diese Methode ja mit allen
Parametern bestückt werden muss, die zur Umrechnung
der Weltkoordinaten in Gerätekoordinaten nötig sind.
Das nachfolgende Programm ist nicht in allen Einzelheiten
angegeben, da sicher viele Dinge , wie z.B. die Platzierung
von Layoutelementen , problemlos erledigt werden können und keiner weiteren Erläuterung
mehr bedürfen.
// Matrizen3// Created by Hans-Georg Beckmann on Sun Dec 29 2002.// Nun alle Standarstransformationsmatrizen und Weltkoordinaten
import java.awt.*;import java.applet.*;import java.awt.event.*; // falls man etwas mit Buttons machen möchte
Man lege sich am Anfang Matrizen für Translation (T), Rotation (R), Sklaierung (S) und das Er-
gebnis der Matrizenoperationen (M1) fest.
public class Matrizen3 extends Applet {
Seite 36
3.4.3 Klassen für das Applet
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
WPunkt+ werte : float[3]
<< Konstruktor >>
+ WPunkt ( )
+ WPunkt ( x: float, y:float )
Figur
+ ecken : WPunkt[]
+ anzahl : int
+ xecken: float[]
+ yecken:float[]
<< Konstruktor>>
+Figur (eckpunkte:WPunkt[])
<< Methoden >>
+ malMatrix ( m:Matrix)
Matrix M1 = new Matrix();Matrix T = new Matrix();Matrix S = new Matrix();Matrix R = new Matrix();
WPunkt[] Hausecken = new WPunkt[6]; // Hier die FigureckenFigur Haus; // aus denen dann die Figur wird
Aus dem Programm "Funktionsplotter" und den Mandelbrotmengen kennt man die Variablen
für Welt - und Gerätekoordinaten schon.
final static int xGmin =40;final static int xGmax =440;final static int yGmin = 40;final static int yGmax =540;final static int deltaxG=400;final static int deltayG=400;float xWmin =-25;float xWmax =25;float yWmin =-25;float yWmax =25;float xW,yW,deltaxW, deltayW; // die Welt-Koordinaten und Auflösungenint xG,yG; // die zugehöringen Gerätekoordinatenfloat dx;
In der Methode init werden die nötigen Größen für die Koordinatentransformation festgelegt
und dann weitere Festlegungen getroffen:
public void init() {
.............
............ Hausecken[0]=new WPunkt(0,0); Hausecken[1]=new WPunkt(6,0);
Hausecken[2]=new WPunkt(6,2); Hausecken[3]=new WPunkt(4,2); Hausecken[4]=new WPunkt(2,3); Hausecken[5]=new WPunkt(0,2); Haus=new Figur(Hausecken);
Nun kann man hier schon die Matrizen festlegen, wenn man die nicht während des Pro-
grammablaufes ändern will. Es könnte z.B. wie folgt aussehen:
T.setTrans(4,2); // 4 in x-Richtung , 2 in y-Richtung S.setScale(2,2); // Skalierung um den Faktor 2 R.setRot(10); // Rotation um 10 Grad ............... }
In der paint-Methode wird eine Methode Figurmalen aufgerufen, die weiter unten noch kommt.
Die Klasse Matrix funktioniert so gut, dass man die Matrizenmultiplikation geschachtelt durch-
Seite 37
Programmtext - init
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
führen kann. Will man etwa das Haus erst rotieren, dann skalieren und am Ende verschieben,
dann wäre der "normale" Weg: M1= M1.malMatrix(R);
M1= M1.malMatrix(S);
M1= M1.malMatrix(T);
Das geht aber auch in einer Zeile. M1=M1.malMatrix(T.malMatri(S.malMatrix(R)));
public void paint (Graphics g) { Figurmalen( Haus ); // Original zeichnen M1=M1.malMatrix(T.malMatrix(S.malMatrix(R))); Haus=Haus.malMatrix(M1); // Die Matrix auf die ganze Figur anwenden (s.u) Figurmalen(Haus); // neues Haus zeichnen }// Ende von paint
In der folgenden Methode wird aus den Punkten der Figur in den Weltkoordinaten (im Window)
ein Polygon in den Gerätekoordinaten (Viewport ).
public void Figurmalen ( Figur f ){
Polygon internPoly=new Polygon(); // neues leeres Polygonint eckenzahl;Graphics g;
eckenzahl=f.ecken.length; // Anzahl der Ecken der Figurfor (int i=0;i<eckenzahl;i++){
xW=f.ecken[i].x;yW=f.ecken[i].y;xG=xGmin+(int)Math.round((1/dx)*(xW-xWmin));yG=yGmax-(int)Math.round((deltayG/deltayW)*(yW-yWmin));internPoly.addPoint(xG,yG);
} // Ende von for Eckenzahl, Polygon fertig
g=getGraphics();g.drawPolygon(internPoly); // Zeichne das Polygon
Zum Umgang mit Polygonen siehe auch "Goto Java S.480 ff
Man kann sich auch einige Werte zur Kontrolle ausgeben lassen, wenn das nötig ist.
// Nun zu Kontrollzwecken die Koordinatenausgeben lassenfor (int i=0;i<eckenzahl;i++)g.drawString(" "+internPoly.xpoints[i]+" "+internPoly.ypoints[i], 100, 200+i*15);
}// Ende von Figurmalen
Die wichtigste Klasse ist Matrix. Sie hat zwei Konstruktoren. Der erste erzeugt eine Einheitsma-
Seite 38
Programmtext - paint
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
trix. Das ist die Matrix, die nichts ändert, wenn mit ihr multipliziert wird.
Der Zweite ermöglicht es, die 6 wichtigen Werte anzugeben, die man für Transformationen
braucht. Wir werden diese Werte aber durch die Methoden setScale, setTrans, setRot und malMa-
trix festlegen. Das man aber z.B. auch eine Möglichkeit zum Spiegeln braucht, ist dieser zweite
Konstruktor sinnvoll.
//*******************************************// Die Klasse für die 3x3 Matrizen//*******************************************
public class Matrix{float[][] werte = new float[3][3];
//*************************** die Konstruktoren *******************************// Zuerst der Konstruktor, der eine Einheitsmatrix erzeugtpublic Matrix(){for (int i= 0;i<3;i++) for (int j=0;j<3;j++) { if (i==j) {this.werte[i][j]=1;} else {this.werte[i][j]=0;} } }// Ende von Konstruktor 1
// nun der Konstruktor, der die Matrix mit speziellen Werten füllen kann
public Matrix (float a, float b, float c, float d, float h, float v){
werte[0][0]=a;werte[0][1]=b;werte[0][2]=0;werte[1][0]=c;werte[1][1]=d;werte[1][2]=0;werte[2][0]=h;werte[2][1]=v;werte[2][2]=1;
}// Ende von Konstruktor 2
//********************************** METHODEN ***********************************public void reset(){for (int i= 0;i<3;i++) for (int j=0;j<3;j++) { if (i== j) {this.werte[i][j]=1;} else {this.werte[i][j]=0;} } }// Ende von reset
public void setScale(float sx, float sy){
this.reset();werte[0][0]= sx;werte[1][1]= sy;
}// Ende von setScale
public void setTrans (float tx,float ty)
Seite 39
Programmtext -die Klassen
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
{this.reset();werte[2][0]= tx;werte[2][1]= ty;
} // Ende von setTrans
public void setRot( int winkel ) // Winkel als Integer-Wert{
double bogen;bogen= Math.PI*winkel/180;this.reset();werte[0][0]=(float)Math.cos(bogen);werte[0][1]=(float)Math.sin(bogen);werte[1][0]=(float)(-Math.sin(bogen));werte[1][1]=(float)Math.cos(bogen);
}// Ende von setRot
//****************** nun die Multiplikationen Punkt · Matrix und Matrix · Matrix
public WPunkt malPunkt(WPunkt p){
WPunkt ergebnis= new WPunkt(); // Neuer Punktergebnis.x=werte[0][0]*p.x+werte[1][0]*p.y+werte[2][0];ergebnis.y=werte[0][1]*p.x+werte[1][1]*p.y+werte[2][1];ergebnis.z=1;return ergebnis; // raus mit dem neuen Punkt
}// Ende von malPunkt
Die folgende Methode läßt sich mit vielen geschachtelten for-Schleifen sehr viel kürzer fassen.Hier die lang(weilige) Fassung
public Matrix malMatrix(Matrix m) // m wird rechts dran multipliziert{Matrix ergebnis= new Matrix();ergebnis.werte[0][0]=this.werte[0][0]*m.werte[0][0]+this.werte[0][1]*m.werte[1][0]+this.werte[0][2]*m.werte[2][0];ergebnis.werte[1][0]=this.werte[1][0]*m.werte[0][0]+this.werte[1][1]*m.werte[1][0]+this.werte[1][2]*m.werte[2][0];ergebnis.werte[2][0]=this.werte[2][0]*m.werte[0][0]+this.werte[2][1]*m.werte[1][0]+this.werte[2][2]*m.werte[2][0];
ergebnis.werte[0][1]=this.werte[0][0]*m.werte[0][1]+this.werte[0][1]*m.werte[1][1]+this.werte[0][2]*m.werte[2][1];ergebnis.werte[1][1]=this.werte[1][0]*m.werte[0][1]+this.werte[1][1]*m.werte[1][1]+this.werte[1][2]*m.werte[2][1];ergebnis.werte[2][1]=this.werte[2][0]*m.werte[0][1]+this.werte[2][1]*m.werte[1][1]+this.werte[2][2]*m.werte[2][1];
ergebnis.werte[0][2]=this.werte[0][0]*m.werte[0][2]+this.werte[0][1]*m.werte[1][2]+this.werte[0][2]*m.werte[2][2];ergebnis.werte[1][2]=this.werte[1][0]*m.werte[0][2]+this.werte[1][1]*m.werte[1][2]+this.werte[1][2]*m.werte[2][2];ergebnis.werte[2][2]=this.werte[2][0]*m.werte[0][2]+this.werte[2][1]*m.werte[1][2]+this.werte[2][2]*m.werte[2][2];
return ergebnis;
}// Ende von malMatrix
Seite 40
Programmtext - die Methoden
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
}// Ende von Klasse Matrix
Nun noch die Klassen für Punkte und Figuren in den Weltkoordinaten.
//*******************************************// Die Klasse für die Punkte im Window//*******************************************public class WPunkt{
float x;float y;float z=1;
//************************** Konstruktoren **************************public WPunkt() // Standarpunkt (0,0,1)
{ x=0;y=0;z=1;}public WPunkt(float xx, float yy)
{ x=xx; y=yy;z=1;}}//***************************** Ende von Klasse WPunkt *************
//*******************************************// Die Klasse für Figur im Window//*******************************************public class Figur{
WPunkt[] ecken;int anzahl;float[] xEcken,yEcken;
//******************************** Konstruktor **********************public Figur(WPunkt[] eckpunkte){
anzahl=eckpunkte.length;xEcken=new float[anzahl];yEcken=new float[anzahl];for ( int i=0;i< anzahl;i++){
xEcken[i]=eckpunkte[i].x;yEcken[i]=eckpunkte[i].y;
}
ecken=new WPunkt[anzahl];for ( int i=0;i< anzahl;i++)
{ecken[i] = new WPunkt(xEcken[i],yEcken[i]);}}// Ende von Konstruktor
Die folgende Methode wendet nun eine Matrix m auf alle Eckpunkte einer Figur an und gibt als
Ergebnis die neuberechnete Figur zurück. Bequemer geht es kaum noch.
public Figur malMatrix(Matrix m)
{WPunkt[] hilfspunkte = new WPunkt[anzahl]; // neue PunkteFigur hilfsfigur; // Für die berechneten Punkte
Seite 41
Programmtext - die Methoden
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
for (int i=0; i< anzahl;i++){hilfspunkte[i]=m.malPunkt(this.ecken[i]); // nimm den aktuellen Eckpunkt
// mit Matrix m mal}// Ende von forhilfsfigur=new Figur(hilfspunkte);return hilfsfigur;
}// Ende von malmatrix
}// Ende von Figur
} // Ende von Applet
Wenn man sich nicht ganz sicher ist, ob es klappt, dann definiere man sich einige Matrizen und
lasse sie sehr simpel in der paint-Methode ausgeben. Eine einfache Matrizenmultiplikation kann
man so auch auch probieren und das Ergebnis ausgeben lassen. z.B.
M2=new Matrix(2,3,4,6,1,1); M3=new Matrix(2,0,0,2,0,0); // eine Matrix mal "2" for (int i= 0;i<3;i++) { g.drawString(" "+M1.werte[i][0]+" "+M1.werte[i][1]+" "+M1.werte[i][2]
+" ",40,50+i*15); g.drawString(" "+M2.werte[i][0]+" "+M2.werte[i][1]+" "+M2.werte[i][2]
+" ",40,100+i*15); M4=M2.malMatrix(M3); g.drawString(" "+M4.werte[i][0]+" "+M4.werte[i][1]+" "+M4.werte[i][2]
+" ",40,150+i*15); }
Im nebenstehenden Beispiel wurde verschoben , ska-
liert und rotiert.
Nun sind auch Grafiken möglich,die sonst nur mit ei-
ner selbstgeschriebenen Turtlegrafik möglich waren
( siehe Kapitel über Rekursionen ). Man muss nicht
mehr mit move und turn eine Turtle über den Bild-
schirm schicken ,um Muster zu erzeugen , die auf
Drehung von Figuren beruhen.
Seite 42
3.4.4 Beispielbilder
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
Aufgabe:
Schreiben sie das vollständige Applet und probieren sie die unterschiedlichen Transformationen.
Probieren sie auch Scherung und Spiegelung aus.
Seite 43
3.4.4 Beispielbilder
© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen
Rotation und Skalierung mit Zufallsfarben Rotation und Skalierung mit Zufallsfarben
Zuerst verschoben und skaliert dann nur nochrotiert