Solução TikZ

Solução TikZ

Estou tentando recriar esse diagrama exato usando tikz. Até agora, tenho tentado usar decorações aninhadas no tikz, já que as usei para outras construções fractais. No entanto, essas construções eram todas decorações pré-definidas pelo tikz, como a curva de Koch, ou aquelas para as quais encontrei soluções na troca de pilhas, como o triângulo de Sierpinski.

Tenho procurado muito definir minhas próprias decorações, mas parece um processo bastante complicado para um novato em tikz e não encontrei nenhum exemplo muito semelhante ao que estou tentando fazer. Sei que também será possível utilizar sistemas Lindemayer, mas só entendo como utilizá-los para construções de linhas.

Se ajudar, na minha opinião, parece que a maneira mais simples de fazer isso seria definir o quadrado como a forma inicial com origem no canto inferior esquerdo e, em seguida, dimensionar em 1/4 para o quadrado inferior esquerdo, dimensionar em 1/ 4, em seguida, transfira para cima para o quadrado superior esquerdo, etc. e, em seguida, defina a nova forma para substituir a inicial, pronta para a próxima iteração.

O fractal em questão

Qualquer ajuda seria muito apreciada!

Responder1

Aqui está uma maneira com um sistema Lindenmayer. Para pedidos acima de 5, compile com 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}

insira a descrição da imagem aqui

E aqui está um jeito de decorar:

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

insira a descrição da imagem aqui

Responder2

Solução TikZ

Os quadrados pretos do fractal são gerados através de umexpansívelrecursão.

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

Como todos os comandos de desenho são mantidos na memória, a memória é o fator limitante.

Resultado do pedido 5:

Pedido 5

Solução IniTeX

O exemplo a seguir usa regras simples no iniTeX para desenhar quadrados para obter ordens mais altas sem ficar sem memória.

A dimensão máxima no TeX é 16383,99998 pt ( \maxdimen). Isto é (2 30 - 1) sp (1 pt = 2 16 sp = 65536 sp). Os menores quadrados do próximo nível usam uma borda quadrada com comprimento de um quarto. Então, segue-se que com o menor comprimento da aresta quadrada de 1 sp, a maior ordem é 14, o comprimento da aresta do resultado é então 2 28 sp.

O exemplo usa pdfTeX ou luaTeX no modo iniTeX ( pdftex -ini -etexou luatex -ini). LuaTeX é mais rápido e tem menos restrições de memória. Para efeito de comparação, a ordem 8 leva cerca de 45 segundos com o pdfTeX, mas 8 segundos com o LuaTeX. Pedidos mais altos com LuaTeX:

  • Pedido 10:o tempo é de 3 3/4 min, o tamanho do arquivo é de 47 MiB.

  • Pedido 11:o tempo é de 33 minutos, o tamanho do arquivo é de 173 MiB.

No pedido 12, o computador desistiu e tive que reiniciar.

Exemplo:

\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

Resultado do pedido 11 (melhores resoluções são rejeitadas pelo imgur):

Resultado, pedido 11

Devido ao grande número de quadrados, a visualização de um PDF com ordens superiores torna o visualizador de PDF mais lento.

Portanto, é mais eficiente gerar uma imagem bitmap monocromática, por exemplo, com os menores quadrados como quadrados de 1 x 1 pixel. A largura e a altura da imagem para a ordem 11 são então 2 22 pixels = 4194304 pixels.

Responder3

Aqui está uma tentativa com MetaPost, para quem pode interessar. A macro recursiva ( square_fractal) na base deste programa é fortemente inspirada emesta respostaparaum assunto intimamente relacionado.

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.

insira a descrição da imagem aqui

A partir da ordem 0 (o quadrado completo), o MetaPost gerencia uma saída até a ordem 6 na minha máquina. Curiosamente, a ordem 7 é alcançada se o código anterior for incluído em um programa LuaLaTeX. Não sei o motivo.

EditarAinda dentro do LuaLaTeX, e após usar números de ponto flutuante ( \mplibnumbersystem{double}adicionados logo após \usepackage{luamplib}) em vez dos números de ponto fixo padrão, o MetaPost consegue produzir a figura na ordem 9 após 20 minutos. Mas quase congela meu laptop muito antigo (um MacBook Pro de 2008), então não me atrevo a prosseguir. Talvez eu tente novamente em um computador mais recente e mais potente.

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

A figura abaixo é a do pedido 8. Não consegui produzir uma versão PNG do pedido 9 por causa do quase congelamento do meu laptop.

insira a descrição da imagem aqui

Responder4

Outra alternativa com Tikz e recursão.

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

insira a descrição da imagem aqui

informação relacionada