Igelgrafik

Hier findest Du eine Reihe von besonders schönen oder interessanten Igel-Zeichnungen. Besonders bei den Bildern, die geometrisch sehr regelmäßig sind, lassen sich die einzelnen Igel-Schritte oft mit einem sehr kurzen Programm beschreiben, das geschickt “Schleifen” und oder “Rekursion” einsetzt.

Wenn Du die Beispiele anklickst, wird der Quelltext angezeigt. Oben rechts auf der Seite ist der Ausprobieren-Knopf. Wenn Du dort klickst, wird der Quelltext geladen, so dass Du laufen lassen und verändern kannst.

Wenn Du selbst ein Skript geschrieben hast, kannst Du es für die Gallerie einreichen. Die besten Vorschläge werden hier veröffentlicht.

Igelgrafik (auf Englisch: turtle graphics) ist ein wesentlicher Bestandteil der Programmiersprache Logo, die in den 1960er Jahren von Seymour Papert entwickelt wurde. Sie sollte insbesondere dazu dienen, Kindern ans Programmieren heranzuführen.

Die Igel-Befehle, die in der Programmierumgebung hier bereitgestellt werden, sind

vor n Bewege den Igel um n Schritte vorwärts
zurück n Bewege den Igel um n Schritte zurück
links n Drehe den Igel um n Grad nach links
rechts n Drehe den Igel um n Grad nach rechts
stifthoch() Nach diesem Befehl zeichnet der Igel bei seinen Bewegungen keinen Strich
stiftrunter() Nach diesem Befehl (und in der Ausgangssituation) zeichnet der Igel bei den Befehlen vor, zurück und nachhause seinen Weg
stiftfarbe farbe Setze die Farbe, mit der der Igel zeichnet
stiftbreite n Setze die Breite des Strichs, den der Igel zeichnet (Ausgangswert: 2)
fülle farbe Fülle die geschlossene Figur, die der Igel ab diesem Punkt zeichnet, mit der angegebenen Farbe
bildschirmleer() Leere den Bildschirm und setze den Igel zurück auf die Ausgangsposition. Dies ist praktisch, wenn man sein Skript, eventuell mit kleinen Änderungen, mehrfach ausführt und nicht immer auf den Bildshcirm-löschen-Button klicken will. Der bildschirmleer()-Befehl sollte immer vor allen anderen Igel-Befehlen genutzt werden.
gerade() Richte den Igel so aus, dass er nach oben zeigt
nachhause() Setze den Igel zurück auf die Ausgangsposition
versteckeigel() Verstecke den Igel
zeigeigel() Zeige den Igel (wenn er mit versteckeigel() versteckt war)
geschwindigkeit n Setze die Geschwindigkeit, mit der der Igel die Befehle abarbeitet, auf n (Ausgangswert ist 20)

Der Igel bewegt sich auf einem Quadrat mit der Seitenlänge 600. Der Startpunkt ist der Mittelpunkt, und der Igel zeigt in der Ausgangsposition nach oben.

Die verfügbaren Farben sind schwarz, weiß, rot, orange, blau, hellblau, grün, hellgrün, gelb, lila, grau, braun.

Siehe auch die Hilfe/FAQ-Seite

L-Systeme

L-Systeme (oder Lindenmayer-Systeme, benannt nach dem ungarischen Biologen A. Lindenmayer) sind ein Formalismus, mit dem sich sehr prägnante Beschreibungen geben lassen, wie man mit Igelgrafik gewisse selbstähnliche Strukturen zeichnet. Die Beschreibung besteht aus einem Anfangszustand und aus Ersetzungsregeln, die auf diesen Anfangszustand angewandt werden. Nach einigen Ersetzungen bekommt man eine Liste von Symbolen, die dann in eine Kette von Igel-Befehlen übersetzt und vom Igel abgearbeitet wird.

Viele pflanzliche Strukturen (Bäume, Blätter) lassen sich durch L-Systeme beschreiben.

