У меня есть углы наклона, крена и угла. Как бы преобразовать их в вектор направления?
Было бы особенно круто, если бы вы могли показать мне кватернион и/или матричное представление этого!
У меня есть углы наклона, крена и угла. Как бы преобразовать их в вектор направления?
Было бы особенно круто, если бы вы могли показать мне кватернион и/или матричное представление этого!
К сожалению, существуют различные соглашения о том, как определять эти вещи (и рулон, шаг, рыскание не совсем такие же, как углы Эйлера), поэтому вам нужно быть осторожным.
Если мы определяем pitch = 0 как горизонтальный (z = 0) и yaw как против часовой стрелки от оси x, тогда вектор направления будет
x = cos(yaw)*cos(pitch) y = sin(yaw)*cos(pitch) z = sin(pitch)
Обратите внимание, что я не использовал roll; это вектор единицы направления, он не указывает отношения. Достаточно легко написать матрицу вращения, которая будет переносить вещи в кадр летающего объекта (если вы хотите знать, скажем, там, где указывает левое крыло), но это действительно хорошая идея, чтобы сначала определить соглашения. Не могли бы вы рассказать нам больше о проблеме?
EDIT: (Я хотел вернуться к этому вопросу в течение двух с половиной лет.)
Для полной матрицы вращения, если мы используем вышеприведенное соглашение, и сначала хотим, чтобы вектор был рывком, затем шаг, затем сверните, чтобы получить окончательные координаты в мировой системе координат, мы должны применять матрицы вращения в обратный порядок.
Первый рулон:
| 1 0 0 |
| 0 cos(roll) -sin(roll) |
| 0 sin(roll) cos(roll) |
затем шаг:
| cos(pitch) 0 -sin(pitch) |
| 0 1 0 |
| sin(pitch) 0 cos(pitch) |
затем yaw:
| cos(yaw) -sin(yaw) 0 |
| sin(yaw) cos(yaw) 0 |
| 0 0 1 |
Объедините их, и общая матрица вращения:
| cos(yaw)cos(pitch) -cos(yaw)sin(pitch)sin(roll)-sin(yaw)cos(roll) -cos(yaw)sin(pitch)cos(roll)+sin(yaw)sin(roll)|
| sin(yaw)cos(pitch) -sin(yaw)sin(pitch)sin(roll)+cos(yaw)cos(roll) -sin(yaw)sin(pitch)cos(roll)-cos(yaw)sin(roll)|
| sin(pitch) cos(pitch)sin(roll) cos(pitch)sin(roll)|
Итак, для единичного вектора, начинающегося с оси x, конечные координаты будут:
x = cos(yaw)cos(pitch)
y = sin(yaw)cos(pitch)
z = sin(pitch)
И для единичного вектора, который начинается с оси y (левый крыло), конечные координаты будут:
x = -cos(yaw)sin(pitch)sin(roll)-sin(yaw)cos(roll)
y = -sin(yaw)sin(pitch)sin(roll)+cos(yaw)cos(roll)
z = cos(pitch)sin(roll)
Существует шесть различных способов преобразования трех углов Эйлера в матрицу в зависимости от порядка, в котором они применяются:
typedef float Matrix[3][3];
struct EulerAngle { float X,Y,Z; };
// Euler Order enum.
enum EEulerOrder
{
ORDER_XYZ,
ORDER_YZX,
ORDER_ZXY,
ORDER_ZYX,
ORDER_YXZ,
ORDER_XZY
};
Matrix EulerAnglesToMatrix(const EulerAngle &inEulerAngle,EEulerOrder EulerOrder)
{
// Convert Euler Angles passed in a vector of Radians
// into a rotation matrix. The individual Euler Angles are
// processed in the order requested.
Matrix Mx;
const FLOAT Sx = sinf(inEulerAngle.X);
const FLOAT Sy = sinf(inEulerAngle.Y);
const FLOAT Sz = sinf(inEulerAngle.Z);
const FLOAT Cx = cosf(inEulerAngle.X);
const FLOAT Cy = cosf(inEulerAngle.Y);
const FLOAT Cz = cosf(inEulerAngle.Z);
switch(EulerOrder)
{
case ORDER_XYZ:
Mx.M[0][0]=Cy*Cz;
Mx.M[0][1]=-Cy*Sz;
Mx.M[0][2]=Sy;
Mx.M[1][0]=Cz*Sx*Sy+Cx*Sz;
Mx.M[1][1]=Cx*Cz-Sx*Sy*Sz;
Mx.M[1][2]=-Cy*Sx;
Mx.M[2][0]=-Cx*Cz*Sy+Sx*Sz;
Mx.M[2][1]=Cz*Sx+Cx*Sy*Sz;
Mx.M[2][2]=Cx*Cy;
break;
case ORDER_YZX:
Mx.M[0][0]=Cy*Cz;
Mx.M[0][1]=Sx*Sy-Cx*Cy*Sz;
Mx.M[0][2]=Cx*Sy+Cy*Sx*Sz;
Mx.M[1][0]=Sz;
Mx.M[1][1]=Cx*Cz;
Mx.M[1][2]=-Cz*Sx;
Mx.M[2][0]=-Cz*Sy;
Mx.M[2][1]=Cy*Sx+Cx*Sy*Sz;
Mx.M[2][2]=Cx*Cy-Sx*Sy*Sz;
break;
case ORDER_ZXY:
Mx.M[0][0]=Cy*Cz-Sx*Sy*Sz;
Mx.M[0][1]=-Cx*Sz;
Mx.M[0][2]=Cz*Sy+Cy*Sx*Sz;
Mx.M[1][0]=Cz*Sx*Sy+Cy*Sz;
Mx.M[1][1]=Cx*Cz;
Mx.M[1][2]=-Cy*Cz*Sx+Sy*Sz;
Mx.M[2][0]=-Cx*Sy;
Mx.M[2][1]=Sx;
Mx.M[2][2]=Cx*Cy;
break;
case ORDER_ZYX:
Mx.M[0][0]=Cy*Cz;
Mx.M[0][1]=Cz*Sx*Sy-Cx*Sz;
Mx.M[0][2]=Cx*Cz*Sy+Sx*Sz;
Mx.M[1][0]=Cy*Sz;
Mx.M[1][1]=Cx*Cz+Sx*Sy*Sz;
Mx.M[1][2]=-Cz*Sx+Cx*Sy*Sz;
Mx.M[2][0]=-Sy;
Mx.M[2][1]=Cy*Sx;
Mx.M[2][2]=Cx*Cy;
break;
case ORDER_YXZ:
Mx.M[0][0]=Cy*Cz+Sx*Sy*Sz;
Mx.M[0][1]=Cz*Sx*Sy-Cy*Sz;
Mx.M[0][2]=Cx*Sy;
Mx.M[1][0]=Cx*Sz;
Mx.M[1][1]=Cx*Cz;
Mx.M[1][2]=-Sx;
Mx.M[2][0]=-Cz*Sy+Cy*Sx*Sz;
Mx.M[2][1]=Cy*Cz*Sx+Sy*Sz;
Mx.M[2][2]=Cx*Cy;
break;
case ORDER_XZY:
Mx.M[0][0]=Cy*Cz;
Mx.M[0][1]=-Sz;
Mx.M[0][2]=Cz*Sy;
Mx.M[1][0]=Sx*Sy+Cx*Cy*Sz;
Mx.M[1][1]=Cx*Cz;
Mx.M[1][2]=-Cy*Sx+Cx*Sy*Sz;
Mx.M[2][0]=-Cx*Sy+Cy*Sx*Sz;
Mx.M[2][1]=Cz*Sx;
Mx.M[2][2]=Cx*Cy+Sx*Sy*Sz;
break;
}
return(Mx);
}
FWIW, некоторый процессор может одновременно вычислить Sin и Cos (например, fsincos на x86). Если вы это сделаете, вы можете сделать это немного быстрее, используя три вызова вместо 6, чтобы вычислить начальные значения sin и cos.
Обновление: на самом деле существует 12 способов, если вы хотите получить правые или левые результаты - вы можете изменить "ручность", отрицая углы.
vDir->X = sin(yaw);
vDir->Y = -(sin(pitch)*cos(yaw));
vDir->Z = -(cos(pitch)*cos(yaw));
Обратите внимание на смену знака и подменю "поворот". Надеюсь, это немного сэкономит.
Вам нужно четко рассказать о своих определениях здесь - в частности, какой вектор вы хотите? Если это направление, на которое указывает самолет, рулон даже не влияет на него, и вы просто используете сферические координаты (возможно, с осями/углы перепутаны).
Если, с другой стороны, вы хотите взять данный вектор и преобразовать его под этими углами, вы ищете матрицу вращения. wiki article на матрицах вращения содержит формулу для поворота поворота в направлении поворота, основанного на матрицах вращения xyz. Я не собираюсь вводить его здесь, учитывая греческие буквы и матрицы.
Если кто-то наткнется на поиск в FreeCAD.
import FreeCAD, FreeCADGui
from FreeCAD import Vector
from math import sin, cos, pi
cr = FreeCADGui.ActiveDocument.ActiveView.getCameraOrientation().toEuler()
crx = cr[2] # Roll
cry = cr[1] # Pitch
crz = cr[0] # Yaw
crx = crx * pi / 180.0
cry = cry * pi / 180.0
crz = crz * pi / 180.0
x = sin(crz)
y = -(sin(crx) * cos(crz))
z = cos(crx) * cos(cry)
view = Vector(x, y, z)