Junta universal Cardán. es un elemento mecanico que tiene la suficiente complejidad como para necesitar de técnicas que no hemos visto hasta ahora.

Utilizaremos una nueva macro Axis_Rotate_Trans(Axis, Angle) para implementar el giro de objetos que viene en «transforms.inc«.

Verás la explicación de esta función en varios sitios, pero aquí te ofrecemos un ejemplo muy sencillo que explica como se usa, porque no hay nada como ver un ejemplito con su código. ¿Verdad?

El modelo de este sistema mecánico debería estar formado por tres piezas. Un par de ejes terminados en una horquilla (pieza en U) y una cruceta central que representamos con un metal más oscuro.

Sin embargo, hemos hecho algunas trampitas. Nuestro fuente sólo incluye dos piezas formadas por un eje terminado en horquilla que ya incorpora la parte de la cruceta que está insertada en la horquilla.

La cruceta es de un material liso y una vez colocadas las piezas correctamente no se nota la trampa. Tampoco se nota que nos hemos ahorrado horadar la horquilla para hacer el agujero donde se inserta la cruceta ya que las piezas convenientemente interpenetradas crean la ilusión de la forma que deseamos representar.

Si hubiéramos creado la cruceta como una pieza independiente, la implementación de su giro en el espacio habría resultado más laboriosa dado que las combinaciones de tantos giros distintos no son algo trivial.

Precisamente por esa razón, no podemos usar los giros en la forma tradicional referidos a los ejes X,Y,Z para animar el conjunto que combina un par de giros. En lugar de ello usamos un giro corriente para girar uno de los ejes que formará un ángulo con el anterior, y luego a partir del vector de dirección del eje obtenido en su nueva posición, aplicamos un giro de rotación al rededor del mismo.

El vector en dirección del eje se obtiene mediante la resta de los extremos del cilindro del eje. (<0,0,TamCruceta>–<0,0,5>)

Una vez obtenido un eje el otro se coloca girado 180 grados respecto del eje y (rotate y*180) y los ejes deben rotar en el mismo sentido pero desfasados 90 grados.

La constante Epsil es un valor muy pequeño distinto de cero. Sirve para solucionar pequeños fallos que suelen ocurrir cuando restamos formas que comparten alguna superficie creando una indeterminación que se traduce en partes de la imágenes afectadas de ruido debido a los pequeños errores de redondeo que se originan durante los cálculos internos del trazador al operar en coma flotante. Si le das el valor cero a esta constante podrás ver estos errores.

// junta_cardan.pov
// (C) Antonio Castro Snurmacher
// Licencia GPL de GNU
// rm -f junta_cardan*.png ; pov.py junta_cardan n 11 11 1 1800 1 1800 ; ffmpeg -f image2 -i junta_cardan%04d.png -sameq -y junta_cardan.avi
#include "colors.inc"
#include "textures.inc"
#include "shapes.inc"
#include "stones.inc"
#include "metals.inc"
#include "transforms.inc"
#declare Luz1=light_source { <-5, 20, 5> color Gray50 }
#declare Luz2=light_source { <20, 5, -5> color Gray50 }
#declare CameraDown= camera {
location <9, 8, -20>
look_at <0,0,0>
angle 20
// AspectRatio debe declararse en el '.ini'
// Su valor es el ancho/alto y normalmente valdrá 16/9 o 4/3
right AspectRatio*x
// rotate <0,Clock05,0>
}
#declare CameraUp= camera {
location <5, 30, 2>
look_at <0,0,0>
angle 30
// AspectRatio debe declararse en el '.ini'
// Su valor es el ancho/alto y normalmente valdrá 16/9 o 4/3
right AspectRatio*x
// rotate <0,Clock05,0>
}
#declare Camera00= camera {
location <20, 7, 5>
look_at <0,0,0>
angle 25
// AspectRatio debe declararse en el '.ini'
// Su valor es el ancho/alto y normalmente valdrá 16/9 o 4/3
right AspectRatio*x
// rotate <0,Clock05,0>
}
#declare EscalaSuelo=8;
#declare Suelo2= plane { y, -2/EscalaSuelo
texture {T_Stone21}
scale EscalaSuelo
}
#declare Metal1 = texture {
pigment {Gray60}
finish { ambient 0.2 diffuse 0.45 reflection 0.35 phong 0.7 phong_size 7 }
}
#declare Metal2 = texture {
pigment {Gray30}
finish { ambient 0.2 diffuse 0.5 reflection 0.3 phong 0.7 phong_size 7 }
}
#declare Epsil=.000000001; // Un tamaño arbitrario muy pequeño.
#declare TamCruceta=1.2;
#declare TamCrucetaM=TamCruceta+Epsil;
#declare RadCruceta=.5;
#declare TamAnchoU=(TamCruceta+RadCruceta)/2.5;
#declare GrosorU=.25; // .25
#declare Epsil2 = .1;
#declare A=intersection {
box {<-Epsil-TamAnchoU,-Epsil-GrosorU/2,-TamAnchoU>}
union{
cylinder {<0,TamCruceta,0>,<0,-TamCruceta,0>,TamAnchoU}
box {<-TamAnchoU,-GrosorU/2,0>}
}
}
#declare U= union{
intersection {A
translate <0,-TamCruceta+GrosorU/2,0>
}
intersection {A
translate <0,TamCruceta-GrosorU/2,0>
}
difference{
cylinder {<-TamAnchoU,0,RadCruceta>,, TamCruceta}
union{
box {,<-TamCrucetaM,-TamCrucetaM,-TamCrucetaM>}
cylinder {<-TamCrucetaM,0,RadCruceta>,, TamCruceta-GrosorU}
}
}
}
#declare Eje = union{
object{
cylinder {<0,TamCruceta+Epsil2,0>,<0,-TamCruceta-Epsil2,0>,RadCruceta}
texture {Metal2}
}
object{
union {
cylinder {<0,0,TamCruceta+Epsil2*2>,<0,0,5>, .5}
difference {U}
}
texture {Metal1}
}
}
#declare MaxAnguloArticula=55;
#declare Clock2= clock*1.5;
#declare RotX=<-MaxAnguloArticula*clock/1800,0,0>;
camera {Camera00}
Luz1
Luz2
Suelo2
object {
Eje
Axis_Rotate_Trans(<0,0,TamCruceta>-<0,0,5>, Clock2+90)
rotate RotX
}
object {Eje
rotate y*180
Axis_Rotate_Trans(<0,0,TamCruceta>-<0,0,5>, Clock2)
}