Kryzon from the BlitzBasic.com forum (dead link) helped me out here:
internal static class QuaternionExtensions
{
internal static Vector3 GetYawPitchRollVector(this Quaternion q)
{
return new Vector3(q.GetYaw(), q.GetPitch(), q.GetRoll());
}
private static float GetYaw(this Quaternion q)
{
float x2 = q.X * q.X;
float y2 = q.Y * q.Y;
return (float)Math.Atan2(2f * q.Y * q.W - 2f * q.Z * q.X, 1f - 2f * y2 - 2f * x2);
}
private static float GetPitch(this Quaternion q)
{
return (float)-Math.Asin(2f * q.Z * q.Y + 2f * q.X * q.W);
}
private static float GetRoll(this Quaternion q)
{
float x2 = q.X * q.X;
float z2 = q.Z * q.Z;
return (float)-Math.Atan2(2f * q.Z * q.W - 2f * q.Y * q.X, 1f - 2f * z2 - 2f * x2);
}
}
internal static class Vector3Extensions
{
internal static Quaternion GetYawPitchRollQuaternion(this Vector3 v)
{
float c1 = (float)Math.Cos(-v.Z / 2.0);
float c2 = (float)Math.Cos(-v.Y / 2.0);
float c3 = (float)Math.Cos( v.X / 2.0);
float c1c2 = c1 * c2;
float s1 = (float)Math.Sin(-v.Z / 2.0);
float s2 = (float)Math.Sin(-v.Y / 2.0);
float s3 = (float)Math.Sin( v.X / 2.0);
float s1s2 = s1 * s2;
return new Quaternion(
c1 * s2 * c3 - s1 * c2 * s3,
c1c2 * s3 + s1s2 * c3,
s1 * c2 * c3 + c1 * s2 * s3,
c1c2 * c3 - s1s2 * s3);
}
}