Точность вычислений в 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?), это бы радикально повысило точность.

Связанный контент