TikZソリューション

TikZソリューション

私は tikz を使用してこの図を正確に再現しようとしています。これまでは、他のフラクタル構造に使用していたため、tikz でネストされた装飾を使用しようとしてきました。ただし、これらの構造はすべて、コッホ曲線のように tikz によって事前に定義された装飾か、シェルピンスキーの三角形のように Stack Exchange で解決策を見つけた装飾のいずれかでした。

独自の装飾を定義する方法についていろいろ調べてきましたが、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) です。次のレベルの最小の正方形では、正方形の辺の長さは 4 分の 1 になります。次に、最小の正方形の辺の長さが 1 sp の場合、最大次数は 14 となり、結果の辺の長さは 2 28 sp になります。

pdftex -ini -etexこの例では、iniTeX モード (または)で pdfTeX または luaTeX を使用しますluatex -ini。LuaTeX の方が高速で、メモリ制限も少なくなります。比較すると、8 番目のオーダーは pdfTeX では約 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.

ここに画像の説明を入力してください

私のマシンでは、MetaPost は 0 次 (完全な正方形) から始めて 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 のものです。ラップトップがフリーズしそうになったため、次数 9 の PNG バージョンを作成できませんでした。

ここに画像の説明を入力してください

答え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}

ここに画像の説明を入力してください

関連情報