
Я хочу построить дерево, которое удовлетворяет следующим условиям:
- Он растет справа.
- Первый ребенок растет под углом 0 градусов (последующие дети растут по часовой стрелке).
- Все дочерние узлы находятся на одной вертикали, а расстояние между последовательными узлами всегда одинаково.
В целом, я хотел бы добиться следующего:
Действительно, простой способ кодирования, который осуществляется через
\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?), это бы радикально повысило точность.