
Quiero construir un árbol que satisfaga lo siguiente:
- Crece hacia la derecha.
- El primer niño crece a 0 grados (los niños siguientes crecen en el sentido de las agujas del reloj).
- Todos los nodos secundarios están en la misma vertical y la distancia entre nodos consecutivos es siempre la misma.
Considerándolo todo, lo que me gustaría lograr es esto:
De hecho, una manera fácil de codificar es a través de
\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}
Sin embargo, probé un enfoque alternativo, que esperaba que produjera los mismos 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}
Tenga en cuenta que en el código anterior he asumido que 1) la distancia de nivel del primer niño (horizontal) es de 3 cm y 2) el segundo niño crece a -5 grados. Con estas dos condiciones y algo de trigonometría básica, se puede calcular primero la distancia entre hermanos entre nodos consecutivos y luego el ángulo g
y la distancia de nivel l
para cualquier nodo secundario.
Creo que mi parametrización es correcta; sin embargo, algunos ángulos/distancias de nivel entre hermanos están ligeramente desviados,
aunque (después de otras respuestas) utilicé el motor aritmético de punto fijo para intentar mejorar la precisión. Incluso reemplazando las funciones trigonométricas por los primeros términos de su serie 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}
Están presentes los mismos problemas (tenga en cuenta que el número de nodos aquí se ha elegido para garantizar que la serie atan
converja):
¿Hay algo que pueda hacer para superar estos problemas de inexactitud o es un problema intrínseco de TikZ que no se puede evitar? (suponiendo que no haya ningún defecto en mi enfoque, como creo que es el caso).
Respuesta1
No sé muy bien por qué las matemáticas parecen fallar en este caso (aunque supongo que debería hacerlo), pero parece que no es un problema con la forma en que TikZ/PGF hace las matemáticas, tiene algo que ver con la forma en que se construyen los árboles. .
Desafortunadamente, no he podido determinar cuál es exactamente el problema, pero el hecho de que el problema seanoLa precisión de los cálculos matemáticos per se se puede demostrar utilizando los mismos cálculos fuera de un árbol:
\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}
Entonces debe haber algo más sucediendo.
En cualquier caso, creo que estás trabajando mucho en algo que se podría hacer.muchomás simplemente con una función de crecimiento personalizada.
A continuación se muestra un ejemplo de la grow via three points
función de crecimiento de la 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}
Respuesta2
Una solución de 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}
Todo lo que tienes que hacer es cambiar los valores de los parámetros ( \NoDots
, \Hori
y \Vert
) y el dibujo se ajustará en consecuencia.
Respuesta3
Tu problema me dio curiosidad. MetaPost también utiliza aritmética de punto fijo por defecto: un “numérico” no puede ser menor 2^(-16)
ni mayor que 2^12
, aunque internamente MetaPost puede manejar valores hasta 2^15
. (Desde hace poco es posible cambiar a varios modos aritméticos de punto flotante, pero no los usaré aquí).
Así que decidí hacer una versión MetaPost de tu segundo gráfico, con las mismas funciones, y observar la alineación. (Para ser procesado con 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}
Bueno, por lo que puedo ver, parecen alineados correctamente:
Entonces, en este caso parece haber un problema, no con la aritmética de punto fijo en sí misma, sino con la biblioteca de punto fijo de tikz
(¿dos pocos bits utilizados para representar los números?). O con la forma en que se definen las funciones trigonométricas.
De todos modos, si es posible cambiar a la aritmética de punto flotante tikz
(¿quizás con LuaTeX?), mejoraría drásticamente la precisión.