Funktionsweise von L-Systemen

Ein L-System besteht aus den folgenden Informationen:

  • Ein Ausgangszustand
  • Ersetzungsregeln
  • Vorschriften, wie die vorkommenden Symbole in Igelgrafik-Befehle übersetzt werden (dies ist mehr oder weniger standardisiert, d.h. für jedes L-System gleich)

Gehen wir dies in einem Beispiel durch:

Ausgangszustand F-F-F-F

Ersetzungsregeln:

  • F: F-F+F+FF-F-F+F

(In diesem Beispiel gibt es nur eine Ersetzungsregel. Bei komplizierteren L-Systemen kann es für mehrere Symbole Ersetzungsregeln geben.)

Diese Ersetzungsregel wird nun auf den Ausgangszustand angewandt, d.h., alle Symbole, für die eine Ersetzungsregel definiert ist (hier nur das F) werden durch die in der Regel angegebene Zeichenkette ersetzt. Alle Symbole, für die keine Regel vorgegeben ist, bleiben einfach erhalten. Im ersten Schritt erhalten wir also

F-F+F+FF-F-F+F-F-F+F+FF-F-F+F-F-F+F+FF-F-F+F-F-F+F+FF-F-F+F

So machen wir nun weiter: Im zweiten Schritt wird auf die neue Zeichenkette die Ersetzungsregel(n) angewandt, und wir bekommen:

F-F+F+FF-F-F+F-F-F+F+FF-F-F+F+F-F+F+FF-F-F+F+F-F+F+FF-F-F+FF-F+F+FF-F-F+F-F-F+F+FF-F-F+F-F-F+F+FF-F-F+F+F-F+F+FF-F-F+F-F-F+F+FF-F-F+F-F-F+F+FF-F-F+F+F-F+F+FF-F-F+F+F-F+F+FF-F-F+FF-F+F+FF-F-F+F-F-F+F+FF-F-F+F-F-F+F+FF-F-F+F+F-F+F+FF-F-F+F-F-F+F+FF-F-F+F-F-F+F+FF-F-F+F+F-F+F+FF-F-F+F+F-F+F+FF-F-F+FF-F+F+FF-F-F+F-F-F+F+FF-F-F+F-F-F+F+FF-F-F+F+F-F+F+FF-F-F+F-F-F+F+FF-F-F+F-F-F+F+FF-F-F+F+F-F+F+FF-F-F+F+F-F+F+FF-F-F+FF-F+F+FF-F-F+F-F-F+F+FF-F-F+F-F-F+F+FF-F-F+F+F-F+F+FF-F-F+F

Die Zeichenkette wird also sehr schnell ziemlich lang. Je nachdem, wie viele Schritte man durchführt, bekommt man ein anderes Ergebnis. Oft sind zwischen 5 und 10 Schritten schon genug. Wenn die rechten Seiten der Ersetzungsregeln lang sind, dauert die Berechnung dann auch schon eine gewisse Zeit.

Zum Schluss wird das Ergebnis in eine Igelzeichnung übersetzt, und zwar wie folgt. Man nimmt die Zeichenkette, die man nach dem letzten durchgeführten Schritt erhalten hat, und lässt sie durch den Igel von links nach rechts abarbeiten. Dabei geht der Igel für jedes F 10 Schritte nach vorne (vor 10), dreht sich für jedes + um 90 Grad nach links (links 90), und dreht sich für jedes - um 90 Grad nach rechts (rechts 90). Bei anderen L-Systemen benutzt man gegebenenfalls eine andere Schrittweite und/oder einen anderen Winkel.

Das L-System in dem Beispiel hier produziert die sogenannte quadratische Koch-Insel.

L-Systeme auf der Igelgrafik-Seite

