Ich versuche, dieses genaue Diagramm mit Tikz nachzubilden. Bisher habe ich versucht, verschachtelte Dekorationen in Tikz zu verwenden, da ich diese für andere fraktale Konstruktionen verwendet habe. Diese Konstruktionen waren jedoch alle entweder von Tikz vordefinierte Dekorationen wie die Koch-Kurve oder solche, für die ich auf Stack Exchange Lösungen gefunden habe, wie das Sierpinski-Dreieck.
Ich habe viel darüber nachgedacht, meine eigenen Dekorationen zu definieren, aber es scheint ein ziemlich komplizierter Prozess für einen Tikz-Neuling zu sein, und ich habe keine Beispiele gefunden, die dem, was ich versuche, allzu ähnlich sind. Ich weiß, dass es auch mit Lindemayer-Systemen möglich sein wird, aber ich verstehe nur, wie man sie für Linienkonstruktionen verwendet.
Falls es hilft: Meiner Ansicht nach besteht die einfachste Möglichkeit darin, das Quadrat als Ausgangsform mit Ursprung unten links festzulegen, dann das untere linke Quadrat um 1/4 zu skalieren, das obere linke Quadrat um 1/4 zu skalieren und dann nach oben zu verschieben usw. und dann die neue Form so festzulegen, dass die Ausgangsform ersetzt wird, und bereit für die nächste Iteration zu sein.
Jede Hilfe wäre sehr willkommen!
Antwort1
Hier ist eine Möglichkeit mit einem Lindenmayer-System. Bei Bestellungen über 5 mit LuaLaTeX kompilieren.
% \RequirePackage{luatex85} % Only for LuaLaTeX and standalone class
\documentclass[varwidth,border=5]{standalone}
\usepackage{tikz}
\usetikzlibrary{lindenmayersystems}
\pgfdeclarelindenmayersystem{square fractal}{%
\symbol{S}{\pgflsystemstep=0.5\pgflsystemstep}
\symbol{A}{\pgftransformshift%
{\pgfqpoint{0.75\pgflsystemstep}{0.75\pgflsystemstep}}}
\symbol{R}{\pgftransformrotate{90}}
\symbol{Q}{%
\pgfpathrectangle{\pgfqpoint{-0.5\pgflsystemstep}{-0.5\pgflsystemstep}}%
{\pgfqpoint{\pgflsystemstep}{\pgflsystemstep}}%
}
\rule{Q -> [SQ[ASQ][RASQ][RRASQ][RRRASQ]]}
}
\begin{document}
\foreach\i in {0,...,5}{%
\tikz\fill [l-system={square fractal, step=5cm, axiom=Q, order=\i}]
lindenmayer system;
\ifodd\i\par\bigskip\leavevmode\fi
}
\end{document}
Und hier ist eine Möglichkeit mit Dekorationen:
\documentclass[varwidth,border=5]{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations}
\pgfdeclaredecoration{square fractal}{start}{
\state{start}[width=0pt,next state=draw]{
\pgfpathmoveto{\pgfpointdecoratedinputsegmentfirst}
}
\state{draw}[width=\pgfdecoratedinputsegmentlength]{
\pgfpointdiff{\pgfpointdecoratedinputsegmentfirst}%
{\pgfpointdecoratedinputsegmentlast}
\pgfgetlastxy\tmpx\tmpy
\pgfmathveclen\tmpx\tmpy
\pgfmathparse{\pgfmathresult/4}%
\let\tmp=\pgfmathresult
\pgfpathlineto{\pgfpoint{\tmp}{+0pt}}
\pgfpathlineto{\pgfpoint{\tmp}{-\tmp}}
\pgfpathlineto{\pgfpoint{3*\tmp}{-\tmp}}
\pgfpathlineto{\pgfpoint{3*\tmp}{+0pt}}
\pgfpathlineto{\pgfpointdecoratedinputsegmentlast}
}
\state{final}{
\pgfpathclose
}
}
\begin{document}
\tikz[decoration=square fractal]
\fill (0,0) rectangle (4,4);
\tikz[decoration=square fractal]
\fill decorate { (0,0) rectangle (4,4) };
\\
\tikz[decoration=square fractal]
\fill decorate { decorate { (0,0) rectangle (4,4) } };
\tikz[decoration=square fractal]
\fill decorate { decorate { decorate { (0,0) rectangle (4,4) } } };
\end{document}
Antwort2
TikZ-Lösung
Die schwarzen Quadrate des Fraktals werden erzeugt durch einerweiterbarRekursion.
\documentclass[tikz]{standalone}
\usepackage{etoolbox}
\makeatletter
\patchcmd{\tikz@@command@path}{=100}{=10000}{}{\errmessage{Patching failed.}}
\makeatother
\makeatletter
\newcommand*{\@SquareFractal}[4]{%
% #1: order
% #2: edge length
% #3: x position of lower left corner
% #4: y position of lower left corner
\ifnum#1=0
(#3,#4)rectangle(\the\dimexpr(#3)+(#2)\relax,\the\dimexpr(#4)+(#2)\relax)%
\expandafter\@gobble
\else
\expandafter\@firstofone
\fi
{
% Middle
\expandafter\@SquareFractal
\expandafter{\the\numexpr(#1)-1\expandafter}%
\expandafter{\the\dimexpr(#2)/2\expandafter}%
\expandafter{\the\dimexpr(#3)+(#2)/4\expandafter}%
\expandafter{\the\dimexpr(#4)+(#2)/4}%
% Bottom left
\expandafter\@SquareFractal
\expandafter{\the\numexpr(#1)-1\expandafter}%
\expandafter{\the\dimexpr(#2)/4}%
{#3}%
{#4}%
% Bottom right
\expandafter\@SquareFractal
\expandafter{\the\numexpr(#1)-1\expandafter}%
\expandafter{\the\dimexpr(#2)/4\expandafter}%
\expandafter{\the\dimexpr(#3)+(#2)*3/4}%
{#4}%
% Top left
\expandafter\@SquareFractal
\expandafter{\the\numexpr(#1)-1\expandafter}%
\expandafter{\the\dimexpr(#2)/4\expandafter}%
\expandafter{\the\dimexpr(#3)\expandafter}%
\expandafter{\the\dimexpr(#4)+(#2)*3/4}%
% Top right
\expandafter\@SquareFractal
\expandafter{\the\numexpr(#1)-1\expandafter}%
\expandafter{\the\dimexpr(#2)/4\expandafter}%
\expandafter{\the\dimexpr(#3)+(#2)*3/4\expandafter}%
\expandafter{\the\dimexpr(#4)+(#2)*3/4}%
}%
}
\newcommand*{\SquareFractal}[2]{%
% #1: order
% #2: edge length
\begingroup
\edef\x{\@SquareFractal{#1}{#2}{0pt}{0pt}}%
\expandafter\tikz\expandafter\fill\x;%
\endgroup
}
\makeatother
\begin{document}
\foreach\i in {0, ..., 5} {\SquareFractal{\i}{\linewidth}}
\end{document}
Da alle Zeichenbefehle im Speicher vorgehalten werden, stellt der Speicher den limitierenden Faktor dar.
Ergebnis für Auftrag 5:
IniTeX-Lösung
Das folgende Beispiel verwendet einfache Regeln in iniTeX zum Zeichnen der Quadrate, um höhere Ordnungen zu erhalten, ohne dass der Speicher überlastet wird.
Die maximale Dimension in TeX beträgt 16383,99998 pt ( \maxdimen
). Das sind (2 30 - 1) sp (1 pt = 2 16 sp = 65536 sp). Die kleinsten Quadrate der nächsten Ebene haben eine Quadratkantenlänge von einem Viertel. Daraus folgt, dass bei der kleinsten Quadratkantenlänge von 1 sp die größte Ordnung 14 ist, die Kantenlänge des Ergebnisses ist dann 2 28 sp.
Das Beispiel verwendet entweder pdfTeX oder luaTeX im iniTeX-Modus ( pdftex -ini -etex
oder luatex -ini
). LuaTeX ist schneller und hat weniger Speicherbeschränkungen. Zum Vergleich: Ordnung 8 dauert mit pdfTeX etwa 45 s, mit LuaTeX jedoch 8 s. Höhere Ordnungen mit LuaTeX:
Bestellung 10:Die Zeit beträgt 3 3/4 Minuten, die Dateigröße 47 MiB.
Bestellung 11:Zeit beträgt 33 Minuten, Dateigröße beträgt 173 MiB.
Bei Befehl 12 gab der Computer auf und ich musste neu starten.
Beispiel:
\catcode`\{=1
\catcode`\}=2
\catcode`\#=6
\ifx\directlua\undefined
\pdfoutput=1
\pdfminorversion=4
\pdfhorigin=0pt
\pdfvorigin=0pt
\pdfcompresslevel=9
\else
\directlua{%
tex.enableprimitives('', {'outputmode', 'dimexpr', 'numexpr'})
tex.enableprimitives('pdf', {'pagewidth', 'pageheight'})
}
\outputmode=1
\directlua{
pdf.setorigin()
pdf.setminorversion(4)
pdf.setcompresslevel(9)
}
\fi
\dimendef\pagewidth=0
\dimendef\xpos=2
\def\SquareFractal#1#2{%
% #1: order
% #2: minimum edge length
\pagewidth=\dimexpr#2\MulFour#1!\relax
\immediate\write16{* Calculating square fractal of order #1 ...}%
\pdfpagewidth=\pagewidth %
\pdfpageheight=\pagewidth %
\shipout\hbox{%
\xpos=0pt\relax
\SquareFractalRecursiv#1!\pagewidth!0pt!0pt!%
\kern\dimexpr\pagewidth-\xpos\relax
}%
\advance\count0 by 1\relax
}
\def\MulFour#1!{%
\ifnum#1=0
\else
*4%
\expandafter\MulFour
\the\numexpr#1-1\expandafter!%
\fi
}
\def\SquareFractalRecursiv#1!#2!#3!#4!{%
% #1: order
% #2: edge length
% #3: x position of lower left corner
% #4: y position of lower left corner
\ifnum#1=0 %
\iffalse
\raise#4\hbox to 0pt{%
\kern#3\relax
\vrule width#2height#2\relax
\hss
}%
\else
\ifdim#3=\xpos
\else
\kern\dimexpr#3-\xpos\relax
\fi
\vrule width#2 depth-#4 height\dimexpr#4+#2\relax
\xpos=\dimexpr#3+#2\relax
\fi
\else
% Lower left square
\expandafter\SquareFractalRecursiv
\the\numexpr#1-1\expandafter!%
\the\dimexpr#2/4\expandafter!%
#3!%
#4!%
% Middle square
\expandafter\SquareFractalRecursiv
\the\numexpr#1-1\expandafter!%
\the\dimexpr#2/2\expandafter!%
\the\dimexpr#3+#2/4\expandafter!%
\the\dimexpr#4+#2/4!%
% Lower right square
\expandafter\SquareFractalRecursiv
\the\numexpr#1-1\expandafter!%
\the\dimexpr#2/4\expandafter!%
\the\dimexpr#3+#2*3/4!%
#4!%
% Upper left square
\expandafter\SquareFractalRecursiv
\the\numexpr#1-1\expandafter!%
\the\dimexpr#2/4\expandafter!%
\the\dimexpr#3\expandafter!%
\the\dimexpr#4+#2*3/4!%
% Upper right square
\expandafter\SquareFractalRecursiv
\the\numexpr#1-1\expandafter!%
\the\dimexpr#2/4\expandafter!%
\the\dimexpr#3+#2*3/4\expandafter!%
\the\dimexpr#4+#2*3/4\expandafter!%
\fi
}
% BTW, unit bp instead of pt decreases the output file size
% a bit because of less fractional digits.
% \SquareFractal{<order>}{<length of smallest square>}
% The values of the follwing calls are used in such a way
% that the generated fractals with different orders have
% the same widths and heights.
\SquareFractal{0}{4096pt}
\SquareFractal{1}{1024pt}
\SquareFractal{2}{256pt}
\SquareFractal{3}{64pt}
\SquareFractal{4}{16pt}
\SquareFractal{5}{4pt}
\SquareFractal{6}{1pt}% 65536 sp
\SquareFractal{7}{16384sp}
\SquareFractal{8}{4096sp}
\SquareFractal{9}{1024sp}
\SquareFractal{10}{256sp}
\SquareFractal{11}{64sp}
% \SquareFractal{12}{16sp}
% \SquareFractal{13}{4sp}
% \SquareFractal{14}{1sp}
\end
Ergebnis für Bestellung 11 (bessere Auflösungen werden von imgur abgelehnt):
Aufgrund der schieren Anzahl an Quadraten verlangsamt das Anzeigen einer PDF-Datei mit höheren Ordnungen den PDF-Viewer.
Effizienter ist es daher, ein monochromes Bitmap-Bild zu erzeugen, z.B. mit den kleinsten Quadraten als Quadrate von 1 x 1 Pixel. Die Bildbreite und -höhe für die Ordnung 11 beträgt dann 2 22 Pixel = 4194304 Pixel.
Antwort3
Hier ist ein Versuch mit MetaPost, für wen es interessant sein könnte. Das rekursive Makro ( square_fractal
) an der Basis dieses Programms ist stark inspiriert vondiese AntwortZuein eng verwandtes Thema.
vardef square_fractal(expr A, B, n) =
save P; pair P[]; P0 = A; P1 = B;
for i = 1 upto 2:
P[i+1] = P[i-1] rotatedaround (P[i], -90);
endfor;
if n = 0: fill P0 for i = 1 upto 3: -- P[i] endfor -- cycle;
else:
save Q; pair Q[];
for i = 0, 2:
Q[i] = 1/4[P[i],P[i+1]]; Q[i+1] = 3/4[P[i],P[i+1]];
square_fractal(P[i], Q[i], n-1);
square_fractal(Q[i+1], P[i+1], n-1);
endfor;
square_fractal(P0 rotatedaround (Q0, -90), P1 rotatedaround (Q1, 90), n-1); fi
enddef;
beginfig(1);
for n = 0 upto 4:
draw image(square_fractal(origin, (4cm, 0), n)) shifted (n*4.5cm, 0);
endfor;
endfig;
end.
Ausgehend von der Ordnung 0 (dem vollen Quadrat) schafft MetaPost auf meiner Maschine eine Ausgabe bis zur Ordnung 6. Interessanterweise wird Ordnung 7 erreicht, wenn der vorherige Code in ein LuaLaTeX-Programm eingebunden wird. Den Grund dafür kenne ich nicht.
BearbeitenNoch immer innerhalb von LuaLaTeX und nach Verwendung von Fließkommazahlen (die \mplibnumbersystem{double}
direkt danach hinzugefügt wurden \usepackage{luamplib}
) anstelle der standardmäßigen Festkommazahlen schafft es MetaPost, die Zahl in der Größenordnung von 9 nach 20 Minuten zu erzeugen. Allerdings friert es meinen sehr alten Laptop (ein MacBook Pro von 2008) fast ein, sodass ich mich nicht traue, damit weiterzumachen. Vielleicht werde ich es auf einem neueren und leistungsstärkeren Computer noch einmal versuchen.
\RequirePackage{luatex85}
\documentclass[border=5mm]{standalone}
\usepackage{luamplib}
\mplibnumbersystem{double}
\begin{document}
\begin{mplibcode}
vardef square_fractal(expr A, B, n) =
save P; pair P[]; P0 = A; P1 = B;
for i = 1 upto 2:
P[i+1] = P[i-1] rotatedaround (P[i], -90);
endfor;
if n = 0: fill P0 for i = 1 upto 3: -- P[i] endfor -- cycle;
else:
save Q; pair Q[];
for i = 0, 2:
Q[i] = 1/4[P[i],P[i+1]]; Q[i+1] = 3/4[P[i],P[i+1]];
square_fractal(P[i], Q[i], n-1);
square_fractal(Q[i+1], P[i+1], n-1);
endfor;
square_fractal(P0 rotatedaround (Q0, -90), P1 rotatedaround (Q1, 90), n-1); fi
enddef;
beginfig(1);
square_fractal(origin, (12cm, 0), 9);
endfig;
\end{mplibcode}
\end{document}
Die folgende Abbildung zeigt die Ordnung 8. Ich konnte keine PNG-Version der Ordnung 9 erstellen, da mein Laptop fast eingefroren war.
Antwort4
Eine weitere Alternative mit Tikz und Rekursion.
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\newcommand\DrawFracSquare[4]{{% {Current number}{Side Length}{X}{Y}
\ifnum#1=0
\fill[black] ($(#3,#4)-(#2/2,#2/2)$) rectangle +(#2,#2);
\else
\pgfmathsetmacro\NewNumber{int(#1-1)}
\pgfmathsetmacro\NewSideLength{#2/2}
\edef\NewRec{\noexpand\DrawFracSquare{\NewNumber}{\NewSideLength}{#3}{#4}}
\NewRec
\pgfmathsetmacro\NewSideLength{#2/4}
\pgfmathsetmacro\NewX{#3+3*#2/8}
\pgfmathsetmacro\NewY{#4+3*#2/8}
\edef\NewRec{\noexpand\DrawFracSquare{\NewNumber}{\NewSideLength}{\NewX}{\NewY}}
\NewRec
\pgfmathsetmacro\NewX{#3-3*#2/8}
\pgfmathsetmacro\NewY{#4+3*#2/8}
\edef\NewRec{\noexpand\DrawFracSquare{\NewNumber}{\NewSideLength}{\NewX}{\NewY}}
\NewRec
\pgfmathsetmacro\NewX{#3-3*#2/8}
\pgfmathsetmacro\NewY{#4-3*#2/8}
\edef\NewRec{\noexpand\DrawFracSquare{\NewNumber}{\NewSideLength}{\NewX}{\NewY}}
\NewRec
\pgfmathsetmacro\NewX{#3+3*#2/8}
\pgfmathsetmacro\NewY{#4-3*#2/8}
\edef\NewRec{\noexpand\DrawFracSquare{\NewNumber}{\NewSideLength}{\NewX}{\NewY}}
\NewRec
\fi
}}
\begin{document}
\begin{tikzpicture}
\DrawFracSquare{0}{3}{0}{4}
\DrawFracSquare{1}{3}{4}{4}
\DrawFracSquare{2}{3}{8}{4}
\DrawFracSquare{3}{3}{0}{0}
\DrawFracSquare{4}{3}{4}{0}
\DrawFracSquare{5}{3}{8}{0}
\end{tikzpicture}
\end{document}