
Quero construir uma árvore que satisfaça o seguinte:
- Cresce para a direita.
- O primeiro filho cresce a 0 graus (os filhos subsequentes crescem no sentido horário).
- Todos os nós filhos estão na mesma vertical e a distância entre nós consecutivos é sempre a mesma.
Resumindo, o que eu gostaria de alcançar é o seguinte:
Na verdade, uma maneira fácil de codificar isso é através
\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}
No entanto, tentei uma abordagem alternativa, que esperava produzir os mesmos resultados:
\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}
Observe que no código acima presumi que 1) a distância de nível do primeiro filho (horizontal) é de 3 cm e 2) o segundo filho cresce a -5 graus. Com essas duas condições e alguma trigonometria básica, pode-se calcular primeiro a distância irmã entre nós consecutivos e depois o ângulo g
e a distância de nível l
para qualquer nó filho.
Acredito que minha parametrização esteja correta; no entanto, alguns ângulos/distâncias de nível irmãos estão ligeiramente errados,
embora (seguindo outras respostas) eu tenha usado o mecanismo aritmético de ponto fixo para tentar melhorar a precisão. Mesmo substituindo as funções trigonométricas pelos primeiros termos da sua série de Taylor,
\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}
os mesmos problemas estão presentes (observe que o número de nós aqui foi escolhido de modo a garantir que a série atan
convirja):
Há algo que eu possa fazer para superar esses problemas de imprecisão ou é um problema intrínseco do TikZ que não pode ser evitado? (assumindo que não há nenhuma falha na minha abordagem, como penso ser o caso).
Responder1
Não sei bem por que a matemática parece falhar neste caso (embora eu suponha que deveria), mas parece que não é um problema com a forma como o TikZ/PGF faz a matemática, tem algo a ver com a forma como as árvores são construídas .
Infelizmente, não consegui descobrir qual é exatamente o problema, mas o fato de que o problema énãoa precisão dos cálculos matemáticos em si pode ser demonstrada usando os mesmos cálculos fora de uma árvore:
\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}
Então deve haver algo mais acontecendo.
De qualquer forma, penso que você está trabalhando muito com algo que poderia ser feitomuitomais simplesmente com uma função de crescimento personalizada.
O seguinte mostra um exemplo da grow via three points
função de crescimento da trees
biblioteca.
\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}
Responder2
Uma solução 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}
Tudo o que você precisa fazer é alterar os valores dos parâmetros ( \NoDots
, \Hori
, e \Vert
) e o desenho será ajustado de acordo.
Responder3
Seu problema me deixou curioso. O MetaPost também usa aritmética de ponto fixo por padrão: um “numérico” não pode ser menor que 2^(-16)
nem maior que 2^12
, embora internamente o MetaPost possa lidar com valores até 2^15
. (Desde muito recentemente é possível alternar para vários modos aritméticos de ponto flutuante, mas não os usarei aqui.)
Resolvi então fazer uma versão MetaPost do seu segundo gráfico, com as mesmas funções, e observar o alinhamento. (Para ser processado com 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}
Bem, pelo que posso ver, eles parecem alinhados corretamente:
Portanto, neste caso parece haver um problema, não com a aritmética de ponto fixo em si, mas com a biblioteca de ponto fixo de tikz
(dois bits usados para representar os números?). Ou com a forma como as funções trigonométricas são definidas.
De qualquer forma, se for possível mudar para aritmética de ponto flutuante tikz
(talvez com LuaTeX?), isso melhoraria drasticamente a precisão.