Mandelbrot-Grafik mit PHP

Mandelbrot

Bild-Größe in Pixeln:
Berechnet:
Angezeigt:
X:
Y:


Anzahl der berechneten Bildpunkte = 900
Maximale Rechenzeit des PHP-Programms = 300sec

Änderung des berechneten Bereichs:    ◀   ▲   +   -   ▼   ▶   

• Stellen sie die 'Angezeigte Größe' passend zu ihrem Browser-Fenster ein.
• Vergrößern sie danach die 'Berechnete Größe' passend zur Rechen-Geschwindigkeit des Webservers.
• Experimentieren sie mit verschiedenen Farb-Verweis-(CLUT)-Tabellen und vergrößern sie interessante Bereiche der Grafik.
Test mit Zufalls-Werten. Wenn dabei ausschließlich 'schwarze' Bereiche getroffen werden, dann wird kein Bild angezeigt: Wiederholen sie den Versuch oder verkleinern sie mit der  -  Taste.

Mit diesem Link wird die Mandelbrot-Grafik in Original-Größe einem neuen Browser-Tab geladen. Sie können alle Vorgaben der Berechnung (Hilfe) manuell in der Adresszeile des Browsers angeben.

CLUT

Color Lookup Table:

• Links die Farbe des kleinsten Ergebnisses (Abbruch nach wenigen Schritten), rechts jene des größten (langsamer Fortschritt).

• Der 'Innere Bereich' ist ein Sonderfall: Er wird in jedem Fall schwarz dargestellt. Diese Farbe ist in der Balken-Grafik nicht enthalten.

Berechnung

Für IT-EntwicklerInnen ist es zwar hilfreich, jedoch nicht unbedingt notwendig, eine zur Berechnung verwendete Formel zu verstehen:
Das Ziel der Arbeit besteht in der Umsetzung des Auftrags mit den Mitteln der Informatik.

In diesem Fall wird die Farbe jedes einzelnen Bildpunkts nach einem Algorithmus berechnet, d.h. nicht nach einer einfachen Formel, sondern nach einer Liste von Vorschriften, die für jedes Pixel mehrmals (hier bis zu 500mal) durchlaufen wird.

In der Praxis der Informatik sind der Unendlichkeit der Fraktale jedoch konkrete Grenzen gesetzt: Einfache Programme (wie dieses) können nur auf ca. 16 Dezimal-Stellen genau rechnen.
Mit speziell dafür ausgelegten Methoden kan man zwar beliebig genau rechnen, der dazu nötige Aufwand dazu ist jedoch für einfache Arbeits-PC kaum zu rechtfertigen.



Das Ziel des Algorithmus besteht darin, den Verlauf der Berechnung zu beschreiben:

Im Zentrum der Grafik ändern sich die Werte von jx,jy sehr langsam:
Die Berechnung wird (hier: nach 500 Berechnungs-Schritten) abgebrochen und eine dazu vorgesehene Farbe (meistens: Schwarz) zugewiesen.

In großer Entfernung vom Zentrum nehmen die Werte von jx,jy rasch zu.
Nach wenigen Berechnungs-Schritten werden sehr große Zahlen und damit die Grenzen des Variablen-Typs (Double Precision) erreicht. Je nach Anzahl der bis zum Abbruch berechneten Schritte werden dem Bildpunkt jene Farben zugewiesen, die weit links in der Verweis-Tabelle (CLUT) angezeigt werden.

Je näher man dem 'Schwarzen Rand' kommt, umso langsamer wachsen die Werte von jx,jy
Bis zum Abbruch werden immer mehr Schleifen-Durchgänge benötigt. Die Farbe des Bildpunkts wird umso weiter rechts aus der CLUT entnommen, je mehr Berechnungs-Schritte bis zu Abbruch notwendig waren.



Wenn man einen Bereich nahe am 'Schwarzen Rand' genauer untersucht, dann gibt es viele Punkte mit mittleren Zahlenwerten. Die Werte benachbarter Punkte unterscheiden sich stärker, daher nimmt auch auch die Anzahl der darstellbaren Farben zu.

