[Connect C#] Bug with YPRAngles.FromNormalizedMatrix(DMatrix3d)

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 -> 179
180.0 -> 0
181.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;
    }

  • Output:
    179.0 -> 179
    180.0 -> 0
    181.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

  • There seems to be an issue with YPRAngles

    , 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.

     
    Regards, Jon Summers
    LA Solutions