Как преобразовать вектор направления в углы Эйлера?

Я ищу способ преобразования вектора направления (X, Y, Z) в углы Эйлера (заголовок, шаг, банк). Я знаю, что этот вектор направления сам по себе недостаточен, чтобы получить угол банка, поэтому есть еще один так называемый вектор вверх.

Имея вектор направления (X, Y, Z) и вектор вверх (X, Y, Z), как преобразовать его в углы Эйлера?

Ответ 1

Посмотрим, правильно ли я понимаю. Речь идет о ориентации твердого тела в трехмерном пространстве, подобно воздушной плоскости во время полета. Нос этого самолета указывает на вектор направления

D=(XD,YD,ZD) .

К крышу расположен вектор вверх

U=(XU,YU,ZU) .

Тогда заголовок H будет вектором направления D, проецируемым на поверхность земли:

H=(XD,YD,0) ,

с соответствующим углом

angle_H=atan2(YD,XD) .

Pitch P будет угол вверх/вниз носа относительно горизонта, если вектор направления D нормализован, вы получите его от

ZD=sin(angle_P)

в результате чего

angle_P=asin(ZD) .

Наконец, для угла банка мы рассматриваем направление крыльев, полагая, что крылья перпендикулярны телу. Если плоскость летит прямо к D, точки крыльев перпендикулярны к D и параллельны земной поверхности:

W0 = ( -YD, XD, 0 )

Это будет угол в банке 0. Ожидаемый Up Vector будет перпендикулярен к W0 и перпендикулярен к D

U0 = W0 × D

с ×, обозначающим поперечное произведение. U равно U0, если угол банка равен нулю, в противном случае угол между U и U0 является углом банка angle_B, который можно вычислить из

cos(angle_B) = Dot(U0,U) / abs(U0) / abs(U)
sin(angle_B) = Dot(W0,U) / abs(W0) / abs(U) .

Из этого вы получите угол банка как

angle_B = atan2( Dot(W0,U) / Dot(U0,U) / abs(W0) * abs(U0) ) .

Нормирующие коэффициенты отменяют друг друга, если U и D нормированы.

Ответ 2

нам нужны три вектора: X1, Y1, Z1 локальной системы координат (LCS), выраженные в терминах мировой системы координат (WCS). В приведенном ниже коде показано, как вычислить три угла Эйлера на основе этих 3 векторов.

#include <math.h> 
#include <float.h> 

#define PI 3.141592653589793 
/**
 * @param X1x
 * @param X1y
 * @param X1z X1 vector coordinates
 * @param Y1x
 * @param Y1y
 * @param Y1z Y1 vector coordinates
 * @param Z1x
 * @param Z1y
 * @param Z1z Z1 vector coordinates
 * @param pre precession rotation
 * @param nut nutation rotation
 * @param rot intrinsic rotation
 */
void lcs2Euler(
        double X1x, double X1y, double X1z,
        double Y1x, double Y1y, double Y1z,
        double Z1x, double Z1y, double Z1z,
        double *pre, double *nut, double *rot) {
    double Z1xy = sqrt(Z1x * Z1x + Z1y * Z1y);
    if (Z1xy > DBL_EPSILON) {
        *pre = atan2(Y1x * Z1y - Y1y*Z1x, X1x * Z1y - X1y * Z1x);
        *nut = atan2(Z1xy, Z1z);
        *rot = -atan2(-Z1x, Z1y);
    }
    else {
        *pre = 0.;
        *nut = (Z1z > 0.) ? 0. : PI;
        *rot = -atan2(X1y, X1x);
    }
}