Estate atento ya que en esta reseña hallarás la contestación que buscas.
Solución:
¡Qué buena pregunta! Me sorprende que nadie haya preguntado esto antes …
Aquí hay dos piezas del rompecabezas: hacer bien los círculos finales y decidir dónde dibujar los bordes. El primero resulta ser realmente fácil, si sabe qué buscar en el manual de TikZ. El segundo requiere un poco de matemáticas, pero no demasiadas.
Tratemos con el primero. Cuando dibuja un “ciclo” en TikZ, puede especificar los radios. Entonces puedes decir draw (0,0) circle[x radius=2cm, y radius=3cm];
. Esto producirá una elipse con el eje mayor hacia arriba y el eje menor en la horizontal. Ahora, en TikZ, puede especificar distancias adimensionales. Imaginemos la conversación …
usted: Dibuja un círculo con radio x 2cm y radio y 3cm.
TikZ: ¡Sí señor! ¡En seguida, señor!
usted: Dibuja un círculo con radio x 2 y radio y 3.
TikZ: ¡Sí señor! Bien … espera. “x radio 2”? 2 que? 2 manzanas? 2 naranjas?
usted: 2 en la dirección x.
TikZ: (poniéndose un poco quejumbroso) Sí, pero ¿dónde está eso?
usted: Los X dirección. De esa manera.
TikZ: ¿Podrías ser más específico?
usted: Bien, digamos que la dirección x es 1 cm a lo largo y 0,5 cm hacia arriba. ¿Eso servirá?
TikZ: Sí. pausa Ahora, ¿qué hay de ti?
El punto de esa tontería es que cuando especificas una longitud sin dimensiones, TikZ la interpreta como ese número multiplicado por el vector apropiado. Entonces x radius=2
significa “establecer el eje x de esta elipse para que sea el doble de la actual x
vector “. Pero tenemos un control total sobre lo que x
vector es! Entonces, si le decimos a TikZ que x
significa algo más, lo usará.
Lo bueno de esto es que si dices eso x=(1cm,1cm), y=(0cm,1cm)
entonces TikZ dibujará algo aproximado (cos θ, cos θ + sin θ), que es exactamente lo que quieres si estás mirando un círculo de tal manera que el eje x se encuentra en realidad a lo largo de la diagonal.
Comparar y contrastar:
documentclassstandalone
usepackagetikz
begindocument
begintikzpicture
draw[ultra thick] (0,0) circle[x radius=2,y radius=2];
draw[ultra thick] (4,0) circle[x=(1cm,1cm),y=(0cm,1cm),x radius=2,y radius=2];
draw[ultra thick] (8,0) circle[x=(1cm,1cm),y=(0cm,1cm),x radius=2cm,y radius=2cm];
endtikzpicture
enddocument
El del medio es el correcto aquí.
Entonces, para los extremos del cilindro, el truco es simple: dibuja tus extremos como círculos honestos usando adimensional longitudes. Luego ajuste el x
y y
valores para adaptarse. (Hay una advertencia aquí: si usa longitudes adimensionales para establecer el x
y y
valores, entonces se establecen en términos de Actualx
y y
. Aunque esto podría ser lo que desea en teoría, si escribe x=(1,1), y=(1,-1)
entonces el x
que se utiliza para configurar el y
es el nuevo, no el antiguo). Con radios adimensionales, también es posible utilizar las transformaciones correctamente.
Ahora a los bordes del cilindro. La dificultad aquí es que el lugar para dibujar los bordes está determinado por su ubicación final en la página. Entonces, para decidir dónde dibujar los bordes, necesitamos averiguar exactamente dónde se dibujarán los extremos del cilindro y encontrar sus puntos extremos. Lo que queremos decir con “extremo” aquí es que queremos dibujar una línea tangente a lo largo de la dirección del cilindro. Entonces tomamos la dirección ortogonal a la dirección del cilindro como se muestra en la página y busca los puntos extremos de los círculos deformados como se muestra en la página en esa direccion.
Afortunadamente, esto es bastante sencillo. Nuestro círculo deformado tiene la ecuación cos θ x + sen θ y ya sea en el espacio 3D o en la página. Así que solo tenemos que averiguar qué son xey en la página. Podemos hacer eso “dibujando” un vector de una unidad en la dirección xy registrando el real coordenadas. Para obtener la dirección ortogonal a la dirección del cilindro, “dibujamos” un vector en la dirección del cilindro y registramos también sus coordenadas. Llamemos a ese uno z. Luego tomamos su dirección ortogonal, digamos w. Así que ahora examinamos la función cos θ w · x + sen θ w · y y buscamos sus valores extremos. Diferenciando y estableciendo igual a cero, obtenemos -sin θ w · x + cos θ w · y = 0. Reordenando, obtenemos tan θ = w · y / w · x. Dado que solo queremos pecado θ y cos θ, en realidad no necesitamos resolver θ en sí mismo (aunque podemos hacerlo si lo necesitamos para otra cosa). Tenga en cuenta que usamos estos en el sistema de coordenadas original.
Poniendo todo eso junto, si asumimos que nuestro cilindro debe ir a lo largo de la dirección z (lo que sea que sea) y la sección transversal en el plano xy (de nuevo, sea lo que sea), entonces resolver las matemáticas es el siguiente código.
path (1,0,0);
pgfgetlastxycylxxcylxy
path (0,1,0);
pgfgetlastxycylyxcylyy
path (0,0,1);
pgfgetlastxycylzxcylzy
pgfmathsetmacrocylt(cylzy * cylyx - cylzx * cylyy)/ (cylzy * cylxx - cylzx * cylxy)
pgfmathsetmacroangatan(cylt)
pgfmathsetmacroct1/sqrt(1 + (cylt)^2)
pgfmathsetmacrostcylt * ct
Si esto fuera en un macro, podríamos ser un poco más eficientes y utilizar [email protected]
en lugar de dibujar un punto y obtener los últimos valores xy.
Una vez que tenemos esos valores, dibujar el cilindro en sí es bastante fácil. He aquí un ejemplo.
documentclassstandalone
usepackagetikz
begindocument
begintikzpicture
beginscope[x=(.7cm,-.3cm)]
path (1,0,0);
pgfgetlastxycylxxcylxy
path (0,1,0);
pgfgetlastxycylyxcylyy
path (0,0,1);
pgfgetlastxycylzxcylzy
pgfmathsetmacrocylt(cylzy * cylyx - cylzx * cylyy)/ (cylzy * cylxx - cylzx * cylxy)
pgfmathsetmacroangatan(cylt)
pgfmathsetmacroct1/sqrt(1 + (cylt)^2)
pgfmathsetmacrostcylt * ct
fill[red] (ct,st,0) -- ++(0,0,-8) arc[start angle=ang,delta angle=180,radius=1] -- ++(0,0,8) arc[start angle=ang+180,delta angle=-180,radius=1];
beginscope[every path/.style=ultra thick]
draw (0,0,0) circle[radius=1];
draw[->] (0,0,0) -- (1,0,0);
draw[->] (0,0,0) -- (0,1,0);
draw (ct,st,0) -- ++(0,0,-8);
draw (-ct,-st,0) -- ++(0,0,-8);
draw (ct,st,-8) arc[start angle=ang,delta angle=180,radius=1];
draw[dashed] (ct,st,-8) arc[start angle=ang,delta angle=-180,radius=1];
endscope
endscope
endtikzpicture
enddocument
Esto produce lo siguiente:
Si queremos ponernos un poco sofisticados, podemos poner algo de sombreado en el interior del cilindro llenándolo de colores sucesivamente más oscuros. Simplemente pon
foreach ztint in 0,.1,...,1
pgfmathsetmacrotint(ztint/2 + .5)*100
fill[blue!tint] (ct,st,-ztint) -- ++(0,0,-4) arc[start %% angle=ang,delta angle=-180,radius=1] -- ++(0,0,4) arc[start %% angle=ang+180,delta angle=180,radius=1];
antes de la línea que comienza fill[red]
. Esto produce:
Si cambiamos la definición de los vectores, digamos que [x=(.7cm,.3cm),z=(.5cm,-.5cm)]
, encontramos que se transforma como debería:
Las advertencias habituales sobre el uso de TikZ para dibujar dibujos en 3D se aplican aquí: depende de usted, el usuario, decidir qué se dibuja sobre qué y organizar su dibujo de manera adecuada.
Aquí hay un código que hice hace algún tiempo (usa gnuplot). Probablemente lo adaptes para dibujar cilindros más simples …
tikzsetmath3d/.style= x=(1cm,0cm), y=(0.353cm,0.353cm), z=(0cm,1cm)
begintikzpicture[math3d]
newcommandn11
newcommandh2
newcommandrl2
newcommandrh1
path[draw,fill=white] plot[domain=0:2*pi,samples=4*n] (rl*cos(x r), rl*sin(x r), 0);
foreach t in 1,...,n
filldraw[fill=gray] (rl*cos(2*t*pi/n r),rl*sin(2*t*pi/n r),0) -- (rl*cos((2*t+1)*pi/n r),rl*sin((2*t+1)*pi/n r),0) -- (rh*cos((2*t+1)*pi/n r),rh*sin((2*t+1)*pi/n r),h) -- (rh*cos(2*t*pi/n r),rh*sin(2*t*pi/n r),h) -- cycle;
path[draw,fill=white] plot[domain=0:2*pi,samples=4*n] (rh*cos(x r), rh*sin(x r), h);
beginscope[dashed,->,opacity=0.7]
draw (0,0,0) -- (rl,0,0) node[below] $x$;
draw (0,0,0) -- (0,rl,0) node[right] $y$;
draw (0,0,0) -- (0,0,h) node[above] $z$;
endscope
endtikzpicture
Por ejemplo, comience por configurar rl
y rh
al mismo valor (radio bajo y radio alto). n
es el número de “paneles” y h
es la altura del cilindro.
Tenga en cuenta que no es tan fácil saber dónde dibujar las líneas verticales aparentes de los cilindros. Seguramente se puede calcular el ángulo en el que ocurren, pero no es sencillo. La solución anterior permite evitar este problema.
Con el boceto puede obtener:
el código (tomado de la documentación) es
def n_cyl_segs 20 def n_views 10 def I [1,0,0]
def endopts [fill=blue]
repeat n_views, rotate(180/n_views, [I]) then translate([I] * 2.1)
sweep[endopts] n_cyl_segs<>, rotate(360/n_cyl_segs, [0,1,0])
line[fill=red](1,-1)(1,1)
global language tikz
En mi humilde opinión, una referencia muy útil para dibujar objetos en la perspectiva correcta es: Norling: perspectiva simplificada
Si para ti ha resultado de ayuda este artículo, te agradeceríamos que lo compartas con más entusiastas de la programación y nos ayudes a difundir este contenido.