In testing the Eigen/EulerAngles implementation I have shown that I create a matrix and go Matrix > Angles > Matrix but I cannot successfully go Angles > Matrix > Angles for any matrix other than the identity matrix. Example code // Hand-Craft, ANG > MAT > ANG // first quad inputAngles << 0, 0, M_PI/4; outputMatrix.block<3,3>(0, 0) = (Eigen::AngleAxisf(inputAngles[0], Eigen::Vector3f::UnitZ()) * Eigen::AngleAxisf(inputAngles[1], Eigen::Vector3f::UnitX()) * Eigen::AngleAxisf(inputAngles[2], Eigen::Vector3f::UnitZ())).toRotationMatrix(); outputAngles = inputMat.block<3,3>(0,0).eulerAngles(2, 0, 2); // follows Z-X-Z with output inputAngles == [0.78539819, 0.78539819, 0.78539819] pi/4, pi/4, pi/4 outputAngles == [-2.3561945, -0.78539824, -2.3561945] -3pi/4, -pi/4, -3pi/4 See this thread for more (http://forum.kde.org/viewtopic.php?f=74&t=111436&p=266230#p266230) Obviously Euler angles have lots of different conventions -- if the Eigen documentation gave a very thorough walk through for one convention it would be very helpful. Also what the expected domain/range of the three euler angles is would be handy without having to dig through the source code. Finally it is posited here (https://d3cw3dd2w32x2b.cloudfront.net/wp-content/uploads/2012/07/euler-angles.pdf) that according to the Graphics Gems IV method (which, according to the Eigen source code is in use) it is possible to avoid floating point instability by slightly modifying the generation method of the third coefficient
Here is an updated code example including variable definitions. The original code example got a little mushed in copy and paste. Eigen::Matrix4f inputMat; Eigen::Matrix4f outputMat; Eigen::Array3d inputAngles; Eigen::Array3d outputAngles; inputMat = outputMat = Eigen::Matrix4f::Identity(); // Hand-Craft, ANG > MAT > ANG // first quad inputAngles << M_PI/4, M_PI/4, M_PI/4; outputMatrix.block<3,3>(0, 0) = (Eigen::AngleAxisf(inputAngles[0], Eigen::Vector3f::UnitZ()) * Eigen::AngleAxisf(inputAngles[1], Eigen::Vector3f::UnitX()) * Eigen::AngleAxisf(inputAngles[2], Eigen::Vector3f::UnitZ())).toRotationMatrix(); outputAngles = outputMatrix.block<3,3>(0,0).eulerAngles(2, 0, 2); // follows Z-X-Z
Created attachment 342 [details] Avoid if statement and improve consistency of eulerAngles method Here is a patch implementing the approach of linked pdf. The return angles are guaranteed to be in the range [0:pi]x[0:pi]x[-pi:pi]. Implementation-wise this is much simpler and faster this way than starting with a wider [-pi:pi] range.
This looks great. Thanks a lot for your time on this wonderful project.
https://bitbucket.org/eigen/eigen/commits/b12526cb05c9/ Changeset: b12526cb05c9 User: ggael Date: 2013-06-09 23:14:45 Summary: Fix bug 609: avoid if statement and improve consistency of eulerAngles method
I need to re-open this. Not having success with all test cases. All of the hand constructed matricies are checked with the following code (written here for brevity). Matricies are hand crafted for a right-hand system, although the determinant is still checked for safety. The following test cases do not work and I've follow-copies the input/output for inspection. Eigen::Matrix4f inputMat, outputMat; Eigen::Array3d inputAngles; inputMat = Eigen::Matrix4f::Identity(); outputMat = inputMat; // MAT > ANG > MAT inputMat.block<3,1>(0,0) << 0,1,0; inputMat.block<3,1>(0,1) << -1,0,0; inputMat.block<3,1>(0,2) << 0,0,1; if( inputMat.determinant() != 1 ) { // flip from LH to RH inputMat.block<3,1>(0,2) *= -1; } outputMat = inputMat; inputAngles = inputMat.block<3,3>(0,0).cast<double>().eulerAngles(2, 0, 2); // follows Z-X-Z outputMat.block<3,3>(0, 0) = (Eigen::AngleAxisd(inputAngles[0], Eigen::Vector3d::UnitZ()) * Eigen::AngleAxisd(inputAngles[1], Eigen::Vector3d::UnitX()) * Eigen::AngleAxisd(inputAngles[2], Eigen::Vector3d::UnitZ())).toRotationMatrix().cast<float>(); // Gives 0 -1 0 0 1 0 0 0 0 0 1 0 0 0 0 1 -0.846852 -0.531829 0 0 0.107965 -0.171917 0.979177 0 -0.520755 0.829218 0.203007 0 0 0 0 1 // Hand-Craft, MAT > ANG > MAT inputMat.block<3,1>(0,0) << 0,-1,0; inputMat.block<3,1>(0,1) << 1,0,0; inputMat.block<3,1>(0,2) << 0,0,1; // Gives 0 1 0 0 -1 0 0 0 0 0 1 0 0 0 0 1 2.22045e-016 1.57009e-016 -1 0 1.57009e-016 1 1.57009e-016 0 1 -1.57009e-016 2.22045e-016 0 0 0 0 1 // Hand-Craft, MAT > ANG > MAT inputMat.block<3,1>(0,0) << 0,-1,0; inputMat.block<3,1>(0,1) << -1,0,0; inputMat.block<3,1>(0,2) << 0,0,-1; // Gives 0 -1 0 0 -1 0 0 0 0 0 -1 0 0 0 0 1 -2.22045e-016 -1.57009e-016 1 0 1.57009e-016 -1 -1.57009e-016 0 1 1.57009e-016 2.22045e-016 0 0 0 0 1 Here are two examples in reverse, checked with the following code, which also aren't working inputMat = outputMat = Eigen::Matrix4f::Identity(); // Hand-Craft, ANG > MAT > ANG // first quad inputAngles << 0, 0, 0; outputMat.block<3,3>(0, 0) = (Eigen::AngleAxisd(inputAngles[0], Eigen::Vector3d::UnitZ()) * Eigen::AngleAxisd(inputAngles[1], Eigen::Vector3d::UnitX()) * Eigen::AngleAxisd(inputAngles[2], Eigen::Vector3d::UnitZ())).toRotationMatrix().cast<float>(); outputAngles = outputMat.block<3,3>(0,0).cast<double>().eulerAngles(2, 0, 2); // follows Z-X-Z // Gives 0 0 0 1.5708 1.5708 1.5708 // Hand-Craft, ANG > MAT > ANG inputAngles << M_PI/4, 0, 0; // Gives 0.785398 0 0 1.5708 1.5708 1.5708
Created attachment 360 [details] self-contained test case Works for me with the attached self-contained example. It works both with double and float. Remark that with the Z-X-Z convention, if the second angle (around X) is zero then the Euler angles are not uniquely defined. As I already explained, we always pick the one with the first angle equal to zero.
I got everything working. Thanks again.
(In reply to comment #2) > Created attachment 342 [details] [review] > Avoid if statement and improve consistency of eulerAngles method > > Here is a patch implementing the approach of linked pdf. The return angles are > guaranteed to be in the range [0:pi]x[0:pi]x[-pi:pi]. Implementation-wise this > is much simpler and faster this way than starting with a wider [-pi:pi] range. Based on a specific example and studying the math again, it appears the second angle can be -pi:pi, not 0:pi as listed now in the docs. EulerAngle.h lines 60 and 65 seem to allow for values 0:-pi and 0:pi respectively. For example, this matrix evaluates to a second angle which is slightly less than -pi/2 (using Z-X-Z convention) -0.0619354 -0.018203 -0.997914 0 -0.99757 -0.0308364 0.0624764 0 -0.0319091 0.999359 -0.0162488 0 0 0 0 1 Is this a bug in the docs or the angle code? Thanks
This seems to have been a bug in the docs. I fixed the doc and extended the unit test (in default and 3.2): http://bitbucket.org/eigen/eigen/commits/42e0115 http://bitbucket.org/eigen/eigen/commits/4a867dd
-- GitLab Migration Automatic Message -- This bug has been migrated to gitlab.com's GitLab instance and has been closed from further activity. You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.com/libeigen/eigen/issues/609.