Die Igelgrafik-Seite stellt eine einfache Möglichkeit zur Verfügung, L-Systeme zu definieren, und dann vom Igel zeichnen zu lassen. Zunächst definiert man dazu folgendermaßen den Ausgangszustand (Axiom) und die Ersetzungsregeln:

  LSystem.setzeaxiom 'F-F-F-F'
  LSystem.setzeregeln
    'F': 'F-F+F+FF-F-F+F'

und die verwendete Distanz und Winkel:

  LSystem.distanz = 10
  LSystem.winkel = 90

Dann kann man das L-System wie folgt berechnen und zeichnen lassen. Die Zahl, die dem zeichnen-Befehl übergeben wird, ist die Anzahl der Ersetzungsschritte.

  LSystem.zeichnen 4

Verwendbare Symbole

Im Igelgrafik-L-System stehen die folgenden Symbole zur Verfügung, die in Igel-Befehle übersetzt werden. (Außerdem kann man zur Erzeugung des L-Systems auch andere Symbole verwenden, die der Igel dann ignoriert.)

Symbol Übersetzung in Igel-Befehl
A vor distanz
B vor distanz
F vor distanz
G vor distanz
H vor distanz
f stifthoch(); vor distanz; stiftrunter()
g stifthoch(); vor distanz; stiftrunter()
h stifthoch(); vor distanz; stiftrunter()
[ Speichere die aktuelle Position des Igels.
] Lasse den Igel zur zuletzt gespeicherten Position zurückkehren.
+ links winkel
- rechts winkel
| links 180
a stiftfarbe farbe1
b stiftfarbe farbe2
c stiftfarbe farbe3

Die Farben können mit den folgenden Befehlen eingestellt werden:

  LSystem.farbe1 = blau
  LSystem.farbe2 = rot
  LSystem.farbe3 = gelb

(Die hier angegebenen Farben sind die Voreinstellungen.)

Beispiele von L-Systemen

L-system gallery (Bernie Pope)
A gallery of L-systems

Links mit mehr Information

Wikipedia, deutsch
L-Systeme und andere künstliche Pflanzen (Florian Breier)

Wikipedia, englisch
Vorlesungsmaterial, englisch von Dr. Michael T.M. Emmerich & Dr. Andre Deutz; Webseite der Vorlesung

Iterierte Funktionensysteme

Iterierte Funktionen-Systeme (IFS) können zur Konstruktion von fraktalen Figuren benutzt werden. Dieser Weg, Fraktale zu konstruieren, wurde 1981 von John Hutchinson gefunden.

Barnsleys Kranz

Edgar, Math. Intelligencer 1991

Funktionsweise von IFS

Wir betrachten, um das Ergebnis hier gut darstellen zu können, IFS für die Ebene. (Aus mathematischer Sicht kann man analog auch höherdimensionale IFS betrachten.)

Die Grundbausteine sind dann Funktionen, die aus einem Punkt (x,y) der Ebene einen neuen Punkt (x', y') berechnen. Solche Funktionen können wir entsprechend auch in CoffeeScript modellieren; ein einfaches Beispiel wäre

 (x,y) -> [ -y, x ]

Diese Funktion berechnet zu einem Punkt sein Bild unter der Drehung um 90 Grad gegen den Uhrzeigersinn um den Ursprung.

IFS “funktionieren” in der Regel nur dann, wenn die benutzten Funktionen zusätzlich noch die folgende Eigenschaft haben: Wenden wir die Funktion auf zwei Punkte an, so ist der Abstand der beiden Bildpunkt kleiner als der Abstand der beiden ursprünglichen Punkte. Solche Funktionen nennt man kontrahierend.

Ein IFS besteht dann einfach aus einer oder mehreren (kontrahierenden) Funktionen. Die zugehörige fraktale Menge ist die Fixpunktmenge dieses Systems von Funktionen, d.h. die (eindeutig bestimmte) kompakte Teilmenge X der reellen Ebene, die von jeder der Funktionen in sich abgebildet wird.

