Lindenmayer (L-Systems) 为单个单元着色

Lindenmayer (L-Systems) 为单个单元着色

我使用以下代码来制作 Lindenmayer 图纸,利用来自本网站

是否可以修改此代码,使每个单元都具有不同的颜色,从而生成最后一张图片?

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{lindenmayersystems}
\usetikzlibrary[shadings]
\begin{document}
{
\pgfdeclarelindenmayersystem{Pntaplx}{
\rule{F -> F++F++F+++++F-F++F}
}
\foreach \k in {0,1}
{
\begin{tikzpicture}[scale=5,rotate=0]
\draw[draw=red!80!black, fill=yellow, line width=0.1cm, line cap=round, lindenmayer system={Pntaplx, axiom=F++F++F++F++F, order=\k, angle=36, step=.4cm}] lindenmayer system;
\end{tikzpicture}
}
}
\end{document}

在此处输入图片描述

在此处输入图片描述

答案1

这不是一个 L 系统——但它确实展示了一种绘制五片状让您可以玩转色彩。

在此处输入图片描述

我用过元帖子对于绘图,包裹在中luamplib,因此您需要使用来编译它lualatex

\documentclass[border=5mm]{standalone}
\usepackage{luamplib}
\begin{document}
\mplibtextextlabel{enable}
\begin{mplibcode}
input colorbrewer-rgb
vardef median(expr p) = origin for i=1 upto 5: + 1/5 point i of p endfor enddef;
vardef flake(expr level, limit, p, s) = 
    if level < 1:
        fill p withcolor s;
        draw p withcolor 3/4 s;  % or omit the colour to get the default black
    else:
        save small_p, m;
        path small_p; pair m; m = median(p); 
        small_p = p shifted -m scaled 0.381966; % (phi/(phi+1+phi)) \simeq 0.381966 
        for i=1 upto 5:
            flake(level - 1, limit, small_p shifted (point i of p - point i of small_p), 
            if level = limit: Spectral[6][i] else: s fi);
        endfor
        flake(level - 1, limit, small_p rotated 180 shifted m, 
            if level = limit: Spectral 6 6 else: s fi);
    fi
enddef;
beginfig(1);
    path P; P = for i=1 upto 5: 50 up rotated 72i -- endfor cycle;
    for j=1, 2, 3:
        for i=1 upto j+1:
            picture T; 
            T = image(
                flake(j, i, P, 15/16);
                label("$(" & decimal j & "," & decimal i & ")$", 
                    point 1/2 of bbox currentpicture + 6 down);
            );
            draw T shifted (100j-100i, 110j);
        endfor
    endfor
endfig;
\end{mplibcode}
\end{document}

笔记

上面示例中的大部分代码都用于处理颜色。对于基本的五叶草递归程序,您可以将其剥离如下:

vardef flake(expr level, p) = 
    if level < 1:
        draw p;
    else:
        save small_p, m;
        path small_p; pair m; 
        m = median(p);   
        small_p = p shifted -m scaled 0.381966; % (phi/(phi+1+phi)) \simeq 0.381966 
        flake(level - 1, small_p shifted (point 0 of p - point 0 of small_p));
        flake(level - 1, small_p shifted (point 1 of p - point 1 of small_p)); 
        flake(level - 1, small_p shifted (point 2 of p - point 2 of small_p)); 
        flake(level - 1, small_p shifted (point 3 of p - point 3 of small_p)); 
        flake(level - 1, small_p shifted (point 4 of p - point 4 of small_p)); 
        flake(level - 1, small_p rotated 180 shifted m);
    fi
enddef;

此处的方法是使用level参数和要绘制的五边形来定义例程p。当级别小于 1 时,只需绘制路径p。否则,flake使用缩小和移位的副本再次调用p——称为small_p,并将级别设置为level-1。这是在 MP 中进行递归的一种简单方法。

然后,您可以在完整的程序中使用此例程,如下所示:

\documentclass[border=5mm]{standalone}
\usepackage{luamplib}
\begin{document}
\begin{mplibcode}
vardef median(expr p) = origin for i=1 upto 5: + 1/5 point i of p endfor enddef;
vardef flake(expr level, p) = 
    ... as above ...
enddef;
beginfig(1);
    path P; P = for i=1 upto 5: 100 up rotated 72i -- endfor cycle;
    flake(3, P);
endfig;
\end{mplibcode}
\end{document}

编译该代码lualatex将产生如下结果:

