Eines meiner Dokumente, was sich mit Fraktalen beschäftigt, behandelt IFS-Fraktale (Iterated Function Systems). Ein iteriertes Funktionensystem bedeutet wiederholte Abbildungen eines Raumes in sich selbst, auf diese Weise lassen sich bekannte Fraktale wie das Sierpinski Dreieck, die Koch-Kurve und der Barnsley-Farn erzeugen.

Da ich in LaTeX schreibe, stellt sich mir die Frage: wie lassen sich IFS-Fraktale direkt in LaTeX erzeugen und ausgeben?

Mögliche Tools wären beispielsweise LuaTeX, expl3, PGF und PostScript für die Berechnung sowie TikZ, PSTricks, pgfplots und mplib für die Ausgabe. Es ließen sich natürlich auch MetaPost und Asymptote integrieren, auch wenn "ein bisschen extern".

Ich werde mit einer Antwort mit LuaTeX und pgfplots für den Barnsley-Farn beginnen.

Wer schafft alternative Wege für dieses und andere IFS-Fraktale?

gefragt 29 Jun '14, 12:29

stefan's gravatar image

stefan ♦♦
18.3k163148
Akzeptiert-Rate: 50%


Das folgende kleine Dokument berechnet und druckt einen Barnsley-Farn mittels des sog. Chaos Games: zufällig ausgewählte Transformationen werden wiederholt angewendet.

Hier verwende ich Lua zur Berechnung und pgfplots für die Ausgabe. Daher wird LuaLaTeX benötigt. Die Matrix m enthält die Koordinaten für die affinen Transformationen sowie ihre Wahrscheinlichkeiten, die dann summiert separat in der Wahrscheinlichkeitsmatrix pm abgelegt werden, damit ich nicht in der Schleife mehr addieren muss. Die Matrix-Schreibweise vereinfacht Veränderungen der Parameter.

Vorsicht, das Übersetzen dauert sehr lang! Ich habe 100000 Punkte berechnen lassen, wer das hier mal laufen lassen will, sollte zunächst einen viel kleineren Wert nehmen.

Open in writeLaTeX
\documentclass[tikz]{standalone}
\usepackage{pgfplots}
\usepackage{luacode}
\begin{luacode*}
  function barnsley(iterations,options)
    local x = math.random()
    local y = math.random()
    local m = {
        0.0,   0.0,   0.0, 0.16, 0.0,  0.0, 0.01,
       0.85,  0.04, -0.04, 0.85, 0.0,  1.6, 0.85,
        0.2, -0.26,  0.23, 0.22, 0.0,  1.6, 0.07,
      -0.15,  0.28,  0.26, 0.24, 0.0, 0.44, 0.07
    }
    local pm = { m[7], m[7] + m[14], m[7] + m[14] + m[21] }
    if options ~= [[]] then
      tex.sprint("\\begin{axis}[hide axis]\\addplot["
        .. options .. "] coordinates{")
    else
      tex.sprint("\\addplot coordinates{")
    end
    for i=1, iterations do
      p = math.random()
      if     p < pm[1] then
        case = 0
      elseif p < pm[2] then
        case = 1
      elseif p < pm[3] then
        case = 2
      else
        case = 3
      end
      newx = (m[7*case+1] * x) + (m[7*case+2] * y) + m[7*case+5]
         y = (m[7*case+3] * x) + (m[7*case+4] * y) + m[7*case+6]
         x = newx
      tex.sprint("("..x..","..y..")")
    end
    tex.sprint("};\\end{axis}")
  end
\end{luacode*}
\begin{document}
\begin{tikzpicture}
  \directlua{barnsley(100000, [[color=green!50!black, only marks,
    mark size = 0.05pt]])}
\end{tikzpicture}
\end{document}

Barnsley-Farn

Die Matrix kann man verändern, um Fraktale zu erhalten, die mehr einem Baum, einem Busch oder anderen Farnen ähneln. Beispielsweise mit Werten von der oben verlinkten Wikipedia-Seite (m.E. original von David Nicolls)

Open in writeLaTeX
   0.0,   0.0,   0.0, 0.25, 0.0, -0.14, 0.02,
  0.85,  0.02, -0.02, 0.83, 0.0,   1.0, 0.84,
  0.09, -0.28,   0.3, 0.11, 0.0,   0.6, 0.07,
 -0.09,  0.28,   0.3, 0.09, 0.0,   0.7, 0.07

Leptosporangiate-Farn

Open in writeLaTeX
    0.0,   0.0,    0.0, 0.25,    0.0,  -0.4, 0.02,
   0.95, 0.005, -0.005, 0.93, -0.002,   0.5, 0.84,
  0.035,  -0.2,   0.16, 0.04,  -0.09,  0.02, 0.07,
  -0.04,   0.2,   0.16, 0.04,  0.083,  0.12, 0.07

Thelypteridaceae-Farn

Mit einer einfacheren Matrix und damit leicht verkürztem Code erhält man ein Sierpinski-Dreieck:

Open in writeLaTeX
\documentclass[tikz]{standalone}
\usepackage{pgfplots}
\usepackage{luacode}
\begin{luacode*}
  function ifs(iterations,options)
    local x = math.random()
    local y = math.random()
    local m = {
       0.5, 0, 0, 0.5,    0,   0, 0.3333,
       0.5, 0, 0, 0.5, 0.25, 0.5, 0.3333,
       0.5, 0, 0, 0.5,  0.5,   0, 0.3333,
    }
    local pm = { m[7], m[7] + m[14], m[7] + m[14] }
    if options ~= [[]] then
      tex.sprint("\\begin{axis}[hide axis]\\addplot["
        .. options .. "] coordinates{")
    else
      tex.sprint("\\addplot coordinates{")
    end
    for i=1, iterations do
      p = math.random()
      if     p < pm[1] then
        case = 0
      elseif p < pm[2] then
        case = 1
      else
        case = 2
      end
      newx = (m[7*case+1] * x) + (m[7*case+2] * y) + m[7*case+5]
         y = (m[7*case+3] * x) + (m[7*case+4] * y) + m[7*case+6]
         x = newx
      tex.sprint("("..x..","..y..")")
    end
    tex.sprint("};\\end{axis}")
  end
\end{luacode*}
\begin{document}
\begin{tikzpicture}
  \directlua{ifs(20000, [[color=black, only marks,
    mark size = 0.05pt]])}
\end{tikzpicture}
\end{document}

Sierpinski-Dreieck

Analog kann man einen Sierpinski-Teppich erhalten, und in 3D einen Menger-Schwamm aka Menger sponge. Bei letzterem stellt sich dann die Frage einer guten dreidimensionalen Darstellung.

Permanenter link

beantwortet 29 Jun '14, 12:39

stefan's gravatar image

stefan ♦♦
18.3k163148
Akzeptiert-Rate: 50%

bearbeitet 29 Jun '14, 14:35

PSTricks bietet auch einen Barnsley-Farn, in Postscript samt darin codierten Transformations-Parameter und Wahrscheinlichkeiten. Direkt in LaTeX lässt sich daher nicht so leicht experimentieren, doch es ist eine sehr gute Demonstration. Und man kann ja selber auch den Postscript-Code übernehmen und ändern.

Anwendung, einfach mit XeLaTeX zu übersetzen oder auch durch LaTeX im DVI Modus mit nachfolgendem dvips und ggf. ps2pdf:

Open in writeLaTeX
\documentclass{standalone}
\usepackage{pstricks}
\usepackage{pst-fractal}
\begin{document}
\begin{pspicture}(-3,0)(3,11)
  \psFern[scale=30, maxIter=200000, linecolor=green]
\end{pspicture}
\end{document}

Der eigentliche Code steht in pst-fractal.pro:

Open in writeLaTeX
/tx@Fern { %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%    \pst@fractal@scale 
%    \pst@tempA 
%    \pst@fractal@maxIter
%    \pst@fractal@radius
%    \pst@number\pslinewidth
%    { \pst@usecolor\pslinecolor }
  /setColor ED
  SLW
  /radius ED
  /maxIter ED  
  translate
  dup scale
  /m1 [  0.00  0.00  0.00  0.16  0.00 0.00 ] def
  /m2 [  0.85 -0.04  0.04  0.85  0.00 1.60 ] def
  /m3 [  0.20  0.23 -0.26  0.22  0.00 1.60 ] def
  /m4 [ -0.15  0.26  0.28  0.24  0.00 0.44 ] def
  1 setlinecap
  setColor
  0 0 % start point
  maxIter cvi {
  % get a transformation matrix probabilistically
  /r rand 100 mod def
  r  1 lt { /m m1 def }{ r 86 lt 
    { /m m2 def }{ r 93 lt { 
      /m m3 def }{ /m m4 def } ifelse } ifelse } ifelse
  % Make a linear transformation, then
  % plot a point at current location
   m transform 2 copy radius 0 360 arc
   stroke
  } repeat
} def

Barnsley-Farn

Permanenter link

beantwortet 29 Jun '14, 12:50

stefan's gravatar image

stefan ♦♦
18.3k163148
Akzeptiert-Rate: 50%

bearbeitet 29 Jun '14, 12:55

Deine Antwort
Vorschau umschalten

Folgen dieser Frage

Per E-Mail:

Wenn sie sich anmelden, kommen Sie für alle Updates hier in Frage

Per RSS:

Antworten

Antworten und Kommentare

Markdown-Grundlagen

  • *kursiv* oder _kursiv_
  • **Fett** oder __Fett__
  • Link:[Text](http://url.com/ "Titel")
  • Bild?![alt Text](/path/img.jpg "Titel")
  • nummerierte Liste: 1. Foo 2. Bar
  • zum Hinzufügen ein Zeilenumbruchs fügen Sie einfach zwei Leerzeichen an die Stelle an der die neue Linie sein soll.
  • grundlegende HTML-Tags werden ebenfalls unterstützt

Frage-Themen:

×730
×298
×28
×5

gestellte Frage: 29 Jun '14, 12:29

Frage wurde gesehen: 13,642 Mal

zuletzt geändert: 29 Jun '14, 14:35