![Lindenmayer (L-Systems) 为单个单元着色](https://linux22.com/image/464193/Lindenmayer%20(L-Systems)%20%E4%B8%BA%E5%8D%95%E4%B8%AA%E5%8D%95%E5%85%83%E7%9D%80%E8%89%B2.png)
我使用以下代码来制作 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 = 3
和color mixing = 2
、4
和6
分别
评论。有两个全局参数,初始五边形的半径、基本五边形内部的颜色混合程度(初始绘图对应于最大颜色混合,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}