在此处输入图片描述

你可以尝试一下,做出一些变化。例如,如果你注释掉第六个调用,flake将形状放在中间,那么你得到的是这个垫圈:

在此处输入图片描述

请注意,为了正确缩放和旋转,最好将形状移回原点,然后缩放和旋转,然后移回所需位置。请注意,要正确执行此操作,您不能使用内置命令,center因为内置命令会给出形状边界框的中心,而不是形状的实际中线(即通过形状的五个点的圆心)。

您还可以将前五个调用放入循环中,如多色示例所示。其余的复杂性只是处理颜色。

答案2

在此处输入图片描述

这是我最初回答的结果。由于 OP 询问 pic 元素是否可以用于递归构造,请参阅在 Tikz 中绘制递归多边形,我下面指出一种可能性。

在此处输入图片描述 使用递归 pic 元素p rec,它需要三个参数:递归步骤、结束、角度。

在此处输入图片描述 使用递归 pic 元素p* rec,它需要三个参数:递归步骤、结束、角度。

在此处输入图片描述 end = 345分别

在此处输入图片描述 end = 3color mixing = 246分别

评论。有两个全局参数,初始五边形的半径、基本五边形内部的颜色混合程度(初始绘图对应于最大颜色混合,indCM=6)和计数器,pCnt

新版答案

\documentclass[11pt, border=.8cm]{article}
\usepackage{ifthen}
\usepackage{tikz}
\usetikzlibrary{calc, math}
\begin{document}


