There seems to be an issue with YPRAngles.FromNormalizedMatrix when the DMatrix3d is rotated exactly 180 degrees around Z.
DMatrix3d test1 = DMatrix3d.Rotation(2, Angle.FromDegrees(179.0)); System.Diagnostics.Debug.Print("179.0 -> " + YPRAngles.FromNormalizedMatrix(test1).Yaw.Degrees); DMatrix3d test2 = DMatrix3d.Rotation(2, Angle.FromDegrees(180.0)); System.Diagnostics.Debug.Print("180.0 -> " + YPRAngles.FromNormalizedMatrix(test2).Yaw.Degrees); DMatrix3d test3 = DMatrix3d.Rotation(2, Angle.FromDegrees(181.0)); System.Diagnostics.Debug.Print("181.0 -> " + YPRAngles.FromNormalizedMatrix(test3).Yaw.Degrees);
Output: 179.0 -> 179180.0 -> 0181.0 -> -179
I believe this has to do with the final check within the FromNormalizedMatrix static function. This should probably be a <= rather than a <
// Assembly location: C:\Program Files\Bentley\MicroStation CONNECT Edition\MicroStation\Bentley.GeometryNET.Structs.dll public static YPRAngles FromNormalizedMatrix(DMatrix3d matrix) { double coffzx = matrix.coffzx; double x = Math.Sqrt(matrix.coffzy * matrix.coffzy + matrix.coffzz * matrix.coffzz); Angle pitch1 = Angle.Atan2(coffzx, x); Angle pitch2 = Angle.Atan2(coffzx, -x); if (x < Geometry.SmallAngle) return new YPRAngles(Angle.Atan2(-matrix.coffxy, matrix.coffyy), pitch1, Angle.Zero); Angle yaw1 = Angle.Atan2(matrix.coffyx, matrix.coffxx); Angle roll1 = Angle.Atan2(matrix.coffzy, matrix.coffzz); Angle yaw2 = Angle.Atan2(-matrix.coffyx, -matrix.coffxx); Angle roll2 = Angle.Atan2(-matrix.coffzy, -matrix.coffzz); YPRAngles yprAngles1 = new YPRAngles(yaw1, pitch1, roll1); YPRAngles yprAngles2 = new YPRAngles(yaw2, pitch2, roll2); return yprAngles1.MaxAbsRadians() < yprAngles2.MaxAbsRadians() ? yprAngles1 : yprAngles2; }
Maury said:Output: 179.0 -> 179180.0 -> 0181.0 -> -179
I rewrote your code using C++ and got this result...
CMessageTracer msg (__FUNCTION__); YawPitchRollAngles ypr179; RotMatrix matrix179; matrix179.InitIdentity (); matrix179.InitFromPrincipleAxisRotations (matrix179, 0.0, 0.0, Angle::FromDegrees(179.0).Radians()); if (YawPitchRollAngles::TryFromRotMatrix (ypr179, matrix179)) { msg = L"179°= "; msg.AppendDbl ((double)ypr179.GetYaw().Degrees()); msg.Output (); } YawPitchRollAngles ypr180; RotMatrix matrix180; matrix180.InitIdentity (); matrix180.InitFromPrincipleAxisRotations (matrix180, 0.0, 0.0, Angle::FromDegrees(180.0).Radians()); if (YawPitchRollAngles::TryFromRotMatrix (ypr180, matrix180)) { msg = L"180°= "; msg.AppendDbl ((double)ypr180.GetYaw().Degrees()); msg.Output (); } YawPitchRollAngles ypr181; RotMatrix matrix181; matrix181.InitIdentity (); matrix181.InitFromPrincipleAxisRotations (matrix181, 0.0, 0.0, Angle::FromDegrees(181.0).Radians()); if (YawPitchRollAngles::TryFromRotMatrix (ypr181, matrix181)) { msg = L"181°= "; msg.AppendDbl ((double)ypr181.GetYaw().Degrees()); msg.Output (); }
Result:
181°= -179.00 180°= 180.00 179°= 179.00
Regards, Jon Summers LA Solutions
Thanks for doing that. That is the results I would expect from the DgnPlatformNET API
Maury said:There seems to be an issue with YPRAngles
Robert Hook, this is a reproducible bug. YPR angles implemented in .NET gives a different result to YPR angles implemented in C++.
Apparently the C# function is written in C#, rather than calling P/Invoke on the C++ implementation.