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 ♦♦ |
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 beantwortet 29 Jun '14, 12:50 stefan ♦♦ |
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} 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 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 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} 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. beantwortet 29 Jun '14, 12:39 stefan ♦♦ |