Mathematisch gesehen beruht die Existenz und Eindeutigkeit der Fixpunktmenge auf dem Fixpunktsatz von Banach und dem Begriff der Hausdorff-Metrik. Siehe zum Beispiel die Diskussion auf den unten verlinkten Wikipedia-Seiten.

Interessanterweise lässt sich diese Fixpunktmenge, als das Fraktal, an dem wir interessiert sind, leicht darstellen (bzw. eine hinreichend gute Annäherung): Man startet mit einem beliebigen Punkt, zum Beispiel dem Ursprung (0,0), und wendet dann in zufälliger Reihenfolge die Funktionen aus dem IFS an. Die nächste Funktion wird immer auf den Punkt angewendet, den man im vorherigen Schritt erhalten hat. Macht man das oft genug (einige Tausend bis einige Hunderttausend Iterationen) und zeichnet die Punkte, die man so erhält, so bekommt man ein Bild, das (bis auf minimale Unterschiede) von der zufälligen Reihenfolge der Funktionen und auch vom Anfangspunkt unabhängig ist. (Die Punkte die man in den ersten Iterationen erhält, sollte man noch nicht einzeichnen, weil sonst doch der Anfangspunkt eine Rolle spielt; ein sinnvoller Wert ist, die ersten 20 Punkte auszulassen).

Bei einigen IFS kommt man schneller zum Ergebnis, wenn man die Funktionen nicht mit alle mit derselben Wahrscheinlichkeit anwendet, sondern jeweils für jede Funktion eine Wahrscheinlichkeit angibt, mit der sie ausgewählt werden soll.

IFS ausprobieren

Auf der Igelgrafik-Seite kann man IFS folgendermaßen ausprobieren:

Weil für die Darstellung des Fraktals zu einem IFS sehr viele einzelne Punkte anhand ihrer Koordinaten eingezeichnet werden, ist der Igel mit dieser Aufgabe “überfordert”. (IFS haben mit Igelgrafik nichts zu tun; es gibt allerdings einen indirekten Zusammenhang über die Theorie der L-Systeme.) Daher schalten wir als Erstes den Igel “aus”

canvasmodus()

und den “Canvas-Modus” ein. Dies ermöglicht es, wesentlich schneller einzelne Punkte zu zeichnen.

Um ein IFS zu definieren, müssen wir die zugehörigen Funktionen angeben, zum Beispiel

IFS.funktionen = [
      ((x,y) -> [0.27 * x, 0.25 * y + 0.5 + 0.15 * Math.sin(x+y)]),
      ((x,y) -> [0.82 * x + 0.474 * y + 0.3 - 0.01 * Math.cos(x-y), -0.4 * x + 0.8 * y - 0.1]) ]

In diesem Fall besteht das IFS aus zwei verschiedenen Funktionen.

Auf unserem Ausschnitt des Koordinatensystems sind die x-Achse und y-Achse jeweils von -300 bis 300 dargestellt. Zum Beispiel liegt der Punkt (150,150) in der Mitte des oberen rechten Viertels. Die Koordinaten der Punkte, die durch Anwendung der obigen Funktionen entstehen, sind aber recht kleine Zahlen. Wenn man sie direkt in unser Koordinatensystem einzeichnen würde, würde die Figur nur sehr klein dargestellt. Deshalb geben wir noch an, wie die Koordinaten vorher transformiert werden sollen:

IFS.transformiere = (x, y) => [ 200*x-50, 200*y+100]

(Als Standardeinstellung für IFS ist die Transformation (x, y) => [ 200*x, 200*y] vorgegeben. Der obige Befehl ändert das nur um eine Verschiebung um 50 Pixel nach rechts und um 100 Pixel nach oben. Je nach IFS ist es sinnvoll, andere “Vergrößerungsfaktoren” als 200 zu verwenden.)

Um ein gutes Ergebnis zu bekommen, sollte die zweite Funktion mit Wahrscheinlichkeit 90% aufgerufen werden, die erste nur mit Wahrscheinlichkeit 10%:

IFS.gewichtung = [0.1, 0.9]

Nun können wir den Iterationsprozess aufrufen, zum Beispiel so, dass 20 Punkte verdeckt berechnet werden, und dann 40000 Punkte gezeichnet werden:

IFS.zeichnen 40000

Die Farben kodieren, welche der zwei Funktionen als letzte angewandt wurde, um zu dem jeweiligen Bildpunkt zu kommen.

Affine Transformationen

Oft haben die Funktionen die folgende einfache Form:

(x,y) -> [ a*x + b*y + e, c*x + d*y + f ]

Der neue x- und y-Wert werden also einfach dadurch gebildet, dass die alten Werte mit gewissen fixierten Zahlen multipliziert werden, addiert werden, und dann noch eine weitere Zahl addiert wird. Solche Funktionen nennt man auch affine Transformationen. Um eine solche Funktion zu beschreiben, muss man einfach nur die Werte a, b, c, d, e und f kennen. Im Igelgrafik-Fenster kann man für diese affinen Transformationen die folgende Notation verwenden:

IFS.affin([a, b, c, d, e, f])

Konkret könnte man also das folgende IFS betrachten (von Paul Bourke, das Ergebnis sieht aus wie ein Blatt, siehe oben):

IFS.funktionen = (IFS.affin(l) für l in [
    [ 0.000000, 0.243900, 0.000000, 0.305300, 0.000000, 0.000000 ],
    [ 0.724800, 0.033700, -0.025300, 0.742600, 0.206000, 0.253800 ],
    [ 0.158300, -0.129700, 0.355000, 0.367600, 0.138300, 0.175000 ],
    [ 0.338600, 0.369400, 0.222700, -0.075600, 0.067900, 0.082600 ],
  ]
)

Wenn auf den unten verlinkten Seiten Beispiele von IFS einfach durch Sequenzen von Zahlen angegeben sind, dann handelt es sich um IFS, die durch affine Transformationen erzeugt werden. Befinden sich 7 Zahlen in einer Reihe, so sind üblicherweise die ersten 6 Zahlen wie oben zu interpretieren, und die 7. Zahl ist die Gewichtung, d.h. die Wahrscheinlichkeit, mit der die entsprechende Funktion ausgeführt werden sollte.

Weitere Beispiele von IFS

IFS Construction Kit Gallery (L. Riddle)
Gallery of Iterated Function System Images

Weitere Informationen

Wikipedia, deutsch
Wikipedia, englisch

Andere Fraktale

Hier sind einige Beispiele für andere bekannte Fraktale gesammelt.

Diese Fraktale wurden nicht mit den Igelbefehlen, sondern im Canvas-Modus gezeichnet. Dieser Modus wird mit dem Befehl

canvasmodus()

eingeschaltet. Der Igel funktioniert dann nicht mehr, aber dafür kann man wesentlich schneller einzelne Punkte einzeichnen, und zwar wird mit dem Befehl

plot x, y

ein Punkt an der Stelle (x, y) eingezeichnet. Dabei ist (0,0) die Mitte des Zeichenfensters, (-300, -300) die linke untere Ecke, (300, -300) die rechte untere Ecke, (300, 300) die rechte obere Ecke usw.

Mit dem Befehl

plotfarbe farbe

wird die Farbe eingestellt. Dabei muss farbe eine der Igelgrafik-Farben sein (schwarz, weiß, blau, …). Man kann stattdessen auch einen Ausdruck der Form '#1122AA' verwenden, also zum Beispiel farbe '#1122AA', um die Farbe mit dem RGB Code 1122AA einzustellen. Dabei werden der Rot-, Grün- und Blau-Wert jeweils mit einer zwei-stelligen Hexadezimalzahl angegeben.

Wenn man den Bildschirm-löschen-Button anklickt, wird der Canvas-Modus ausgeschaltet und der Igel “wiederbelebt”.