![在 Tikz 中使用角度参数制作自定义 Koch 装饰](https://linux22.com/image/345313/%E5%9C%A8%20Tikz%20%E4%B8%AD%E4%BD%BF%E7%94%A8%E8%A7%92%E5%BA%A6%E5%8F%82%E6%95%B0%E5%88%B6%E4%BD%9C%E8%87%AA%E5%AE%9A%E4%B9%89%20Koch%20%E8%A3%85%E9%A5%B0.png)
因此,我尝试绘制类似于科赫雪花的分形,因此我想定义自己的装饰,该装饰可执行相同的操作,但允许您指定角度。例如,在此图片中,角度为 85 度:
但我似乎找不到任何关于定义装饰的教程。下面提供的内容只是我从其他装饰问题中收集到的开始部分,但它不起作用。有人能给我一个教程或展示一个允许这样做的代码示例吗?谢谢!
\documentclass[]{standalone}
\usepackage{calc,tikz}
\usetikzlibrary{decorations}
\tikzset{/pgf/decoration/.cd,
angle/.initial=1.5pt,
% definition of the decoration
\pgfdeclaredecoration{cesaro}{initial}
{
\state{initial}[width=1pt]%,%
%next state=midd]
{
\def\angle{%
\pgfkeysvalueof{/pgf/decoration/angle}%
}
% First line
\pgfpathlineto{\pgfpoint{0.0pt}{$\pgfdecoratedpathlength/2-2*\pgfdecoratedpathlength*cos{\angle}$}}
}
% \state{midd}[1pt]
% \state{final}
}
\begin{document}
\begin{tikzpicture}[scale=1]
\node (a) at (0pt,50pt) {};
\node (b) at (0pt,0pt) {};
\draw[decorate, decoration={cesaro}] (a) -- (b);
\end{tikzpicture}
\end{document}
答案1
手册(在基础层章节中)描述了创建装饰的基础知识,但仍有一些技巧可用于使事情变得更有效率:
\documentclass[tikz,border=5]{standalone}
\usetikzlibrary{decorations}
\pgfkeys{/pgf/decoration/.cd,
Koch angle/.store in=\pgfkochangle, Koch angle=85
}
\pgfdeclaredecoration{Koch}{calculate}{
\state{calculate}[width=0pt, next state=draw, persistent precomputation={
% Exploit the fact that all segment lengths should be the same.
\pgfmathparse{\pgfdecoratedinputsegmentlength/(2*(1+cos(\pgfkochangle)))}%
\let\pgfkochsegmentlength=\pgfmathresult%
\pgfmathparse{\pgfkochsegmentlength*sin(\pgfkochangle)}%
\let\pgfkochy=\pgfmathresult%
\pgfmathparse{\pgfkochsegmentlength*(1 + cos(\pgfkochangle))}%
\let\pgfkochxa=\pgfmathresult%
\pgfmathparse{\pgfkochsegmentlength*(1 + 2*cos(\pgfkochangle))}%
\let\pgfkochxb=\pgfmathresult%
}]{}
\state{draw}[width=\pgfdecoratedinputsegmentlength]{
\pgfpathmoveto{\pgfpointorigin}%
\pgfpathlineto{\pgfqpoint{\pgfkochsegmentlength pt}{0pt}}%
\pgfpathlineto{\pgfqpoint{\pgfkochxa pt}{\pgfkochy pt}}%
\pgfpathlineto{\pgfqpoint{\pgfkochxb pt}{0pt}}%
\pgfpathlineto{\pgfqpoint{\pgfdecoratedinputsegmentlength}{0pt}}%
}}
\begin{document}
\begin{tikzpicture}
\foreach \a [count=\i] in {60, 72, 85}
\draw [decoration={Koch, Koch angle=\a}]
decorate {decorate {decorate {decorate { decorate {(0,\i*4) -- ++(10,0) }}}}};
\end{tikzpicture}
\end{document}
虽然使用全局计数器并不理想,但order
可以实现一个参数来消除对多个命令的需要decorate
:
\documentclass[tikz,border=5]{standalone}
\usetikzlibrary{decorations}
\newcount\pgfdecorationorder
\pgfkeys{/pgf/decoration/.cd,
Koch angle/.store in=\pgfkochangle, Koch angle=85,
Koch order/.code={\global\pgfdecorationorder=#1}, Koch order=1
}
\pgfdeclaredecoration{Koch}{calculate}{
\state{calculate}[width=0pt, next state=draw, persistent precomputation={
% Exploit the fact that all segment lengths should be the same.
\pgfmathparse{\pgfdecoratedinputsegmentlength/(2*(1+cos(\pgfkochangle)))}%
\let\pgfkochsegmentlength=\pgfmathresult%
\pgfmathparse{\pgfkochsegmentlength*sin(\pgfkochangle)}%
\let\pgfkochy=\pgfmathresult%
\pgfmathparse{\pgfkochsegmentlength*(1 + cos(\pgfkochangle))}%
\let\pgfkochxa=\pgfmathresult%
\pgfmathparse{\pgfkochsegmentlength*(1 + 2*cos(\pgfkochangle))}%
\let\pgfkochxb=\pgfmathresult%
}]{}
\state{draw}[width=\pgfdecoratedinputsegmentlength]{
\pgfpathmoveto{\pgfpointorigin}%
\pgfpathlineto{\pgfqpoint{\pgfkochsegmentlength pt}{0pt}}%
\pgfpathlineto{\pgfqpoint{\pgfkochxa pt}{\pgfkochy pt}}%
\pgfpathlineto{\pgfqpoint{\pgfkochxb pt}{0pt}}%
\pgfpathlineto{\pgfqpoint{\pgfdecoratedinputsegmentlength}{0pt}}%
}
\state{final}{
\global\advance\pgfdecorationorder by -1\relax%
\ifnum\pgfdecorationorder>0\relax%
\pgfgetpath\decoratedpath%
\pgfsetpath\empty%
\begin{pgfdecoration}{{Koch}{\pgfdecoratedpathlength}}%
\pgfsetpath\decoratedpath
\end{pgfdecoration}%
\fi
}}
\begin{document}
\begin{tikzpicture}
\foreach \i in {1,...,6}
\draw [decoration={Koch, Koch angle=85, Koch order=\i}]
decorate {(0,\i*5) -- ++(10,0)};
\end{tikzpicture}
\end{document}
答案2
这是一个使用该lindenmayer
库的简单解决方案:
\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{lindenmayersystems}
\pgfdeclarelindenmayersystem{A}{\rule{F-> F+F--F+F}}
\begin{document}
\begin{tikzpicture}
\draw[blue,line cap=round]
[lindenmayer system={A,axiom=F,order=7,angle=80,step=1mm}]
lindenmayer system;
\end{tikzpicture}
\end{document}
当角度为80时,结果是正确的(顺序=7):
当角度为 85 度时,计算误差会累积,并且在多次迭代(阶数=6)时清晰可见。
答案3
我喜欢用 MetaPost 制作分形,所以我忍不住要编写这个程序,使用递归宏,Koch(expr A, B, angl, n)
以初始段的极端、角度和所需的递归顺序作为参数。
以下是将角度参数设置为 60、72 和 85(从下到上)、阶数为 5 的结果,如 Mark Wibrow 的示例所示:
vardef Koch(expr A, B, angl, n) =
if n = 0:
draw A -- B;
else:
save b, v, C, D, E; pair v, C, D, E;
v = unitvector(B-A);
2b * (1 + cosd angl) = abs(B-A);
C = A + b*v;
D = .5[A,B] + b * sind angl * v rotated 90;
E = B - b*v;
Koch(A, C, angl, n-1); Koch(C, D, angl, n-1);
Koch(D, E, angl, n-1); Koch(E, B, angl, n-1);
fi
enddef;
beginfig(1);
k := 0;
for angl = 60, 72, 85:
draw image(Koch(origin, (10cm, 0), angl, 5)) shifted (0, k*4cm);
k := k+1;
endfor;
endfig;
end.
为了好玩,这里是将角度设置为 85 时阶数为 8 的结果(可能需要一些时间):