El problema que tengo, es que necesito convertir rotaciones de eje fijo XYZ, rotaciones de Euler sobre Z, luego X ', luego Z' '.Convirtiendo desde una rotación de Euler ZXZ a rotaciones de eje fijo XYZ
Aquí son las matrices relevantes:
X:
Y:
Z:
combinada, como Rz (psi) Ry (phi) Rx (theta) = Rxyz (theta, phi, psi); que os den
Rxyz:
Y la matriz de rotación para la convención específica de los ángulos de Euler que quiero; es la siguiente:
Euler:
Así que mi plan inicial, fue comparar elementos de la matriz, y extraer los ángulos que yo quería de esa manera; Se me ocurrió esto (código actual real al final):
Pero esto no funciona en varias circunstancias. El ser más obvio cuando Cos (theta) Cos (phi) == 1; desde entonces Cos (beta) = 1, y entonces Sin [beta] = 0. Donde Sin (beta) es s2 en el código. Esto ocurre solo cuando Cos (theta) y cos (phi) = +/- 1.
Así que de inmediato puedo descartar las posibles situaciones;
Cuando theta o phi = 0, 180, 360, 540, ..., entonces Cos (theta) y Cos (phi) son +/- 1;
así que solo tengo que hacerlo de manera diferente para estos casos;
y terminé con este código:
public static double[] ZXZtoEuler(double θ, double φ, double ψ){
θ *= Math.PI/180.0;
φ *= Math.PI/180.0;
ψ *= Math.PI/180.0;
double α = -1;
double β = -1;
double γ = -1;
double c2 = Math.cos(θ) * Math.cos(φ);
β = Math.acos(r(c2));
if(eq(c2,1) || eq(c2,-1)){
if(eq(Math.cos(θ),1)){
if(eq(Math.cos(φ),1)){
α = 0.0;
γ = ψ;
}else if(eq(Math.cos(φ),-1)){
α = 0.0;
γ = Math.PI - ψ;
}
}else if(eq(Math.cos(θ),-1)){
if(eq(Math.cos(φ),1)){
α = 0.0;
γ = -ψ;
}else if(eq(Math.cos(φ),-1)){
α = 0.0;
γ = ψ + Math.PI;
}
}
}else{
//original way
double s2 = Math.sin(β);
double c3 = (Math.sin(θ) * Math.cos(φ))/ s2;
double s1 = (Math.sin(θ) * Math.sin(ψ) + Math.cos(θ) * Math.sin(φ) * Math.cos(ψ))/s2;
γ = Math.acos(r(c3));
α = Math.asin(r(s1));
}
α *= 180/Math.PI;
β *= 180/Math.PI;
γ *= 180/Math.PI;
return new double[] {r(α), r(β), r(γ)};
}
donde R y eq son sólo dos funciones simples;
public static double r(double a){
double prec = 1000000000.0;
return Math.round(a*prec)/prec;
}
static double thresh = 1E-4;
public static boolean eq(double a, double b){
return (Math.abs(a-b) < thresh);
}
eq es sólo para comparar los números para las pruebas, y r es para evitar errores puntuales que empujan los números fuera del rango de Math.acos/Math.asin y me dan resultados NaN flotante;
(es decir, de vez en cuando que terminaría siendo con Math.acos (1,000000000000000004) o algo así.)
que tiene en cuenta los 4 casos de tener rotaciones alrededor de x e y que dejan c2 == 1 .
Pero ahora es donde ocurre el problema;
Todo lo que he hecho anteriormente, tiene sentido para mí, pero no da los ángulos correctos;
Aquí hay alguna salida, en cada par, los primeros son los ángulos theta phi psi, y el segundo de cada par son las líneas alfa gamma correspondientes.Haciendo caso omiso de los errores de redondeo, que parece ser cada vez algunos de los ángulos fuera en alrededor de
[0.0, 0.0, 0.0] - correct!
[0.0, 0.0, 0.0]
[0.0, 0.0, 45.0] - correct!
[0.0, 0.0, 45.0]
[0.0, 0.0, 90.0] - correct!
[0.0, 0.0, 90.0]
[0.0, 0.0, 135.0] - correct!
[0.0, 0.0, 135.0]
[0.0, 0.0, 180.0] - correct
[0.0, 0.0, 180.0]
[0.0, 0.0, 225.0] - correct
[0.0, 0.0, 225.0]
[0.0, 0.0, 270.0] - correct
[0.0, 0.0, 270.0]
[0.0, 0.0, 315.0] - correct
[0.0, 0.0, 315.0]
[0.0, 45.0, 0.0] - incorrect: should be [90, 45, -90]
[90.0, 44.999982, 90.0]
[0.0, 45.0, 45.0]
[45.000018, 44.999982, 90.0]
[0.0, 45.0, 90.0]
[0.0, 44.999982, 90.0]
[0.0, 45.0, 135.0]
[-45.000018, 44.999982, 90.0]
[0.0, 45.0, 180.0]
[-90.0, 44.999982, 90.0]
[0.0, 45.0, 225.0]
[-45.000018, 44.999982, 90.0]
[0.0, 45.0, 270.0]
[0.0, 44.999982, 90.0]
[0.0, 45.0, 315.0]
[45.000018, 44.999982, 90.0]
[0.0, 90.0, 0.0]
[90.0, 90.0, 90.0]
[0.0, 90.0, 45.0]
[45.000018, 90.0, 90.0]
[0.0, 90.0, 90.0]
[0.0, 90.0, 90.0]
[0.0, 90.0, 135.0]
[-45.000018, 90.0, 90.0]
[0.0, 90.0, 180.0]
[-90.0, 90.0, 90.0]
[0.0, 90.0, 225.0]
[-45.000018, 90.0, 90.0]
creo que es debido a la forma Math.acos y Math.asin trabajo, ¿Puede alguien pensar en una solución?
EDITAR: math.asin y math.acos devuelven valores entre -pi/2 y pi/2 y 0 y pi respectivamente. Esto no es ambiguo, así que no creo que el problema esté aquí. Parece como si pudiera tener las matemáticas mal en alguna parte, pero no puedo ver un agujero en mi razonamiento ...
Edit2: Para nadie cómo no saben cómo funcionan las rotaciones de Euler, es como esto:
es decir, girar alrededor de Z, a continuación, alrededor del nuevo eje X (X'), entonces alrededor de la nueva Z '' eje.
Los ángulos de Euler tienen ambigüedades a los 90 - Creo que 0/45/0 es equivalente a 90/45/-90 si entiendo tus ejes correctamente. –
los ángulos de Euler giran alrededor de Z, luego X ', luego Z' ', entonces 0/45/0 es 45 sobre el eje X, mientras que 90/45/90 gira los ejes para que el eje X' sea el mismo que el eje Y 90/45/-90 es una rotación de 45 aproximadamente Y. – will