solución tikz

solución tikz

Estoy intentando recrear este diagrama exacto usando tikz. Hasta ahora he estado intentando usar decoraciones anidadas en tikz ya que las usé para otras construcciones fractales. Sin embargo, todas estas construcciones eran decoraciones predefinidas por tikz, como la curva de Koch, o aquellas para las que encontré soluciones en el intercambio de pila, como el triángulo de Sierpinski.

He estado investigando mucho para definir mis propias decoraciones, pero parece un proceso bastante complicado para un novato en tikz y no he encontrado ningún ejemplo demasiado similar a lo que estoy tratando de hacer. Sé que también será posible utilizar sistemas Lindemayer, pero sólo entiendo cómo utilizarlos para construcciones de líneas.

Si sirve de ayuda, en mi opinión, parece que la forma más sencilla de hacerlo sería establecer el cuadrado como la forma inicial con el origen en la parte inferior izquierda, luego escalar en 1/4 para el cuadrado inferior izquierdo, escalar en 1/ 4 luego traslada hacia arriba para el cuadrado superior izquierdo, etc. y luego configura la nueva forma para reemplazar la inicial, lista para la siguiente iteración.

El fractal en cuestión

¡Cualquier ayuda sería muy apreciada!

Respuesta1

He aquí una manera con un sistema Lindenmayer. Para pedidos superiores a 5, compile con 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}

ingrese la descripción de la imagen aquí

Y aquí tienes una forma con las decoraciones:

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

ingrese la descripción de la imagen aquí

Respuesta2

solución tikz

Los cuadrados negros del fractal se generan mediante unampliablerecursividad.

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

Dado que todos los comandos de dibujo se guardan en la memoria, la memoria es el factor limitante.

Resultado del pedido 5:

Orden 5

Solución IniTeX

El siguiente ejemplo utiliza reglas simples en iniTeX para dibujar cuadrados para obtener órdenes superiores sin quedarse sin memoria.

La dimensión máxima en TeX es 16383,99998 pt ( \maxdimen). Esto es (2 30 - 1) sp (1 pt = 2 16 sp = 65536 sp). Los cuadrados más pequeños del siguiente nivel utilizan una longitud de borde cuadrado de un cuarto. Luego, se deduce que con la longitud del borde cuadrado más pequeña de 1 sp, el orden más grande es 14, la longitud del borde del resultado es entonces 2 28 sp.

El ejemplo utiliza pdfTeX o luaTeX en modo iniTeX ( pdftex -ini -etexo luatex -ini). LuaTeX es más rápido y tiene menos restricciones de memoria. A modo de comparación, el pedido 8 tarda unos 45 s con pdfTeX, pero 8 s con LuaTeX. Órdenes superiores con LuaTeX:

  • Orden 10:El tiempo es de 3 3/4 minutos y el tamaño del archivo es de 47 MiB.

  • Orden 11:El tiempo es de 33 minutos y el tamaño del archivo es de 173 MiB.

En el pedido 12, la computadora se rindió y tuve que reiniciar.

Ejemplo:

\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 del pedido 11 (imgur rechaza las mejores resoluciones):

Resultado, orden 11

Debido a la gran cantidad de cuadrados, ver un PDF con órdenes superiores ralentiza el visor de PDF.

Por lo tanto, es más eficaz generar una imagen de mapa de bits monocromática, por ejemplo con los cuadrados más pequeños como cuadrados de 1 x 1 píxel. El ancho y alto de la imagen para el pedido 11 es entonces 2 22 píxeles = 4194304 píxeles.

Respuesta3

Aquí tenéis un intento con MetaPost, para quien pueda interesar. La macro recursiva (square_fractal ) en la base de este programa está fuertemente inspirada enesta respuestaaun tema estrechamente 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.

ingrese la descripción de la imagen aquí

A partir del orden 0 (el cuadrado completo), MetaPost gestiona una salida hasta el orden 6 en mi máquina. Curiosamente, se alcanza el orden 7 si el código anterior se incluye en un programa LuaLaTeX. No sé el motivo.

EditarAún dentro de LuaLaTeX, y después de usar números de punto flotante ( \mplibnumbersystem{double}agregados justo después \usepackage{luamplib}) en lugar de los números de punto fijo predeterminados, MetaPost logra producir la figura en el orden 9 después de 20 minutos. Pero casi congela mi viejo portátil (un MacBook Pro de 2008), así que no me atrevo a profundizar más. Quizás lo vuelva a intentar en una computadora más reciente y más 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}

La siguiente figura es la del pedido 8. No pude producir una versión PNG del pedido 9 debido a que mi computadora portátil estaba casi congelada.

ingrese la descripción de la imagen aquí

Respuesta4

Otra alternativa con Tikz y recursividad.

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

ingrese la descripción de la imagen aquí

información relacionada