TikZ解決方案

TikZ解決方案

我正在嘗試使用 tikz 重新建立這個精確的圖表。到目前為止,我一直在嘗試在 tikz 中使用嵌套裝飾,因為我將它們用於其他分形結構。然而,這些結構要么都是 tikz 預先定義的裝飾,例如科赫曲線,要么是我在堆疊交換中找到的解決方案,例如謝爾賓斯基三角形。

我一直在研究定義自己的裝飾,但對於 tikz 新手來說,這似乎是一個相當複雜的過程,並且沒有找到任何與我想要做的事情太相似的例子。我知道也可以使用 lindemayer 系統,但只了解如何使用它們進行線路建設。

如果有幫助的話,在我看來,最簡單的方法似乎是將正方形設置為初始形狀,原點位於左下角,然後對左下角的正方形縮放 1/4,縮放 1/ 4 然後向上平移左上角的正方形等,然後設定新形狀來取代初始形狀,為下一次迭代做好準備。

有問題的分形

任何幫助將非常感激!

答案1

這是 Lindenmayer 系統的一種方法。對於 5 以上的命令,使用 LuaLaTeX 進行編譯。

% \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}

在此輸入影像描述

這是一種裝飾方式:

\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}

在此輸入影像描述

答案2

TikZ解決方案

分形的黑色方塊是透過可擴展的遞迴.

\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}

由於整個繪圖命令都保存在記憶體中,因此記憶體是限制因素。

訂單 5 的結果:

訂單 5

IniTeX解決方案

以下範例使用 iniTeX 中的簡單規則來繪製方塊以獲得更高的階數,而不會耗盡記憶體。

TeX 中的最大尺寸為 16383.99998 pt ( \maxdimen)。這是 (2 30 - 1) sp (1 pt = 2 16 sp = 65536 sp)。下一級的最小正方形使用四分之一的正方形邊長。那麼,最小平方邊長為 1 sp,最大階數為 14,則結果的邊長為 2 28 sp。

此範例在 iniTeX 模式下使用 pdfTeX 或 luaTeX(pdftex -ini -etexluatex -ini)。 LuaTeX 速度更快,記憶體限制更少。相較之下,pdfTeX 中的 8 階大約需要 45 秒,而 LuaTeX 則需要 8 秒。 LuaTeX 的更高階:

  • 訂單 10:時間為 3 3/4 分鐘,檔案大小為 47 MiB。

  • 命令 11:時間為 33 分鐘,檔案大小為 173 MiB。

在命令 12 處,計算機放棄了,我不得不重新啟動。

例子:

\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

訂單 11 的結果(imgur 拒絕更好的解析度):

結果,訂單 11

由於方塊數量眾多,查看更高階的 PDF 會降低 PDF 檢視器的速度。

因此,產生單色點陣圖影像是更有效的,例如使用最小的正方形作為1 x 1像素的正方形。 11 階的影像寬度和高度為 2 22像素 = 4194304 像素。

答案3

這是 MetaPost 的一次嘗試,他可能會感興趣。square_fractal該程式基礎上的遞歸巨集 ( ) 深受以下啟發這個答案密切相關的主題

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.

在此輸入影像描述

從 0 階(整個方形)開始,MetaPost 在我的機器上管理高達 6 階的輸出。有趣的是,如果前面的程式碼包含在 LuaLaTeX 程式中,則達到 7 階。我不知道為什麼。

編輯仍然在 LuaLaTeX 中,並且在使用浮點數字(\mplibnumbersystem{double}在後面添加\usepackage{luamplib})而不是默認的定點數字之後,MetaPost 設法在 20 分鐘後生成 9 階的數字。但它幾乎凍結了我非常舊的筆記型電腦(2008 年的 MacBook Pro),所以我不敢更進一步。也許我會在一台更新、功能更強大的電腦上再試一次。

\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}

下圖是訂單8的一張。

在此輸入影像描述

答案4

Tikz 和遞歸的另一種選擇。

\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}

在此輸入影像描述

相關內容