Wir backen uns ein Apfelmännchen
Ein Apfelmännchen in einer Skriptsprache? In MacPerl? Vor einigen Jahren nahm solch ein Unterfangen selbst in einer Hochsprache wie Pascal oder C noch minuten- bis stundenlang meinen kleinen Atari ST in Anspruch. Doch bei einem PowerMac und auch mit den Fortschritten, die Skriptsprachen in der Rechengeschwindigkeit gemacht haben, kann man es ja mal probieren.
Das Apfelmännchen ist der Superstar der fraktalen Geometrie. Gefunden wurde die Figur 1980 von Benoit B. Mandelbrot und wird daher Mandelbrot-Menge genannt. Wegen der besonderen Form erhielt es auch den Spitznamen Apfelmännchen.
Solche fraktalen Figuren konnten erst berechnet werden, seitdem es Computer als »Rechenknechte« gibt. Es müssen nämlich für jeden Punkt des Bildes rückgekoppelte nichtlineare Gleichungen durchgeführt werden. Das bedeutet, das Ergebnis der gerade druchgeführten Rechnung ist der Startwert der nächsten Rechnung. Und erst wenn ein bestimmter Wert erreicht wurde oder eine gesetzte maximale Anzahl von Iterationen druchlaufen wurde, wird entschieden, ob ein Bildpunkt gesetzt wird, oder nicht.
Das Apfelmännchen entsteht aus einer recht einfachen, nämlich quadratischen nichtlinearen (Un-)Gleichung: z <-- z**2 - c
Allerdings sind z und c komplexe Zahlen, die nach einfachen Regeln zu berechen sind. Die relle und imaginäre Komponenten der komplexen Zahl c können als Bildpunke (x, y) begriffen werden.
Das MacPerl-Script ist recht flott, als ich aber versucht habe, die Berechnung mit dem Modul Math::complex durchzuführen, wurde es sehr, sehr langsam. Daher wurden die komplexen Rechnungen auf gewohnte Weise mit reeller Arithmetik durchgeführt:
Hier das Skript:
#!perl
use strict; use Mac::Windows; use Mac::QuickDraw; use Mac::Events;
use constant BREITE => 300; use constant HOEHE => 300; use constant GRENZE => 10;
use constant LINKS => -0.75; use constant RECHTS => 2.25; use constant UNTEN => -1.5; use constant OBEN => 1.5; use constant MAXITER => 20;
my ($style, $title, $win, $winrect);
$style = noGrowDocProc(); $title = "Apfelmännchen"; $winrect = Rect->new(100, 100, 400, 400); $win = MacWindow->new($winrect, $title, 1, $style, 1); $win->sethook("redraw" => \&drawIt);
while ($win->window()) { WaitNextEvent(); }
END { $win->dispose() if (defined($win)); }
sub drawIt { my ($x, $y, $zIm,, $zRe, $cIm, $cRe, $zRhoch2, $zIhoch2, $i);
for ($x = 0; $x < BREITE; $x++) { $cRe = LINKS + $x*(RECHTS - LINKS)/BREITE; for ($y = 0; $y < HOEHE; $y++) { $cIm = UNTEN + $y*(OBEN - UNTEN)/HOEHE; $zRe = 0; $zIm = 0; $zRhoch2 = 0; $zIhoch2 = 0; $i = 0; do { $zIm = 2*$zIm*$zRe - $cIm; $zRe = $zRhoch2 - $zIhoch2 - $cRe; $zRhoch2 = $zRe*$zRe; $zIhoch2 = $zIm*$zIm; $i++ } while ($i < MAXITER) or (($zRhoch2 + $zIhoch2) > GRENZE); if (($zRhoch2 + $zIhoch2) <= GRENZE) { MoveTo($x, $y); LineTo($x, $y); } } } }
Zuerst werden wieder die üblichen Initialisierungen durchgeführt, um in MacPerl grafische Ausgaben in ein Fenster zu legen. In der Routine drawIt beginnt die eigentliche Arbeit. In zwei verschachtelten for-Schleifen wird jeder Bildschirmpunkt aufgesucht. In einer dritten Schleife (do - while) findet die mathematische Rückkopplung statt. Das Kriterium dafür, ob ein Bildpunkt gezeichnet wird, ist, ob nach der maximalen Anzahl der Iterationen (MAXITER) der Grenzwert (GRENZE) immer noch nicht erreicht ist. Wie sich das Apfelmännchen aus einem Kreis entwickelt, kann man sehen, wenn man nacheinander für MAXITER die Werte 2, 5 und 10 eingibt (statt der 20) und das Skript dann laufen läßt.
Literatur:
Karl-Heinz Becker, Michael Dörfler: Rezept für ein Apfelmännchen, Kursbuch 98 (1989), S. 39 - 41
Hallo Kalle und Michael, da habe ich aber eine Jugendsünde ausgegraben...