Die Grafik zeigt umso mehr Details, je mehr Punkte berechnet werden. Damit nimmt jedoch auch die Rechenzeit schnell zu. In der Praxis muss man den besten Kompromiss finden.
Interpreter-Programmiersprachen (Perl, PHP, Python, ...) stoßen je nach PC-Leistung schon bald an ihre Grenzen.
In der Praxis berechnet man hoch aufgelöste Mandelbrot-Bilder daher mit den schnellsten verfügbaren Methoden, z.B. mit Programmen in der Programmiersprache C/C++.



In diesem Beispiel wird die Anzahl der verwendeten Farben auf 251 begrenzt. Man kann daher → Index-Farben einsetzen und viel Rechenzeit sparen.

Dazu werden zunächst die Ergebnis-Zahlen für alle Punkte berechnet und in einem → Array gespeichert. Danach werden die Zahlen so umgerechnet (normalisiert), dass ihre Werte in den Bereich ganzer Zahlen 0...250 fallen.

In einer ↓ Verweis-Tabelle mit 251 Zeilen wird jeder Zahl 0...250 eine beliebige Farbe zugeordnet. Zur Darstellung der Grafik sucht man für jeden Bildpunkt (Pixel) seine normalisierte Ergebnis-Zahl und findet dazu in der Tabelle (Color Lookup Table, CLUT) die entsprechende Farbe.

Im Demo-Beispiel können sie verschiedene CLUT-Tabellen wählen. Die (gleichen) Ergebnis-Zahlen werden je nach CLUT in unterschiedlichen Farben dargestellt. Die verwendete CLUT wird unterhalb der Mandelbrot-Grafik als Farb-Balken angezeigt.
Details der Farb-Verweis-Tabelle im Kapitel ↓ CLUT.

Erzeugung der Grafik (PHP-Quelltext)

◀  Das Programm in der Programmiersprache → PHP beginnt mit header()-Funktionen. Damit wird u.a. der (MIME)-Typ der nachfolgenden Daten im → HTTP-Header angekündigt.

• Default values: Hier werden die Standard-Werte aller Vorgaben definiert. Sie gelten, wenn sie nicht durch GET-Argumente geändert werden.

• GET:  Die Decodierung und Kontrolle der Argumente nimmt den größten Anteil des Programms ein. Argumente:
• Im Bereich 'Scale' werden jene Faktoren berechnet, mit denen die Beziehung zwischen der XY-Adresse der Pixel und dem zu berechnende XY-Werte-Bereich hergestellt wird.

• Die Mandelbrot-Funktion wird mit der unten gezeigten ↓ Datei mandelfunc.php eingebunden.
• Das Grafik-Objekt $img wird erzeugt.
• Die Farben-Verweis-Tabelle (CLUT) wird mit der ↓ Datei clut.php eingebunden.

• In 2 ineinander verschachtelten Schleifen werden alle Punkte (Pixel) der Grafik durchlaufen. Im → Array $mda werden die Ergebnisse der Mandelbrot-Funktion gespeichert. Die kleinsten und größten Werte werden in den Variablen $mdmin,$mdmax gespeichert.

• Im Bereich 'Normalize' werden alle Array-Elemente nochmals durchlaufen. Der jeweilige Wert $n der Mandelbrot-Funktion wird in einen ganzzahligen Index 0...$i...250 umgerechnet. Damit wird die passende Farbe $cola[$i] aus dem CLUT-Array gewählt und mit Funktion imagesetpixel() an den Bildpunkt zugewiesen.

• Zuletzt wird die fertige Grafik mit imagepng() an den Browser gesendet.


Vereinfachung

Für eigene Experimente kann man das Beispiel stark vereinfachen:
Schalten sie die Zeilen-Nummern mit Mausklick ab und kopieren sie den Text in eine Datei mandelbrot.php und speichern sie die Datei im Arbeits-Verzeichnis ihres eigenen Webservers. Die Mandelbrot-Grafik wird von einer einzigen Datei mit nur ca. 70 Programm-Zeilen erzeugt.

• An Stelle der aufwändig decodierten GET-Argumente werden im Abschnitt 'Parameters' fixe Vorgaben verwendet. Sie müssen allerdings den Quelltext ändern, um die Grafik mit anderen Vorgaben zu erzeugen.

• Die Berechnung mit Funktion mandelbrot() wurde vereinfacht.

• Die Beziehung zwischen den Ergebnissen der Mandelbrot-Funktion und der dargestellten Farbe (Funktion clut() ) wurde vereinfacht: Der Bereich von 10..500 Schleifen-Durchläufen wird mit nur 2 Farben (Blau, Rot) dargestellt. Die Skala ist für kleine Zahlenwerte stark gedehnt.

