TikZ/PGF 装饰仅向 y 坐标添加噪声

TikZ/PGF 装饰仅向 y 坐标添加噪声

我正在尝试想出一个 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将噪音添加到相对于终点的位置。

相关内容