TikZ 中定点运算的计算精度

TikZ 中定点运算的计算精度

我想建立一棵满足以下条件的树:

  1. 它向右边生长。
  2. 第一个孩子以 0 度生长(后续孩子则按顺时针方向生长)。
  3. 所有子节点都处于同一垂直方向,并且连续节点之间的距离始终相同。

总而言之,我想要实现的是:

在此处输入图片描述

事实上,一个简单的编码方法是通过

\documentclass{article}
\usepackage{tikz}
\tikzset{bcir/.style={circle,fill=black,
 minimum size=4pt,inner sep=0},every node/.style={bcir}}
\begin{document}
\begin{tikzpicture}[x=3cm,y=2mm]
\node (A) {};
\foreach \i in {0,...,8} \node at (1,-\i) {} edge (A);
\end{tikzpicture}
\end{document}

然而,我尝试了一种替代方法,我期望产生相同的结果:

\documentclass{article}
\usepackage{tikz}
\usepackage{fp}
\usetikzlibrary{fixedpointarithmetic}
\tikzset{bcir/.style={circle,fill=black,
minimum size=4pt,inner sep=0},every node/.style={bcir}}

\begin{document}
\begin{tikzpicture}[fixed point arithmetic]  
\node {}
  child[grow=\g,level distance=\l cm] 
  foreach \i [evaluate={
     \k=tan(5)*\i;
     \g=-atan(\k);
     \l=3/cos(\g);
  }] in {0,...,13} {node {}};
\end{tikzpicture}  
\end{document}

请注意,在上面的代码中,我假设 1) 第一个(水平)子节点的水平距离为 3 厘米,2) 第二个子节点的增长为 -5 度。有了这两个条件和一些基本的三角学知识,就可以先计算出连续节点之间的兄弟节点距离,然后计算出任何子节点的角度g和水平距离。l

我相信我的参数化是正确的;然而,一些兄弟角度/水平距离略有偏差,

在此处输入图片描述

尽管(参考其他答案)我使用了定点算术引擎来尝试提高精度。即使用泰勒级数的第一项代替三角函数,

\begin{tikzpicture}[fixed point arithmetic]  
\node {}
  child[grow=\g,level distance=\l cm] 
  foreach \i [evaluate={
     \k=tan(5)*\i;
     \grad=\k-\k^3/3+\k^5/5-\k^7/7+\k^9/9;
     \g=-deg(\grad);
     \l=3/(1-\grad^2/2!+\grad^4/4!-\grad^6/6!);
  }] in {0,...,8} {node {}};
\end{tikzpicture}

存在同样的问题(请注意,这里的节点数已经选择好了,以确保系列确实atan收敛):

在此处输入图片描述

我可以做些什么来克服这些不准确的问题,或者这是一个无法避免的内在 TikZ 问题?(假设我的方法没有缺陷,因为我认为是这样)。

答案1

我不太清楚为什么在这种情况下数学似乎会失败(尽管我认为我应该知道),但这似乎不是 TikZ/PGF 进行数学运算的方式的问题,而是与树的构造方式有关。

不幸的是,我还没能弄清楚问题到底是什么,但问题是不是数学计算本身的准确性可以通过在树之外使用相同的计算来证明:

\documentclass[tikz, border=5]{standalone}
\tikzset{bcir/.style={circle,fill=black,
  minimum size=4pt,inner sep=0}, every node/.style={bcir}}

\begin{document}
\begin{tikzpicture}[every node/.style={bcir, anchor=center}]
\node {} child [grow=\g, level distance=\l cm] foreach \i [evaluate={%
  \k=tan(5)*\i; \g=-atan(\k); \l=3/cos(\g);}]
  in {0,...,13} { node {} };

\foreach \i [evaluate={%
  \k=tan(5)*\i; \g=-atan(\k); \l=3/cos(\g);}]
  in {0,...,13} { \draw [red] (0,0) -- (\g:\l) node [bcir,fill=red]{}; }
\end{tikzpicture}  
\end{document}

在此处输入图片描述

因此一定还有其他事情发生。

无论如何,我认为你正在把本来可以做的事情做得太过分很多使用自定义增长函数可以更简单地实现。

下面显示了grow via three points该库中增长函数的一个例子trees

\documentclass[tikz, border=5]{standalone}
\usetikzlibrary{trees}
\tikzset{bcir/.style={circle,fill=black,
  minimum size=4pt,inner sep=0}, every node/.style={bcir}}

\begin{document}
\begin{tikzpicture}[grow via three points={%
  one child at (3,0) and two children at (3,0) and (3,-1/4)
}]
\node {} child foreach \i in {0,...,13} { node {} };
\end{tikzpicture}  
\end{document}

在此处输入图片描述

答案2

PSTricks 解决方案:

\documentclass{article}

\usepackage{multido}
\usepackage{pstricks}
\usepackage{xfp}

% parameters
\def\NoDots{9}
\def\Hori{4}
\def\Vert{3}

\begin{document}

\begin{pspicture}(\Hori,\Vert)
  \psdot(0,\Vert)
  \multido{\r = \Vert+-\fpeval{\Vert/(\NoDots-1)}}{\NoDots}{%
    \psline(0,\Vert)(\Hori,\r)
    \psdot(\Hori,\r)}
\end{pspicture}

\end{document}

输出

\NoDots您所要做的就是更改参数( 、、\Hori和)的值\Vert,绘图就会进行相应的调整。

答案3

你的问题让我很好奇。MetaPost 默认也使用定点算法:“数字”不能小于 2^(-16)或大于2^12,尽管 MetaPost 内部可以处理高达的值2^15。(最近可以切换到几种浮点算法模式,但我不会在这里使用它们。)

因此,我决定制作第二个图表的 MetaPost 版本,具有相同的功能,并观察对齐情况。(使用 LuaLaTeX 进行处理。)

\documentclass[border=2mm]{standalone}
\usepackage{luamplib}
  \mplibsetformat{metafun}  
\begin{document}
  \begin{mplibcode}
    u := cm;
    def dot(expr c) = drawdot c withpen pencircle scaled 3bp enddef;
    beginfig(1);
      dot(origin); 
      for i = 0 upto 13:
        k := i*tand5; % or i*sind5/cosd5 with Plain MetaPost
        g := -atan k ; % or -angle(1, k) with Plain MetaPost; 
        l := 3u/cosd g;
        draw origin -- l*dir g;
        dot(l*dir g);
      endfor
    endfig;
  \end{mplibcode}
\end{document}

嗯,据我所见,它们似乎正确对齐了:

在此处输入图片描述

因此,在这种情况下,似乎存在一个问题,问题不在于定点算法本身,而在于定点库tikz(用于表示数字的两位?)。或者在于三角函数的定义方式。

无论如何,如果可以切换到浮点运算tikz(也许使用 LuaTeX?),它将大大提高准确性。

相关内容