我想在两点之间绘制一条指定长度的随机曲线。例如,以点(0,0)
和为例(10,10)
。如何用长度为 20 的随机曲线将它们连接起来?
根据这个回答,有一种方法可以找到已绘制曲线的长度,但我不知道从哪里开始预先指定长度。任何帮助都非常感谢。
答案1
这是一条长度约为 30 的随机平滑曲线,范围从 (1, 0) 到 (10, 9)。它是通过递归修饰获得的。random curve of given length
此修饰有四个参数:“随机点”的缩放因子、随机点处切向量的缩放因子、第一个因子的步长变化以及所需长度。
有关施工的一些说明
它基于
for random smooth curves
通过引入的样式scope
。此样式采用一个参数,即随机点的数量。它执行一些计算(主要引入后续操作中所需的随机数和一些单独的常量,\cst{\i}
这些常量允许出于美观原因对随机切向量进行一些控制(参见 2.)。曲线是使用
random curve test
仅接受两个参数(递归修饰的前两个参数)的修饰来构造的(如果需要)。见下图。
假设我们不喜欢点 1 和 3 周围的曲线。我们改变各个常数的符号并得出下一个数字。
- 我们使用递归修饰来构建所需的曲线。
我正在使用@Gonzalo Medina 的想法来决定曲线的长度。
种子通过 固定
\pgfmathsetseed{19}
。您可能想要注释掉该行;请注意,测试阶段没有意义。但是有一个问题;我决定采用一个简单的解决方案来处理random curve of given length
调用时第三个参数的符号;它基于测试步骤!如果需要,我可以修改代码……
代码(它生成了最后一张图纸。)
\documentclass[11pt, margin=.5cm]{standalone}
\usepackage{tikz}
\usetikzlibrary{math, calc}
\usetikzlibrary{decorations.markings}
\usetikzlibrary{decorations.pathreplacing} % for show control points
\usepackage{pgfplots}
\makeatletter
\tikzset{%
measureme/.style={%
decoration={%
markings,
mark=at position 1 with {%
\tikzmath{
\lrc = \pgfdecoratedpathlength*1pt/1cm;
}
\pgfextra{\xdef\lrcG{\lrc}}
}
},
postaction=decorate
},
for smooth random curve/.style={%
evaluate={%
int \N@glc, \M@glc, \i, \j;
real \lrc;
\N@glc = #1;
\M@glc = #1 +1;
for \i in {1, ..., \N@glc}{%
\rndPx{\i} = .5 +1.5*rand;
\rndPy{\i} = .5 -1.5*rand;
};
for \i in {0, ..., \M@glc}{%
\cst{\i} = 1;
\rndVm{\i} = .2 +abs(rand);
\rndVa{\i} = 180*rand;
};
}
},
random curve test/.style 2 args={ % p scale / q scale
decoration={
show path construction,
lineto code={
\path (\tikzinputsegmentfirst) coordinate (P-0);
\path (\tikzinputsegmentlast) coordinate (P-\M@glc);
\path ($($(P-0)!1/\M@glc!(P-\M@glc)$) -(P-0)$) coordinate (v);
\foreach \i in {1, ..., \N@glc}{%
\path ($(P-0)!\i/\M@glc!(P-\M@glc)$)
let
\p1 = (v)
in ++({#1*\rndPx{\i}*\x1}, {#1*\rndPy{\i}*\y1})
coordinate (P-\i);
}
\foreach \i in {0, ..., \M@glc}{%
\path ($(0, 0)!{#2*\cst{\i}*\rndVm{\i}}!\rndVa{\i}: (v)$)
coordinate (v-\i);
}
\foreach \i in {0, ..., \M@glc}{%
\draw[green!70!black] (P-\i) circle (2pt) -- ++(v-\i)
node[pos=1.03, text=red] {\i};
}
\draw[measureme] (P-0)
\foreach \i [evaluate=\i as \j using {int(\i +1)}]
in {0, ..., \N@glc}{%
.. controls ++(v-\i) and ++([scale=-1] v-\j) .. (P-\j)
};
}
},
decorate
},
random curve of given length/.style n args={4}{%
% p scale / q scale / step / length
decoration={
show path construction,
lineto code={
\path (\tikzinputsegmentfirst) coordinate (P-0);
\path (\tikzinputsegmentlast) coordinate (P-\M@glc);
\path ($($(P-0)!1/\M@glc!(P-\M@glc)$) -(P-0)$) coordinate (v);
\foreach \i in {1, ..., \N@glc}{%
\path ($(P-0)!\i/\M@glc!(P-\M@glc)$)
let
\p1 = (v)
in ++({#1*\rndPx{\i}*\x1}, {#1*\rndPy{\i}*\y1})
coordinate (P-\i);
}
\foreach \i in {0, ..., \M@glc}{%
\path ($(0, 0)!{#2*\cst{\i}*\rndVm{\i}}!\rndVa{\i}: (v)$)
coordinate (v-\i);
}
\path[measureme] (P-0) % produces \lrcG, the length
\foreach \i [evaluate=\i as \j using {int(\i +1)}]
in {0, ..., \N@glc}{%
.. controls ++(v-\i) and ++([scale=-1] v-\j) .. (P-\j)
};
\tikzmath{%
\stp = #3;
\dMain = #4 -\lrcG;
if abs(\dMain)<.05 then {%
{%
\draw[red, measureme] (P-0)
\foreach \i [evaluate=\i as \j using {int(\i +1)}]
in {0, ..., \N@glc}{%
.. controls ++(v-\i) and ++([scale=-1] v-\j) .. (P-\j)
};
};
} else {%
if \dMain*\stp<0 then { \stp = -\stp/2; };
\pScale = #1 +\stp;
{%
\path[random curve of given length={\pScale}{#2}{\stp}{#4}]
(P-0) to (P-\M@glc);
};
};
}
}
},
decorate
}
}
\makeatother
\begin{document}
\begin{tikzpicture}[line cap=round]
\pgfmathsetseed{19}
\draw[gray!40] (0, 0) grid (10, 10);
\path (1, 0) coordinate (Pini);
\path (10, 9) coordinate (Pend);
\begin{scope}[for smooth random curve={4}]
\tikzmath{%
\cst{0} = 2;
\cst{1} = -1;
\cst{3} = -1;
}
\draw[random curve test={1}{1}] (Pini) to (Pend);
\draw[random curve of given length={1}{1}{.1}{30}] (Pini) to (Pend);
\end{scope}
\path let
\p1 = ($(Pend) -(Pini)$),
\n1 = {veclen(\x1, \y1)/1cm}
in (Pini) ++(3, -1) node {curve of length \lrcG};
\end{tikzpicture}
\end{document}