Julia-Mengen mit PHP zeichnen und als Bild ausgeben

Java-Programme, welche Juliamengen graphisch ausgeben können sind ziemlich beliebt. Ich habe mich gefragt, ob man mit PHP ebenfalls ein solches Programm schreiben kann. Bei den Java-Programmen werden die Darstellungen in der Regel in einem Programmfenster ausgegeben. Bei PHP gibt es dazu die nützlichen Image-Funktionen. Damit lassen sich nämlich Bilder bearbeiten, erstellen, konvertieren usw. Für das Juliamengen-Script interessierte mich vor allem die Funktion imagesetpixel(). Diese Funktion füllt einzelne Pixel eines Bildes mit der gewünschten Farbe.
Mit dem nachfolgenden Code wird berechnet, wie die einzelnen Pixel eingefärbt werden müssen. Schlussendlich wird die Juliamenge in der Form eines Bildes graphisch dargestellt.

Mathematik
Der Vollständigkeit halber sei hier auch noch erwähnt, was die Julia-Menge überhaupt ist. Um dies genau zu verstehen muss man sich mit komplexen Zahlen auskennen.

Der Begriff Iteration
Unter Iteration versteht man die zu einem bestimmten Startwert z0 entstehenden Glieder einer Zahlenfolge nach der Vorschrift zn+1 = f(zn).
f stellt dabei eine komplexe Funktion dar. Bei einer komplexen Funktion wird jeder komplexen Zahl z der Gaussschen Ebene durch die Vorschrift f genau eine komplexe Zahl zugeordnet.
Nun aber zurück zum Begriff Iteration: z0, z1, z2, z3, ... heisst die Bahn des Punktes z0.

Fluchtmenge, Gefangenenmenge
Strebt die Bahn eines Punktes z0 nach "Unendlich", so heisst z0 Divergenzpunkt, andernfalls bleibt die Bahn von z0 begrenzt.
Die Menge aller Divergenzpunkte einer Iterationsvorschrift zn+1 = f(zn) heisst Divergenzbereich oder Fluchtmenge.
Die Menge der restlichen Punkte der Gaussschen Ebene nennt man Einzugsbereich oder Gefangenenmenge.

Julia-Menge
Die Grenze zwischen Flucht- und Gefangenenmenge der Iteration zn+1 = z2 + c heisst Julia-Menge. c ist eine komplexe Zahl a + bi mit dem Realteil a und dem Imaginärteil b.

Umsetzung im Programm
Jeder Punkt der Gauss-Ebene wird als Startwert der Iteration verwendet. Alle Divergenzpunkte werden z.B. weiss markiert, alle Startpunkte, welche nicht divergieren z.B. blau. Weiss stellt dann die Fluchtmenge dar, blau die Gefangenenmenge. Die Grenze dazwischen ist die Julia-Menge.
Die Überprüfung , ob ein Punkt divergiert oder nicht, erfolgt in einer for-Schleife, in der jeweils die Zahl zn+1 = z2 + c berechnet wird. Ein Punkt divergiert, sobald a2 + b2 > 4, also der Realteil im Quadrat plus der Imaginärteil im Quadrat grösser ist als vier. Damit man die schönen farbigen Darstellungen erhält, kann man noch die Anzahl Durchläufe der for-Schleife, bis a2 + b2 > 4 bei der Einfärbung berücksichtigen.

wichtiger Hinweis
Die Berechnung mit dem nachfolgenden Script ist sehr rechenintensiv, sprich aufwändig, weshalb der Server einige Zeit benötigt, bis das Bild ausgegeben wird. Die Zeit erhöht sich mit der gewählten Auflösung. Ich rate dringend davon ab, diesen Script für mehr als Testzwecke zu verwenden. Ob der Hostinganbieter überhaupt solche Scripts toleriert muss im Vorfeld unbedingt abgeklärt werden. Bei einer Überlastung des Servers muss in der Regel der Verursacher (d.h. derjenige, der solche Scripts verwendet) für allfällige Schäden aufkommen.

Script
Die komplexe Zahl c kann im Code angegeben werden, wobei cRe der Realteil und cIm der Imaginärteil der komplexen Zahl c darstellt. Die Variable dimension ist die Seitenlänge des ausgegebenen Bildes.

 

<?php
 
/**
 * julia.php
 *
 * Julia-Mengen-Script.
 * 
 * WICHTIGER HINWEIS: Die Berechnung mit dem nachfolgenden Script ist sehr rechenintensiv, sprich aufwändig,
 * weshalb der Server einige Zeit benötigt, bis das Bild ausgegeben wird. Die Zeit erhöht sich mit der
 * gewählten Auflösung. Ich rate dringend davon ab, diesen Script für mehr als Testzwecke zu verwenden.
 * Ob der Hostinganbieter überhaupt solche Scripts toleriert muss im Vorfeld unbedingt abgeklärt werden.
 * Bei einer Überlastung des Servers muss in der Regel der Verursacher (d.h. derjenige, der solche Scripts
 * verwendet) für allfällige Schäden aufkommen.
 * 
 * copyright: tssh.jimdo.com
 * date: Apr 09
 */
 
class Julia {
    private $cRe, $cIm, $a1, $b1; //-0.7; 0.3;
    private $reAlt, $imAlt;
    private $dimension;
    private $image;
 
    // Konstruktor
    // Einstellungen, Programmaufruf, Bild ausgeben
    public function Julia() {
        header("Content-type: image/png");
 
        // EINSTELLUNGEN
 
        // Reeller Teil der Zahl c
        $this->cRe = -0.76399;
        // Imaginaerer Teil der Zahl c
        $this->cIm = 0.19411;
        // Seitenlaenge des Bildes
        $this->dimension = 200;
 
        // ENDE EINSTELLUNGEN
 
        $this->image = imagecreatetruecolor($this->dimension, $this->dimension);
        $this->paintComponent();
        imagepng($this->image);
    }
 
    // Ueberpruefen ob die Zahl divergiert oder nicht
    public function checkDiv() {
        $this->reAlt = $this->a1;
        $this->imAlt = $this->b1;
        for ( $i = 0; $i < 50; $i++) {
            $imZ = (2 * $this->reAlt * $this->imAlt) + $this->cIm;
            $reZ = ($this->reAlt * $this->reAlt) - ($this->imAlt * $this->imAlt) + $this->cRe;
            if ( (($reZ * $reZ) + ($imZ * $imZ)) > 4) {
                return $i;
            }
            $this->reAlt = $reZ;
            $this->imAlt = $imZ;
        }
        return $i;
    }
 
    // Punkte berechnen und setzen
    public function paintComponent() {
        $w = $this->dimension;
        $h = $this->dimension;
        $max = round($this->dimension + ((1/3) * $this->dimension));
        $max4 = round($max/4);
        for ( $a = 0; $a <= $max; $a++ ) {
            for ( $b = 0; $b <= $max; $b++ ) {
                $this->a1 = ($a/$max4) - 2.0;
                $this->b1 = ($b/$max4) - 2.0;
                $x = round(($w/2) + ($this->a1*($w/3)));
                $y = round(($h/2) - ($this->b1*($h/3)));
                $returned = $this->checkDiv();
                if ( $returned > 0 ) {
                    imagesetpixel($this->image, $x, $y, imagecolorallocate($this->image, round((($returned*$returned*$returned) / 125000 ) * 255 ), round((($returned*$returned) / 2500 ) * 255 ), round((($returned) / 50 ) * 235 + 20 )));
                }
            }
        }
    }
}
 
$julia = new Julia();
?>

Kommentar schreiben

Kommentare: 0