Im zweiten Teil dieses Tutorials zeige ich Euch, wie Ihr Eure eigenen Fraktalformeln entwickeln könnt.
Bevor Ihr jetzt aber völlig planlos Eure eigenen Formeln entwickelt, solltet Ihr Euch natürlich ein paar grundlegende Gedanken machen. Was soll diese Formel können, stellt sie etwas noch nie dagewesenes dar oder reichen die von Ultra Fractal bereitgestellten Formeln für Eure Zwecke völlig aus.
Solide Grundlage für das Entwickeln eigener Formeln ist, so banal wie es klingt, ein Plan.
Deshalb möchte ich vorab einige Eckpunkte für unseren Formel definieren.
- die Iterationsgleichung soll einen Startwert, einen Exponenten und zwei Funktionen enthalten,
- eine Funktion soll vom Nutzer aktiviert und dann eingeblendet werden können,
- die Daten für den Startwert, Exponent und Bailout sollen vom Nutzer eingegeben werden können und
- zwischen den Fraktaltypen soll umgeschaltet werden können.
Dann lasst uns anfangen.
Fraktalformeldatei erstellen
Zunächst erstellt Ihr Euch eine neue Fraktal-Formel-Datei (Fractal Formula File). Dazu wählt Ihr im Datei (File) Menü den Punkt Neu (New) aus.
Daraufhin öffnet sich im Editor ein leeres Fenster mit den Namen Formula1.
Dieses Fenster bzw. diese Formeldatei nimmt nun nach und nach Eure Programmanweisungen auf. Damit Ihr nicht alles von Hand eingeben müsst, sind im Menüpunkt Einfügen (Insert) viele Anweisungen hinterlegt, die Ihr mit Klick einfügen könnt.
Die Formeln beginnen immer mit dem Eintrag-Identifikator, gefolgt von dessen Inhalt, der in geschweiften Klammern steht. Ihr solltet beachten, dass Leerzeichen und Tabulatoren nicht erlaubt sind. Ebenso darf der Eintrag-Identifikator innerhalb der Formeldatei nicht doppelt auftreten.
Meine-erste-Formel {
; Inhalt
}
Optional kann dem Identifikator ein Wert in Klammern beigefügt werden. Ultra Fractal kann somit die Symmetrie zum Beschleunigen der Berechnung nutzen.
MeinMandelbrot (XAXIS) {
; Inhalt
}
Kommentare in der Formel werden mit vorangestellten Semikolon gekennzeichnet. Zusätzliche globale Kommentare könnt Ihr mit dem speziellen ‘{ }
‘-Kommentar kennzeichnen.
Ich habe es mir angewöhnt, bevor ich die Formeln schreibe, einen globalen Kommentar anzulegen, der folgende Inhalte aufweist:
comment {
File: Formula1.ufm
Version: 1.0
Author: Oliver Konow, 2012
Last Modification:
}
Als nächstes folgt der Identifikator in dem Abschnitte, Funktionen und Parameter sowie weitere Einträge stehen können.
Im Menü Einfügen (Insert) findet Ihr den Punkt Neue Formel (New Formula…)
Es öffnet sich anschließend ein Fenster, in dem Ihr den Titel MeinMandelbrot eingeben und eine Symmetrie der verschiedenen Achsen auswählen könnt. In diesem Fall wählt Ihr XAXIS_NOPARM aus, sie erzwingt eine Symmetrie um die horizontale x-Achse bzw. real-Achse, jedoch nur, wenn alle komplexen Parameter auf (0
, 0
) gesetzt sind.
Den Haken am Punkt: Insert global section könnt Ihr entfernen. Falls Ihr für die verbleibenden Abschnitte keine Kommentare haben wollt, so entfernt den Haken auch am Punkt: Insert comments for each section. Drückt anschließend auf OK.
Hinweis zur Symmetrie: Damit Ultra Fractal die symmetrischen Eigenschaften von Fraktalen zum Beschleunigen der Berechnung nutzen kann, müsst Ihr die Symmetrie der Formel als optionale Einstellung in Klammern hinter dem Eintrag-Identifikator angeben.
Folgende Abschnitte sollten jetzt vorhanden sein:
MeinMandelbrot(XAXIS_NOPARM) {
init:
loop:
bailout:
default:
title = "MeinMandelbrot"
switch:
}
Damit ist das Grundgerüst Eurer Formel fertig, welches Ihr an dieser Stelle speichern solltet. Im nächsten Schritt werde ich die Abschnitte näher erläutern bevor wir sie anschließend mit Variablen befüllen.
Die Abschnitte der Formel
Abschnitt: init
In diesem Abschnitt wird die Hauptvariable z
initialisiert. Sie ist ein vordefiniertes Symbol, weshalb sie korrekterweise ‘#z
‘ bezeichnet werden müsste. In Fraktalformeln kann das #
-Präfix vor ‘#z
‘ weggelassen werden. In Kolorierungs-Algorithmen wird es jedoch benötigt.
Dieser Abschnitt wird pro Pixel nur einmal ausgeführt und eignet sich, um Variablen zu initialisieren.
Abschnitt: loop
Hier steht unsere Hauptgleichung, die nur einmal pro Iteration ausgeführt wird. Der Abschnitt soll den Wert der vordefinierten komplexen Variable #z
unter Berücksichtigung des alten Wertes von ‘z
‘ aktualisieren.
Abschnitt: bailout
Dieser Abschnitt enthält einen einzelnen Boole’schen Ausdruck, der den loop-Abschnitt solange ausführt, wie dieser Wert true
ist. Er wird mindestens einmal ausgeführt.
Abschnitt: default
Grundeinstellungen unserer Formel betreffend sind in diesem Abschnitt zu finden. Er kann Einstellungen wie title
, angle
, center
, maxiter
, helpfile
und/oder helptopic
beinhalten. Parametereinstellungen innerhalb der Blöcke param
und endparam
können ebenfalls verwendet werden.
Weitere Einstellungen sind in der Hilfedatei zu finden.
Abschnitt: switch
Dieser Abschnitt ermöglicht das Umschalten zwischen verwandten Fraktaltypen, z.B. von Mandelbrot in Julia.
Darüber hinaus gibt es noch zwei weitere Abschnitte, die hier nicht aufgeführt, ich aber dennoch kurz erläutern möchte:
Abschnitt: global
In der Fraktalformel ist dies der erste Abschnitt und wird nur einmal pro Bild ausgeführt. Er kann dazu verwendet werden, Suchtabellen zu füllen und Nur-Lese-Variablen zu initialisieren. Somit können viele wiederholte Berechnungen vermeiden werden.
Abschnitt: builtin
Mit diesem Abschnitt könnt Ihr auf fest eingebaute Fraktalformeln zurückgreifen. Wenn dieser Abschnitt verwendet wird, sind die Abschnitte global
, init
, loop
und bailout
nicht zulässig. Der Abschnitt kann folgende Einstellung enthalten: type
.
Einsetzen der Variablen in die Formel
Nachdem das Grundgerüst steht, können nun Variablen, Ausdrücke und Formeln in die entsprechenden Abschnitte eingesetzt werden.
Hinweis! Hinsichtlich der Parameter möchte ich auf den Artikel Formel schreiben – Teil 1 verweisen.
Inhalt des init-Abschnitts
z = @start
Die komplexe Variable z
wird mittels dem benutzerdefinierten Parameter @start
initialisiert. Die Werte können im Karteireiter Formel (Formula) eingegeben werden.
Weitere Informationen zum Parameter @start
werden im Parameterblock erläutert.
Inhalt des loop-Abschnitts
if @auswahl == true
z = z^@power + @myfunc1(z) + @myfunc2(z) + #pixel
else
z = z^@power + @myfunc1(z) + #pixel
endif
Hier befinden sich zwei Iterationsgleichungen, die fortlaufend die komplexe Variable z
berechnen. Die Auswahl der ersten Gleichung erfolgt, wenn der Parameter @auswahl == wahr
, also ausgewählt wurde. Falls nicht, wird die zweite Gleichung verwendet.
In den Gleichungen befinden sich die Parameter @power
, @myfunc1
sowie @myfunc2
deren Exponent bzw. deren Funktionen durch den Nutzer im Karteireiter Formel (Formula) eingegeben bzw. ausgewählt werden kann.
Weitere Informationen zu den Parametern @power
, @myfunc1
sowie @myfunc2
werden in den Parameter- sowie den Funktionsblöcken erläutert.
Desweiteren befindet sich das vordefinierte Symbol #pixel
in der Gleichung, welches die komplexen Koordinaten des berechneten Pixels zurückgibt.
Inhalt des bailout-Abschnitts
|z| <= @bailout
Der loop-Abschnitt wird solange iteriert, bis die Bedingung Betrag z
kleiner gleich dem benutzerdefinierten Parameterwert @bailout
erfüllt ist. Der Wert kann im Karteireiter Formel (Formula) geändert werden.
Nähere Informationen zum Parameter @bailout
werden im Parameterblock erläutert.
Inhalt des default-Abschnitts
title = "MeinMandelbrot"
center = (-1, 0)
helpfile = "Formula1.txt"
helptopic = "Hilfe zu MeinMandelbrot"
Die Einstellung title
beinhaltet den Namen der Formel, in diesem Fall MeinMandelbrot, der auch im Karteireiter Formel (Formula) angezeigt wird, in der Abbildung gelb markiert.
Die zweite Einstellung center
legt die komplexen Koordinaten im Karteireiter Standort (Location) fest.
Mit den Einstellungen helpfile
und helptopic
könnt Ihr eine Hilfedatei, hier die Datei Formula1.txt, und einen speziellen Hinweistext zur Formel anbieten.
Die Hilfedatei wird durch Klick auf das Fragezeichen im Karteireiter Formel (Formula) geöffnet, siehe rote Markierung in der folgenden Abbildung.
heading
caption = "Wähle die Funktion(en)..."
text = "cosh, sqr and zero für die Standard Mandelbrotmenge."
endheading
Mit Hilfe von Überschriften könnt Ihr Parameter- und Funktionsblöcke logisch mit caption
gruppieren und mit Hilfe der Einstellung text
genauer beschreiben. Sie werden für den Benutzer angezeigt, siehe folgendes Bild. Überschriften werden mit heading
eingeleitet und mit endheading
abgeschlossen.
Anschließend folgt der erste Funktionsblock, der zunächst mit einer Überschrift eingeleitet wird.
heading
text = "Erste Funktion"
endheading
func @myfunc1
caption = "Funktion 1"
default = zero()
hint = "Wähle eine Funktion aus, um die Formel zu verändern."
endfunc
Funktionen werden in der Form [type] func <Parameter-Bezeichner>
eingeleitet und mit endfunc
beendet. Die Funktion ist vom Typ entweder ‘complex‘ oder ‘color‘. Wird der Typ nicht angegeben, so wird ‘complex‘ angenommen. Der Parameterbezeichner @myfunc1
ist identisch mit dem benutzerdefinierten Parameter aus dem loop-Abschnitt.
Die Einstellung caption
spezifiziert den Parameter @myfunc1
genauer und default
setzt den Standardwert der Funktion auf atanh
. Mit hint
wird ein kleiner Hinweistext erzeugt, der dann sichtbar ist, wenn Ihr den ?-Button oben in der Titelleiste des Werkzeugfensters Ebenen-Eigenschaften (Layer Properties) und anschließend auf den Parameter klickt.
Der zweite Funktionsblock wird ebenfalls mit einer Überschrift eingeleitet. Im Gegensatz zum ersten Funktionsblock wird der zweite Funktionsblock @myfunc2
nur dann eingeblendet, wenn der Nutzer ein Häkchen in das Kontrollkästchen Funktion 2 nutzen?
des Parameterblocks @auswahl
macht. Der ist durch default = false
standardmäßig ausgeblendet. Durch visible = @auswahl
wird das Einblenden gesteuert.
Mit Hilfe der if
-Bedingung im loop-Abschnitt wird nun die entsprechende Formel zum Berechnen des Fraktals herangezogen.
param @auswahl
caption = "Funktion 2 nutzen?"
default = false
endparam
heading
text = "Zweite Funktion"
visible = @auswahl
endheading
func @myfunc2
caption = "Funktion 2"
default = exp()
hint = "Wähle eine Funktion aus, um die Formel zu verändern."
visible = @auswahl
endfunc
Alle anderen Einstellungen sind wie beim vorangegangenen Funktionsblock. Hier die Liste aller Funktionen in Ultra Fractal.
Auch die Parameterblöck werden in der Form [type] param <Parameter-Bezeichner>
eingeleitet und mit endparam
beendet.
Die folgenden Parameterblöcke werden der Übersicht halber und in gewohnter Weise mit einer Überschrift eingeleitet.
heading
caption = "...und Werte"
endheading
Der Parameter @start
initialisiert in der Standardeinstellung den Real- und Imaginärteil der komplexe Variable z
auf (0
, 0
). Die anderen Einstellungen wurden bereits weiter oben beschrieben.
param @start
caption = "Startwert"
default = (0,0)
hint = "Mit dem Parameter Startwert kann die Mandelbrotmenge \
verändert werden. Verwende (0, 0) für die Standard- \
Mandelbrotmenge."
endparam
Der vordefinierte Parameter @power
ist für den Exponenten unserer Gleichung zuständig. Für den Realteil beträgt der Exponent 2
und für den Imaginärteil 0
.
param @power
caption = "Exponent"
default = (2,0)
hint = "Dieser Parameter wird für den Exponenten der Formel \
verwendet. Die Eingabe von 3, 4 und größer im Realteil, \
lässt die Mandelbrotmenge runder werden. \
Nicht-Integer-Werte sowie Nicht-Null-Werte im \
Imaginärteil verzerren das Afelmännchen. \
Benutzen Sie (2, 0) für die Standard-Mandelbrotmenge."
endparam
Der Ausstiegswert @bailout
, ab wann die Iteration im loop-Abschnitt abgebrochen werden soll, ist vom Typ her eine Fließkommazahl und somit float
. Der Standardwert default ist mit 1.0E20
und der Minimalwert min
mit 1
festgelegt.
float param @bailout
caption = "Bailout"
default = 1.0e20
min = 1.0
Ob ein Fließkommaparameter die exponentielle Interpolation nutzen soll oder nicht, kann mittels exponential
eingestellt werden. Standardmäßig ist dieser Wert auf false
voreingestellt. Ihr könnt diesen Wert später im Werkzeugfenster Zeitstrahl (Timeline) ändern.
Wenn Eure Formel auch in früheren Versionen von Ultra Fractal laufen soll, in denen die exponential
-Einstellung nicht verfügbar war, testet Ihr das mit dem VER40
-Symbol. Der Aufruf erfolgt durch die sogenannte Compiler-Direktive.
Mittels $ifdef VER40
wird die Version von Ultra Fractal abgefragt und sichergestellt, dass in Ultra Fractal 4 der Parameter exponentiell interpoliert wird. Beendet wird die Direktive mit $endif
.
$ifdef VER40
exponential = true
; In Ultra Fractal 4 stellt Ihr sicher, dass dieser Parameter
; exponentiell interpoliert wird.
$endif
hint = "Dieser Parameter definiert, wie lange die Formel \
iteriert wird und ob ein Pixel zur Mandelbrotmenge \
gehört oder nicht. Entsprechend wird er eingefärbt. \
Größere Werte liefern eine klarere Konturen; \
Werte kleiner als 4 verzerren die Fraktale."
endparam
Der Vollständigkeit halber sollen die anderen Versionen nicht unerwähnt bleiben: ULTRAFRACTAL
, VER20
, VER30
, VER40
sowie VER50
.
Die Compiler-Direktiven lauten: $define
, $undef
, $ifdef
, $else
sowie $endif
.
Inhalt des switch-Abschnitts
Um vom Fraktaltyp MeinMandelbrot
zum Typ MeinJuliabrot
schalten zu können, müsst Ihr in der Einstellung type
den Formelbezeichner eintragen.
Die Einstellung für den Zielparameter @seed = #pixel
sorgt dafür, dass das Schaltfeature abhängig vom Punkt ist, den der Nutzer innerhalb des Fraktalfensters klickte. Der Parameter in der Zielformel muss komplex sein, sonst wird die Einstellung ignoriert.
Abschließend werden die Einstellungen für die Parameter @power
, @myfunc1
, @myfunc2
und @bailout
aus der Quellformel in die Zielformel kopiert. Dabei müsst Ihr sicherstellen, dass Quell- und Zielparameter gleich sind, ansonsten werden die Einstellungen ignoriert.
Parameter, die nicht explizit kopiert werden, erhalten voreingestellte Werte.
type = "MeinJuliabrot"
@seed = #pixel
@power = @power
@auswahl = @auswahl
@myfunc1 = @myfunc1
@myfunc2 = @myfunc2
@bailout = @bailout
Zielformel erstellen
Jetzt müsst Ihr nur noch die Zielformel schreiben. Hört sich kompliziert an, ist aber ganz einfach.
Dazu kopiert Ihr zunächst die Formel MeinMandelbrot
und benennt diese in MeinJuliabrot
um. Zu ändernde Stellen habe ich rot markiert.
MeinJuliabrot(XAXIS_NOPARM) {
Als nächstes ändert Ihr den Wert der komplexen Variable z
im init-Abschnitt von
z = @start
in
z = #pixel
Anschließend werden die Iterationsgleichungen im loop-Abschnitt von
z = z^@power + @myfunc1(z) + @myfunc2(z) + #pixel
und
z = z^@power + @myfunc1(z) + #pixel
in
z = z^@power + @myfunc1(z) + @myfunc2(z) + @seed
und
z = z^@power + @myfunc1(z) + @seed
angepasst.
Als letztes müsst Ihr noch im switch-Abschnitt Änderungen von
type = "MeinJuliabrot"
@seed = #pixel
@power = @power
@auswahl = @auswahl
@myfunc1 = @myfunc1
@myfunc2 = @myfunc2
@bailout = @bailout
in
type = "MeinMandelbrot"
@power = @power
@auswahl = @auswahl
@myfunc1 = @myfunc1
@myfunc2 = @myfunc2
@bailout = @bailout
vornehmen.
Sicherlich fragt Ihr Euch jetzt, wie das Umschalten eigentlich funktioniert?
- In der Formel
MeinMandelbrot
wird zunächst der Startwert initialisiert und danach die Iterationsgleichungen ausgeführt. - Dem vordefinierten Symbol
#pixel
werden die komplexen Koordinaten zurückgegeben. - Klickt der Nutzer innerhalb des Fraktalfensters, so schaltet er zum Fraktaltyp
MeinJuliabrot
um, dem als Startwert@seed
die komplexen Koordinaten von#pixel
übergeben werden. - Der Startwert für die Formel
MeinJuliabrot
wird mit den komplexen Koordinaten, die von#pixel
übergeben wurden, initialisiert. - Anschließend werden wie gewohnt die Iterationsgleichungen ausgeführt. Ein erneutes klicken in das Fraktalfenster schaltet wieder zum Fraktaltyp
MeinMandelbrot
zurück.
Hier die Datei formula1.ufm sowie die entsprechende Hilfedatei formula1.txt.
Ich wünsche Euch viel Spaß beim Experimentieren!
Formeln schreiben – Teil 2 by Oliver Konow is licensed under CC BY-NC-ND 4.0
Schreibe einen Kommentar