![Tikz:路径末端的装饰在高弯曲角度下消失](https://linux22.com/image/376087/Tikz%EF%BC%9A%E8%B7%AF%E5%BE%84%E6%9C%AB%E7%AB%AF%E7%9A%84%E8%A3%85%E9%A5%B0%E5%9C%A8%E9%AB%98%E5%BC%AF%E6%9B%B2%E8%A7%92%E5%BA%A6%E4%B8%8B%E6%B6%88%E5%A4%B1.png)
当我使用“向左弯曲=...”或“向右弯曲=...”在路径末尾放置装饰时,装饰会在弯曲角度较大时消失:
\documentclass[border = 2mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations.markings}
\tikzset{enddot/.style={
decoration={markings, mark=at position 1 with {
\fill (0,0)circle(2pt);
}}, postaction={decorate}}}
\begin{document}
\begin{tikzpicture}
\foreach \angle in {0,10,...,80}{
\draw[enddot] (0,0)to[bend right=\angle](\angle:2);
}
\end{tikzpicture}
\end{document}
这是 Tikz 的一个错误吗?
答案1
这是一个非常有趣的观察,但您可以使用 arrows.meta 库非常轻松地实现所需的输出。
\documentclass[border = 2mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{arrows.meta}
\begin{document}
\begin{tikzpicture}
\foreach \angle in {0,10,...,80}{
\draw[-Circle] (0,0)to[bend right=\angle](\angle:2);
}
\end{tikzpicture}
\end{document}
在我看来,这不是一个错误,而是起点和终点要用箭头方法处理。这些特殊点在装饰中使用时会引起一些问题,这并不奇怪。请注意,在这些装饰中,您始终处于路径给定点的切线坐标系中。(当然,当您的装饰是一个圆圈时,您无法欣赏它,但如果您放置它,\draw (0,-2pt) -- (0,2pt);
您会看到它在给定点处与路径正交)。显然,这个切线坐标系在曲线的末端定义不明确。但是,箭头经过“训练”可以处理这个问题,因此不存在问题。
附录: 我愿意不是认为这只是一个舍入误差。考虑 MWE
\documentclass[border = 2mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations.markings}
\tikzset{enddot/.style={
decoration={markings,
mark=at position 1 with {
\fill (0,0)circle(2pt);
},
mark=at position 0.5 with {
\fill (0,0)circle(2pt);
}}, postaction={decorate}}}
\begin{document}
\begin{tikzpicture}
\foreach \angle in {0,10,...,80}{
\draw[enddot] (0,0)to[bend right=\angle](\angle:2);
}
\end{tikzpicture}
\end{document}
它产生的结果与 OP 的情况类似
笔记:中间的圆圈一个都没画出来。
然而,一旦我删除
mark=at position 1 with {
\fill (0,0)circle(2pt);
},
我明白了
恕我直言,这不能用舍入误差来解释。还是我做了什么蠢事?
另一附录:为了从技术层面了解为什么会发生这种情况,我在\pgf@decorate@@movealongpath
in 中添加了一个 typeout pgfmoduledecorations.tex
,使其变为
\def\pgf@decorate@@movealongpath{%
\advance\pgfdecoratedinputsegmentcompleteddistance\pgf@decorate@distancetomove%
\advance\pgfdecoratedinputsegmentremainingdistance-\pgf@decorate@distancetomove%
\ifdim\pgfdecoratedinputsegmentremainingdistance>0pt\relax%
\let\pgf@next\pgf@decorate@@@movealongpath%
\else%
\typeout{gotcha}
\pgf@decorate@distancetomove-\pgfdecoratedinputsegmentremainingdistance%
\pgf@decorate@processnextinputsegmentobject%
\ifx\pgf@decorate@currentinputsegmentobjects\pgfutil@empty%
\pgfdecoratedremainingdistance0pt\relax%
\let\pgf@next\relax%
\else%
\let\pgf@next\pgf@decorate@@movealongpath%
\fi%
\fi%
\pgf@next%
}
这导致了打字
0
gotcha
10
gotcha
20
gotcha
30
gotcha
40
50
60
70
80
其中数字是相应的角度。这意味着在角度过大时,剩余距离变为负数(或更准确地说是非正数),这可能不应该,因此装饰被抑制。所以我认为可以公平地说
是的,舍入误差在解释中起到了一定作用,但公平地说,它们并不是唯一的解释。天真地,我以为舍入误差只是移动装饰,而不是吞掉它。然而,深入研究代码后,我相信已经确定了导致装饰消失的代码片段。
J Leon V. 的观察与此一致。但我不确定他们解释为什么会发生这种情况。但我也不认为这个答案真正解释了为什么上述if语句已经实现。
另一方面,我认为这个答案提供了一种将装饰物放置在应有位置的可靠方法。(我还看到我对上述导数的陈述并不切题。我出于历史原因保留它。我也认为我可以通过提醒读者弧长是切线长度的积分来为其辩护,但这不是我写这句话时所想的。)
答案2
这很有趣,所以错误是在算法中,当线完成时装饰就会消失,例如,如果我使用定义的长度来定位它们,如果它们超出了线的长度,那么点就会作为下一个结果消失。
\foreach \distance in {0.9,1.92,...,2.5}
...
...mark=at position \distance cm with ... % position in cm.
在我第一次迭代探测中,根据线的百分比改变位置:
\foreach \distance in {0.90,0.91,...,1.05}
第一个观察结果是,foreach 算法在计算步长时会添加小数,并不局限于步长的小数。如果我将步长设为千分之一,就会得到这个结果。
\foreach \distance in {0.99,0.991,...,1.01}
在这里您可以看到,即使值接近 1,也会出现错误,然后,用接近 1 的值进行探测,使用更多的小数来提高精度,我就得到了这个。
\foreach \distance in {0.9,0.99,0.999,0.9999,0.99999,0.999999,1,1.0009}
如您所见,错误是由于接近 4 个零位造成的。定位装饰线起点的算法具有有限的极限,可能是由于变量的计算长度,而弯曲角度使该线的经度具有或多或少的小数值,这使得决定标记消失位置的其他算法无法正确确定极限。是否会有一些配置来增加算法中的计算位数?
梅威瑟:
% arara: pdflatex: {synctex: yes, action: nonstopmode}
% arara: animate: {density: 200, delay: 200, other: -background white -alpha remove}
% arara: showanimate
\documentclass[tikz,border = 2pt]{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations.markings}
\begin{document}
\foreach \distance in {0.9,0.99,0.999,0.9999,0.99999,0.999999,1,1.000009}
{
\begin{tikzpicture}
% fill circle and plot
\foreach \angle in {0,10,...,80}{
\draw[decoration={markings, mark=at position \distance with {
\fill[red] (-1pt,-1pt) rectangle (1pt,1pt);
}}, postaction={decorate}] (0,0)to[bend right=\angle](\angle:2);
}
\draw (-0.5,-0.2) rectangle (2.5,2.5);
\node (a) at (1,2.25) {\tiny Mark position=\distance } ;
\end{tikzpicture}
}
\end{document}
对于动画,我使用 ImageMagic 便携版本,嵌入在动画 yaml 文件中的 arara 中。
答案3
对我来说这似乎是舍入错误。作为一种解决方法,您可以使用mark=at position 0.99
而不是mark=at position 1
。这似乎是舍入错误。
代码:
\documentclass[border = 2pt]{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations.markings}
\tikzset{enddot/.style={
decoration={markings, mark=at position 0.99 with {
\fill[red] (0,0) circle (2pt);
}}, postaction={decorate}}}
\begin{document}
\begin{tikzpicture}
\foreach \angle in {0,10,...,80}{
\draw[enddot] (0,0)to[bend right=\angle](\angle:2);
}
\end{tikzpicture}
\end{document}