Convert Euler to Matrix and Matrix to Euler

I am trying to convert the three-dimensional rotation described in terms of Euler angles into a matrix, and then back using .NET / C #. My conventions:

  • left system (x right, y top, z forward)
  • order of revolutions: heading around y, step around x, bank around z
  • rotation is positive using the left hand rule (large pointer to + infinity)

My test:

Euler to the matrix (I simplified the translation part of x, y, z)

Matrix3D matrix = new Matrix3D() { M11 = cosH * cosB - sinH * sinP * sinB, M12 = - sinB * cosP, M13 = sinH * cosB + cosH * sinP * sinB, M21 = cosH * sinB + sinH * sinP * cosB, M22 = cosB * cosP, M23 = sinB * sinH - cosH * sinP * cosB, M31 = - sinH * cosP, M32 = - sinP, M33 = cosH * cosP, }; 

Matrix for Euler

 const double RD_TO_DEG = 180 / Math.PI; double h, p, b; // angles in degrees // extract pitch double sinP = -matrix.M23; if (sinP >= 1) { p = 90; } // pole else if (sinP <= -1) { p = -90; } // pole else { p = Math.Asin(sinP) * RD_TO_DEG; } // extract heading and bank if (sinP < -0.9999 || sinP > 0.9999) { // account for small angle errors h = Math.Atan2(-matrix.M31, matrix.M11) * RD_TO_DEG; b = 0; } else { h = Math.Atan2(matrix.M13, matrix.M33) * RD_TO_DEG; b = Math.Atan2(matrix.M21, matrix.M22) * RD_TO_DEG; } 

This must be wrong. If I take 3 angles, convert them to a matrix and convert the matrix back to angles, the result will be different from the intial values.

I looked at several sites with different formulas starting with euclideanspace.com, but now I am completely lost and cannot find the correct calculations. I appreciate a little help. Is there a mathematician on board?

+7
math c # matrix 3d euler-angles
source share
3 answers

Firstly, it should:

 sinP = -matrix.M32 

EDIT: Complete solution follows

My conclusion:

 Rx(P)=| 1 0 0 | | 0 cos P -sin P | | 0 sin P cos P | Ry(H)=| cos H 0 sin H | | 0 1 0 | | -sin H 0 cos H | Rz(B)=| cos B -sin B 0 | | sin B cos B 0 | | 0 0 1 | 

Multiplies with your order:

 R = Ry(H)*Rx(P)*Rz(B) = | cos H*cos B+sin H*sin P*sin B cos B*sin H*sin P-sin B*cos H cos P*sin H | | cos P*sin B cos B*cos P -sin P | | sin B*cos H*sin P-sin H*cos B sin H*sin B+cos B*cos H*sin P cos P*cos H | 

Which gives the opposite conclusions:

tan B = M12 / M22

sin P = -M32

tan H = M31 / M33

+10
source share

Your idea is wrong: "This should be wrong. If I take 3 angles, convert them to a matrix and convert the matrix back to angles, the result will be different from the intial values." That would be fine, but it is not necessarily so. In general, more than one triplet of Euler angles (fixed agreement) leads to the same spatial orientation. This does not mean that there is no error in your calculation. From Wikipedia: “For example, suppose we use the zyz convention above, then we have the following equivalent pairs: (90 °, 45 °, -105 °) ≡ (-270 °, -315 °, 255 °), multiples of 360 ° (72 °, 0 °, 0 °) ≡ (40 °, 0 °, 32 °) singular alignment (45 °, 60 °, -30 °) ≡ (-135 °, -60 °, 150 °) bistable flip "

+3
source share

There are a huge number of combinations of these functions, since the answer varies depending on your agreements. I usually use DirectX and the same conventions as Unity. In addition, my background is flights, space and maps, so yawing is then performed and then collapses lat / lon style matches.

Unclear conventions or inconsistent layout / decomposition functions can lead to very strange errors. It is also worth keeping in mind that multiple sets of Euler angles can create the same orientation.

Agreements (as indicated above):

  • Euler Angle: X = Pitch, Y = Yaw, Z = Roll
  • Euler order: apply rotation, yaw then step and then roll
  • Axes: + X Right, + Y Up, + Z Forward
  • Matrices: DirectX conventions (using SimpleMath.h from MS DirectXTK )

To convert to OpenGL version, see this .

I accepted Mike Tunnikliff and converted it to C ++ code and added it to my library. I hope other people save time using it.

It is worth noting that the layout function clears the 4th column and translation component from identity, and the decomposition function assumes that the 3x3 rotation element contains pure rotation (i.e., without scaling, etc.).

Firstly, the code for generating the matrix from Euler:

 //==================================================================================================== // MatrixFromYawPitchRoll // // Create matrix based on provided yaw (heading), pitch and roll (bank). // // Assumptions: // Euler: X = Pitch, Y = Yaw, Z = Roll // Applied: Yaw then pitch then roll // Axes: X = Right, Y = Up, Z = Forward // DirectX: Matrices are row major (http://www.mindcontrol.org/~hplus/graphics/matrix-layout.html) // // Code is based on Mike Tunnicliffe answer to this question: // https://stackoverflow.com/questions/1996957/conversion-euler-to-matrix-and-matrix-to-euler inline void MatrixFromYawPitchRoll( const DirectX::SimpleMath::Vector3& euler, DirectX::SimpleMath::Matrix& mat) { float cosY = cosf(euler.y); // Yaw float sinY = sinf(euler.y); float cosP = cosf(euler.x); // Pitch float sinP = sinf(euler.x); float cosR = cosf(euler.z); // Roll float sinR = sinf(euler.z); mat = DirectX::SimpleMath::Matrix::Identity; mat._11 = cosY * cosR + sinY * sinP * sinR; mat._21 = cosR * sinY * sinP - sinR * cosY; mat._31 = cosP * sinY; mat._12 = cosP * sinR; mat._22 = cosR * cosP; mat._32 = -sinP; mat._13 = sinR * cosY * sinP - sinY * cosR; mat._23 = sinY * sinR + cosR * cosY * sinP; mat._33 = cosP * cosY; } 

Then the code to return the Euler angles from the matrix:

 //==================================================================================================== // MatrixDecomposeYawPitchRoll // // Extract the rotation contained in the provided matrix as yaw (heading), pitch and roll (bank) in // radiuans. // // Assumptions: // Euler: X = Pitch, Y = Yaw, Z = Roll // Applied: Yaw then pitch then roll // Axes: X = Right, Y = Up, Z = Forward // DirectX: Matrices are row major (http://www.mindcontrol.org/~hplus/graphics/matrix-layout.html) // // Code is based on Mike Tunnicliffe answer to this question: // https://stackoverflow.com/questions/1996957/conversion-euler-to-matrix-and-matrix-to-euler inline void MatrixDecomposeYawPitchRoll( const DirectX::SimpleMath::Matrix& mat, DirectX::SimpleMath::Vector3& euler) { euler.x = asinf(-mat._32); // Pitch if (cosf(euler.x) > 0.0001) // Not at poles { euler.y = atan2f(mat._31, mat._33); // Yaw euler.z = atan2f(mat._12, mat._22); // Roll } else { euler.y = 0.0f; // Yaw euler.z = atan2f(-mat._21, mat._11); // Roll } } 
0
source share

All Articles