/// <summary> /// Get the FRotator representation of this Quaternion. /// </summary> public FRotator Rotator() { DiagnosticCheckNaN(); float singularityTest = Z * X - W * Y; float yawY = 2.0f * (W * Z + X * Y); float yawX = (1.0f - 2.0f * (FMath.Square(Y) + FMath.Square(Z))); // reference // http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/ // this value was found from experience, the above websites recommend different values // but that isn't the case for us, so I went through different testing, and finally found the case // where both of world lives happily. const float singularityThreshold = 0.4999995f; const float radToDeg = (180.0f) / FMath.PI; FRotator rotatorFromQuat; if (singularityTest < -singularityThreshold) { rotatorFromQuat.Pitch = -90.0f; rotatorFromQuat.Yaw = FMath.Atan2(yawY, yawX) * radToDeg; rotatorFromQuat.Roll = FRotator.NormalizeAxis(-rotatorFromQuat.Yaw - (2.0f * FMath.Atan2(X, W) * radToDeg)); } else if (singularityTest > singularityThreshold) { rotatorFromQuat.Pitch = 90.0f; rotatorFromQuat.Yaw = FMath.Atan2(yawY, yawX) * radToDeg; rotatorFromQuat.Roll = FRotator.NormalizeAxis(rotatorFromQuat.Yaw - (2.0f * FMath.Atan2(X, W) * radToDeg)); } else { rotatorFromQuat.Pitch = FMath.FastAsin(2.0f * (singularityTest)) * radToDeg; rotatorFromQuat.Yaw = FMath.Atan2(yawY, yawX) * radToDeg; rotatorFromQuat.Roll = FMath.Atan2(-2.0f * (W * X + Y * Z), (1.0f - 2.0f * (FMath.Square(X) + FMath.Square(Y)))) * radToDeg; } rotatorFromQuat.DiagnosticCheckNaN("FQuat::Rotator(): Rotator result " + rotatorFromQuat + " contains NaN! Quat = " + this.ToString() + ", YawY = " + yawY + ", YawX = " + yawX); return(rotatorFromQuat); }