![TikZ/PGF 装饰仅向 y 坐标添加噪声](https://linux22.com/image/321202/TikZ%2FPGF%20%E8%A3%85%E9%A5%B0%E4%BB%85%E5%90%91%20y%20%E5%9D%90%E6%A0%87%E6%B7%BB%E5%8A%A0%E5%99%AA%E5%A3%B0.png)
我正在尝试想出一个 PGF 修饰,它向路径的 y 坐标添加伪随机噪声,同时保持 x 坐标不变。这个想法是,如果我正在绘制一个函数 y=f(x),这个修饰应该让它成为一个函数,只是让它变得更嘈杂。这个random steps
修饰不起作用,因为它可能会产生两个具有相同 x 坐标的不同点,这不再是一个函数。
我尝试采用与 相同的基本方法random steps
,但使用极坐标来添加角度 处的噪声90-\pgfdecoratedangle
。但是,对于非水平线的路径,这种方法会失败。这是一个最简单的非工作示例:
\documentclass[varwidth,convert]{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations.pathmorphing}
\begin{document}
\pgfdeclaredecoration{jiggly}{step}
{
\state{step}[width=+\pgfdecorationsegmentlength]
{
\pgfpathlineto{
\pgfpointadd
{\pgfpoint{\pgfdecorationsegmentlength}{0pt}}
{\pgfpointpolar{90-\pgfdecoratedangle}
{rand*\pgfdecorationsegmentamplitude}}
}
}
\state{final}
{
\pgfpathlineto{\pgfpointdecoratedpathlast}
}
}
\pgfmathsetseed{1}
\begin{tikzpicture}[very thick, decoration={jiggly, amplitude=1cm}]
\draw[help lines] (0,0) grid (7,4);
\draw[cyan, decorate] (0,1) -- (3,1);
\draw[red, decorate] (4,0) -- (7,3);
\end{tikzpicture}
\end{document}
如您所见,青色线看起来不错,但红线已变形为不再是函数的东西。它甚至延伸到输入路径的最右点之外,而这不应该通过仅在 y 方向添加噪声来实现。显然,我遗漏了有关装饰如何工作的一些信息,问题是什么?
答案1
在餐巾纸上画了一些图表并运用了一些三角学知识(如果你感兴趣我可以解释一下)之后,我得出了以下结论:(见最后的编辑)
\documentclass[varwidth,convert]{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations.pathmorphing}
\begin{document}
\pgfdeclaredecoration{jiggly}{step}
{
\state{step}[width=+\pgfdecorationsegmentlength]
{ \pgfmathsetmacro{\delta}{rand*\pgfdecorationsegmentamplitude}
\pgfmathsetmacro{\deltax}{\delta*cos(90+\pgfdecoratedangle}
\pgfmathsetmacro{\deltay}{\delta*sin(90+\pgfdecoratedangle}
\pgfpathlineto{\pgfpoint{\pgfdecorationsegmentlength-\deltax}{\deltay}}
}
\state{final}
{
\pgfpathlineto{\pgfpointdecoratedpathlast}
}
}
\pgfmathsetseed{1}
\begin{tikzpicture}[very thick, decoration={jiggly, amplitude=1cm}]
\draw[help lines] (0,0) grid (7,4);
\draw[cyan, decorate] (0,1) -- (3,1);
\draw[red, decorate] (4,0) -- (7,3);
\end{tikzpicture}
\end{document}
结果:
编辑
将我的代码与 OP 的代码进行比较后,我注意到最终我做的是相同的,只是自己计算随机噪声在适当方向上的“投影”,而不是让 pgf 极坐标变换做同样的事情。那么...为什么我的代码有效而 OP 的代码无效?
对我来说唯一合理的解释是,它rand
被用作第二个参数\pgfpointpolar
,也许,当 pgf 将极坐标转换为笛卡尔坐标,从而计算正弦和余弦时,这个参数被评估两次(每个轴一次),rand
每次评估都会给出不同的结果。
因此我通过对 OP 的代码进行简单修改来测试这个想法,这确保只rand
评估一次:
\pgfdeclaredecoration{jiggly}{step}
{
\state{step}[width=+\pgfdecorationsegmentlength]
{\pgfmathsetmacro{\delta}{rand*\pgfdecorationsegmentamplitude}
\pgfpathlineto{
\pgfpointadd
{\pgfpoint{\pgfdecorationsegmentlength}{0pt}}
{\pgfpointpolar{90-\pgfdecoratedangle}
{\delta}}
}
}
\state{final}
{
\pgfpathlineto{\pgfpointdecoratedpathlast}
}
}
而且它也有效!
答案2
另一个(更简单的?)解决方案:
\documentclass[varwidth,convert]{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations.pathmorphing}
\begin{document}
\pgfdeclaredecoration{jiggly}{step}
{
\state{step}[width=+\pgfdecorationsegmentlength]
{
\pgfmathsetmacro{\r}{rand*\pgfdecorationsegmentamplitude}
\pgfpathlineto{\pgfpointadd{\pgfpointpolar{90-\pgfdecoratedangle}{\r}}{\pgfpoint{\pgfdecorationsegmentlength}{0pt}}}
}
\state{final}
{
\pgfpathlineto{\pgfpointdecoratedpathlast}
}
}
\pgfmathsetseed{1}
\begin{tikzpicture}[very thick, decoration={jiggly, amplitude=1cm}]
\draw[help lines] (0,0) grid (7,4);
\draw[cyan, decorate] (0,1) -- (3,1);
\draw[red, decorate] (4,0) -- (7,3);
\end{tikzpicture}
\end{document}
我\pgfpointadd
将噪音添加到相对于终点的位置。