\newcounter{pCnt}
\newcommand{\chooseRGB}[1]{%
  \ifthenelse{\equal{#1}{0}}{\colorlet{RGB}{red}}{}  
  \ifthenelse{\equal{#1}{1}}{\colorlet{RGB}{yellow!90!red!90!blue}}{}
  \ifthenelse{\equal{#1}{2}}{\colorlet{RGB}{orange}}{}
  \ifthenelse{\equal{#1}{3}}{\colorlet{RGB}{green!60!black}}{}
  \ifthenelse{\equal{#1}{4}}{\colorlet{RGB}{blue}}{}
  \ifthenelse{\equal{#1}{5}}{\colorlet{RGB}{violet}}{}
}

\pgfkeys{/tikz/.cd,
  indexColorMixing/.store in=\indCM,
  indexColorMixing = 1
}
\pgfkeys{/tikz/.cd,
  pentagonRadius/.store in=\pentagonR,
  pentagonRadius = 2
}
\tikzset{
  pentagons/.style={%
    evaluate={%
      real \pentagonAngle, \pentagonCst, \pentagonCstRecursion;
      \pentagonAngle = 72;
      \pentagonCst = {2*cos(\pentagonAngle/2)};
      \pentagonCstRecursion = {1/(1 +\pentagonCst))};
    }
  },
  pics/pentagon/.style 2 args={% 
    code={%
      \draw[#1, ultra thick, fill=#2] (0: \pentagonR)
      \foreach \i in {1, ..., 4}{%
        -- (\i*\pentagonAngle: \pentagonR)
      } -- cycle;
    }
  },
  pics/p rec/.style n args={3}{% recursion step, end, angle
    code={%
      \tikzmath{
        integer \i;
        \i = #1+1;
        if \i<#2 then {%
          \tmp = {\pentagonR*pow(\pentagonCstRecursion, \i)*\pentagonCst};
          {
            \path pic {p rec={\i}{#2}{#3 +180}};
          };
          for \j in {0, ..., 4}{%
            {
              \path (#3 +\j*\pentagonAngle: \tmp)
              pic {p rec={\i}{#2}{#3 +\j*\pentagonAngle}};
            };
          };
        } else {%
          \tmp = {\pentagonR*pow(\pentagonCstRecursion, \i-1)};
          {%
            \draw (#3: \tmp)
            \foreach \k in {1, ..., 4}{%
              -- (#3 +\k*\pentagonAngle: \tmp)
            } -- cycle;
          };
        };
      }
    }
  },
  pics/p* rec/.style n args={3}{% recursion step, end, angle
    code={%
      \tikzmath{
        integer \i, \rgb;
        \i = #1+1;
        if \i<#2 then {%
          \tmp = {\pentagonR*pow(\pentagonCstRecursion, \i)*\pentagonCst};
          {
            \path pic {p* rec={\i}{#2}{#3 +180}};
          };
          for \j in {0, ..., 4}{%
            {
              \path (#3 +\j*\pentagonAngle: \tmp)
              pic {p* rec={\i}{#2}{#3 +\j*\pentagonAngle}};
            };
          };
        } else {%
          \tmp = {\pentagonR*pow(\pentagonCstRecursion, \i-1)};
          \rgb = int(mod(int(\thepCnt/(7 -\indCM)), 6));
          {%
            \chooseRGB{\rgb}
            \draw[white, fill=RGB] (#3: \tmp)
            \foreach \k in {1, ..., 4}{%
              -- (#3 +\k*\pentagonAngle: \tmp)
            } -- cycle;
            \stepcounter{pCnt}
          };
        };
      }
    }
  }
}

\begin{tikzpicture}[pentagons, pentagonRadius=1.3,
  evaluate={%
    \t=\pentagonAngle;
    \d = \pentagonCst*\pentagonR;
    \tini=30;}]
  \foreach \j/\rgb in
  {0/violet, 1/red, 2/orange, 3/green!70!black, 4/cyan!70!black}{%
    \path (\tini +\j*\t +\t/2: \d) pic[rotate={\tini +\t/2}]
    {pentagon={\rgb}{\rgb!30}};
  }
  \path (0, 0) pic[rotate=\tini] {pentagon={blue}{blue!35}};
  \path (7, 0) node[scale=1.3, text width=15ex]
  {Elementary drawing using a {\color{blue}pic} element};
\end{tikzpicture}


\begin{tikzpicture}[pentagons, evaluate={\r=2;}]
  \path (0, 0) pic[blue] {p rec={0}{1}{0}};
  \path (5, 0) pic[blue] {p rec={0}{2}{20}};
  \path (10, 0) pic[blue] {p rec={0}{3}{-20}};
\end{tikzpicture}


\begin{tikzpicture}[pentagons]
  \setcounter{pCnt}{0}
  \path (0, 0) pic {p* rec={0}{1}{0}};
  \setcounter{pCnt}{0}
  \path (5, 0) pic {p* rec={0}{2}{10}};
  \setcounter{pCnt}{0}
  \path (10, 0) pic {p* rec={0}{3}{10}};
\end{tikzpicture}


\begin{tikzpicture}[pentagons]
  \setcounter{pCnt}{0}
  \path (0, 0) pic {p* rec={0}{3}{0}};
  \setcounter{pCnt}{0}
  \path (5, 0) pic {p* rec={0}{4}{0}};
  \setcounter{pCnt}{0}
  \path (10, 0) pic {p* rec={0}{5}{10}};
\end{tikzpicture}


\begin{tikzpicture}[pentagons]
  \setcounter{pCnt}{0}
  \path[indexColorMixing=2] (0, 0) pic {p* rec={0}{3}{0}};
  \setcounter{pCnt}{0}
  \path[indexColorMixing=4] (5, 0) pic {p* rec={0}{3}{0}};
  \setcounter{pCnt}{0}
  \path[indexColorMixing=6] (10, 0) pic {p* rec={0}{3}{10}};
\end{tikzpicture}

\end{document}

原始答案

一种方法是直接绘制五边形;我尝试使用元素pic和循环。pic命名的元素pentagon有两个参数,即边缘颜色和内部颜色。默认情况下,它在Ox轴上有一个顶点。

\a五边形的大小由一开始定义的变量控制。

代码

\documentclass[11pt, border=.8cm]{standalone}
\usepackage{tikz}
\usetikzlibrary{calc, math}
\begin{document}

\tikzmath{
  real \a, \d, \t, \tini;
  \a = 2;  % radius
  \t = 72;
  \d = {2*\a*cos(\t/2)};  % distance between two centers 
  \tini = -90;  % initial angle
}
\tikzset{
  pics/pentagon/.style 2 args={%
    code={%
      \draw[#1, ultra thick, fill=#2] (0: \a)
      \foreach \i in {1, ..., 4}{ -- (\i*\t: \a) } -- cycle;
    }
  }
}

\begin{tikzpicture}
  \foreach \j/\rgb in
  {0/violet, 1/red, 2/orange, 3/green!70!black, 4/cyan!70!black}{%
    \path (\tini +\j*\t +\t/2: \d) pic[rotate={\t/4}]
    {pentagon={\rgb}{\rgb!30}};
  }
  \path (0, 0) pic[rotate=\tini] {pentagon={blue}{blue!35}};
\end{tikzpicture}

\end{document}

相关内容