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

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

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


person Kromster    schedule 07.02.2014    source источник
comment
Этот вопрос кажется не по теме, потому что он касается математики, и его следует переместить на math.stackexchange.com.   -  person Bas Bossink    schedule 07.02.2014
comment
@BasBossink Я согласен, но, к сожалению, вопрос слишком стар, чтобы его можно было перемещать сейчас.   -  person jrh    schedule 28.06.2018


Ответы (2)


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

D=(XD,YD,ZD) .

В сторону крыши - вектор вверх.

U=(XU,YU,ZU) .

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

H=(XD,YD,0) ,

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

angle_H=atan2(YD,XD) .

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

ZD=sin(angle_P)

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

angle_P=asin(ZD) .

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

W0 = ( -YD, XD, 0 )

Это будет угол крена 0. Ожидаемый вектор вверх будет перпендикулярен 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) .

Здесь abs вычисляет длину вектора. Отсюда вы получаете угол крена как

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

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

person pentadecagon    schedule 07.02.2014
comment
Я знаю, что это старый пост, но он мне тоже полезен. Я хотел бы знать, что означает abs(W0) * abs(U0). Возвращает ли функция abs() длину вектора? И тогда, разве функция atan2 не должна принимать два аргумента? х и у? В примере передается только один параметр, и я не могу понять, почему. - person zeb; 19.03.2015
comment
atan2 предполагает два аргумента, я полагаю, что angle_B = atan2( Dot(W0,U) / Dot(U0,U) / abs(W0) * abs(U0) ) . должно быть скорее angle_B = atan2( Dot(W0,U) , Dot(U0,U) / abs(W0) * abs(U0) ) . - person Samuel; 12.06.2015
comment
Я проголосовал за этот ответ, поскольку значение abs () неясно, и, как сказал Самуэль, atan2 ожидает два параметра, а не только один. - person padmalcom; 22.10.2017
comment
Отличный алгоритм. Это тоже решило мою проблему :) Однако эта проблема является частью диссертации. Следовательно, у вас есть источник, где это объясняется аналогичным образом, чтобы я мог ссылаться на него? - person DragonGamer; 04.02.2019
comment
Я думаю, что angle_B неверно для крайнего случая, где D=(0,0,1) или D=(0,0,-1). W0 и U0 оба заканчиваются как (0,0,0). В настоящее время я не знаю, как с этим справиться. - person Robadob; 13.03.2021
comment
Реализуя это в GLSL, я также обнаружил, что angle_H работает неправильно для того же крайнего случая. Однако это связано с atan(0,0) неопределенным поведением GLSL, поэтому результаты могут отличаться. - person Robadob; 13.03.2021

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

#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);
    }
}
person 4pie0    schedule 07.02.2014
comment
Когда вы говорите 3 вектора (по какой-то причине называются X Y Z?), Вы имеете в виду начало координат (0,0,0), направление и вектор вверх? Что в вашем ответе? - person Kromster; 07.02.2014
comment
X, Y, Z - векторы направления осей системы координат LCS в [GCS]. Z - это ваше направление, и эти два могут быть получены путем векторного умножения Z и вашего вектора вверх. - person Spektre; 07.02.2014
comment
Я этого не понимаю. Можем ли мы перейти на простой GCS для ясности? - person Kromster; 07.02.2014
comment
LCS - это система координат вашей «камеры», или плоскости, или чего-то еще, что просматривается / движется в направлении Z. (Ось Z LCS) = (вектор направления Z) = (вектор вашего направления). Ортогональные системы имеют 3 оси, а не одну, поэтому вам нужно 2 перпендикулярных вектора к ней. Если ваш вектор вверх перпендикулярен направлению, тогда (вектор оси Y) = (ваш вектор вверх), и тогда ось X проста X = Z * Y или X = Y * Z ... - person Spektre; 07.02.2014
comment
этот фрагмент кода взят отсюда: geom3d.com/data/documents/ Расчет = 20of = 20Euler = 20angles.pdf - person christian; 19.01.2020