• Es werden keine (vor-definierten) → Index-Farben verwendet, sondern jede (TrueColor)-Farbe $col wird mit Funktion clut() einzeln berechnet.

• Die dynamische (Live erzeugte) Grafik wird so wie jede andere in eine Webseite eingebettet, z.B.:
<img src="mandelbrot.php"/>
Mit → CSS-Anweisungen kann man die Grafik in jeder gewünschten Größe anzeigen. Die Auflösung ist allerdings durch die Anzahl der berechneten Pixel begrenzt:
<img src="mandelbrot.php" style="width:300px; height:300px;"/>

▶ Mit diesem ↗ Link wird die vereinfachte Version der Mandelbrot-Grafik in einem eigenen Browser-Tab angezeigt.

Mandelbrot-Funktion

◀  Die links gezeigte Funktion berechnet den Mandelbrot-Algorithmus.
Sie wird mehrfach verwendet und ist daher in eine eigene Datei mandelfunc.php ausgelagert und wird mit der PHP-Anweisung include in ein Programm eingebunden.

Der Mandelbrot-Algorithmus ist in eine while-Schleife eingebettet und wird in den 2 bezeichneten Programm-Zeilen ausgeführt.

Die Funktion unterscheidet sich nur in wenigen Details vom oben vorgestellten ↑ Algorithmus:

Die Schleife wird so oft wiederholt, bis sie durch eine von 3 Bedingungen abgebrochen wird:

Ein kleiner Trick wurde eingebaut, um die Ergebnisse im Falle weniger Durchgänge genauer zu unterscheiden: Es wird gemessen, wann der Algorithmus das Zwischen-Ergebnis $lim erreicht: Diese Zahl wird im Ergebnis als Nachkomma-Rest $nlim/$n berücksichtigt.

In einfachen Fällen werden die Bilder von wenigen Farben am unteren (linken) Rand der CLUT dominiert. Im Beispiel wird daher nicht die Anzahl der Iterationen $n sondern der Logarithmus log($n) zurückgegeben: Das ergibt mit wenig Aufwand deutlich bessere Bilder.

Farb-Verweis-Tabelle (CLUT)



◀  Die Farb-Verweis-Tabelle (CLUT) wird im → Array $cola verwaltet. Die 256 Farben der Tabelle werden in dieser Datei nur einmal mit der vollen Genauigkeit von je 3*8=24 Bit definiert. Danach kann man jedem Bildpunkt sehr rasch eine Farbe der Tabelle zuweisen (→ Details).

• In diesem Beispiel kann man zur Berechnung der CLUT unterschiedliche Regeln wählen. Die Funktionen clut_0() ... clut_4() bieten dazu unterschiedliche Algorithmen, d.h. die → RGB-Farb-Werte werden nach unterschiedlichen Regeln in die Tabelle eingetragen.
Man kann die Algorithmen beliebig variieren und einer (Mandelbrot)-Grafik damit alle gewünschten Farben verleihen.

• Das CLUT-Array wird mit Funktion clut_init() initialisiert: Sie definiert die Farben aller 256 Array-Elementen.

• In einer Schleife werden alle 251 als CLUT verwendeten Elemente des → Arrays $cola durchlaufen. In jedem Durchgang wird eine Index-Farbe berechnet und mit Funktion imagecolorallocate() an das jeweilige Array-Element $cola[$i] zugewiesen.


• Man kann auf Index-Farben verzichten und jedes Pixel in einer von 16777216 TrueColor-Farben darstellen. In diesem Fall berechnet man die Farbe jedes Bildpunkts nicht mit einer Verweis-Tabelle sondern mit einer beliebigen Funktion.

Der Mandelbrot-Algorithmus liefert ganze Zahlen. Die Ergebnis-Werte benachbarter Punkte sind oft identisch. Man erhält daher relativ große Flächen der gleichen Farbe. Wenn man so viele Farben zur Verfügung hat, dann muss man den Mandelbrot-Algorithmus so verändern, dass er eine feinere Abstufung der Ergebnis-Werte liefert. Ein einfaches Beispiel dazu ist in der hier verwendeten ↑ Mandelbrot-Funktion enthalten.