From 65f224ad2b1c2c0785f510f4e58ffdb8a4e1ba7e Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Thu, 27 Dec 2007 23:20:45 +0000 Subject: [PATCH] * Updated the unit tests to compile and run * Added several new methods for converting between euler angles (stored in LLVector3), quaternions and matrices. Most of the new methods are commented out as the math is currently buggy and needs more unit testing to fix git-svn-id: http://libopenmetaverse.googlecode.com/svn/trunk@1568 52acb1d6-8a22-11de-b505-999d5b087335 --- libsecondlife/Types.cs | 154 ++++++++++++++---- .../libsecondlife.Tests/PrimObjectTests.cs | 90 ++-------- .../libsecondlife.Tests/TypeTests.cs | 8 +- 3 files changed, 141 insertions(+), 111 deletions(-) diff --git a/libsecondlife/Types.cs b/libsecondlife/Types.cs index be1bc419..b0e44652 100644 --- a/libsecondlife/Types.cs +++ b/libsecondlife/Types.cs @@ -653,28 +653,22 @@ namespace libsecondlife this = LLVector3.Zero; } + //FIXME: Need comprehensive testing for this /// /// Assumes this vector represents euler rotations along the X, Y, and /// Z axis and creates a quaternion representation of the rotations /// /// A quaternion representation of the euler rotations - public LLQuaternion ToRotation() - { - LLVector3 vec = this; + //public LLQuaternion ToQuaternion() + //{ + // LLMatrix3 rotMat = new LLMatrix3(X, Y, Z); + // rotMat = LLMatrix3.Orthogonalize(rotMat); - if (vec.X > Helpers.PI) vec.X -= Helpers.TWO_PI; - if (vec.Y > Helpers.PI) vec.Y -= Helpers.TWO_PI; - if (vec.Z > Helpers.PI) vec.Z -= Helpers.TWO_PI; + // LLQuaternion quat = rotMat.ToQuaternion(); + // quat = LLQuaternion.Norm(quat); - if (vec.X < -Helpers.PI) vec.X += Helpers.TWO_PI; - if (vec.Y < -Helpers.PI) vec.Y += Helpers.TWO_PI; - if (vec.Z < -Helpers.PI) vec.Z += Helpers.TWO_PI; - - LLQuaternion rot = new LLQuaternion(X, Y, Z, 1f); - if (vec.Z > Helpers.PI) rot.W = 0f; - - return rot; - } + // return quat; + //} #endregion Public Methods @@ -777,6 +771,16 @@ namespace libsecondlife (float)Math.Cos(angle / 2)); } + public static LLVector3 Transform(LLVector3 vector, LLMatrix3 matrix) + { + // Operates "from the right" on row vector + return new LLVector3( + vector.X * matrix.M11 + vector.Y * matrix.M21 + vector.Z * matrix.M31, + vector.X * matrix.M12 + vector.Y * matrix.M22 + vector.Z * matrix.M32, + vector.X * matrix.M13 + vector.Y * matrix.M23 + vector.Z * matrix.M33 + ); + } + /// /// Generate an LLVector3 from a string /// @@ -896,6 +900,11 @@ namespace libsecondlife return new LLVector3(nx, ny, nz); } + public static LLVector3 operator *(LLVector3 vector, LLMatrix3 matrix) + { + return LLVector3.Transform(vector, matrix); + } + #endregion Operators /// An LLVector3 with a value of 0,0,0 @@ -1827,13 +1836,15 @@ namespace libsecondlife this = LLQuaternion.Identity; } - public void GetEulerAngles(out float roll, out float pitch, out float yaw) - { - LLMatrix3 rotMat = new LLMatrix3(this); - rotMat = LLMatrix3.Orthogonalize(rotMat); - rotMat.GetEulerAngles(out roll, out pitch, out yaw); - } + //FIXME: Need comprehensive testing for this + //public void GetEulerAngles(out float roll, out float pitch, out float yaw) + //{ + // LLMatrix3 rotMat = new LLMatrix3(this); + // rotMat = LLMatrix3.Orthogonalize(rotMat); + // rotMat.GetEulerAngles(out roll, out pitch, out yaw); + //} + //FIXME: Need comprehensive testing for this /// /// Returns the inverse matrix from a quaternion, or the correct /// matrix if the quaternion is inverse @@ -2082,10 +2093,44 @@ namespace libsecondlife this = q.ToMatrix(); } + //FIXME: + //public LLMatrix3(float roll, float pitch, float yaw) + //{ + // M11 = M12 = M13 = M21 = M22 = M23 = M31 = M32 = M33 = 0f; + // FromEulers(roll, pitch, yaw); + //} + #endregion Constructors #region Public Methods + // FIXME: Need comprehensive testing for this + //public void FromEulers(float roll, float pitch, float yaw) + //{ + // float cx, sx, cy, sy, cz, sz; + // float cxsy, sxsy; + + // cx = (float)Math.Cos(roll); + // sx = (float)Math.Sin(roll); + // cy = (float)Math.Cos(pitch); + // sy = (float)Math.Sin(pitch); + // cz = (float)Math.Cos(yaw); + // sz = (float)Math.Sin(yaw); + + // cxsy = cx * sy; + // sxsy = sx * sy; + + // M11 = cy * cz; + // M21 = -cy * sz; + // M31 = sy; + // M12 = sxsy * cz + cx * sz; + // M22 = -sxsy * sz + cx * cz; + // M32 = -sx * cy; + // M13 = -cxsy * cz + sx * sz; + // M23 = cxsy * sz + sx * cz; + // M33 = cx * cy; + //} + public void GetEulerAngles(out float roll, out float pitch, out float yaw) { // From the Matrix and Quaternion FAQ: http://www.j3d.org/matrix_faq/matrfaq_latest.html @@ -2126,6 +2171,58 @@ namespace libsecondlife yaw = (float)angleZ; } + public LLQuaternion ToQuaternion() + { + LLQuaternion quat = new LLQuaternion(); + float tr, s; + float[] q = new float[4]; + int i, j, k; + int[] nxt = new int[] { 1, 2, 0 }; + + tr = this[0, 0] + this[1, 1] + this[2, 2]; + + // Check the diagonal + if (tr > 0f) + { + s = (float)Math.Sqrt(tr + 1f); + quat.W = s / 2f; + + s = 0.5f / s; + quat.X = (this[1, 2] - this[2, 1]) * s; + quat.Y = (this[2, 0] - this[0, 2]) * s; + quat.Z = (this[0, 1] - this[1, 0]) * s; + } + else + { + // Diagonal is negative + i = 0; + if (this[1, 1] > this[0, 0]) + i = 1; + if (this[2, 2] > this[i, i]) + i = 2; + + j = nxt[i]; + k = nxt[j]; + + s = (float)Math.Sqrt((this[i, i] - (this[j, j] + this[k, k])) + 1f); + q[i] = s * 0.5f; + + if (s != 0f) + s = 0.5f / s; + + q[3] = (this[j, k] - this[k, j]) * s; + q[j] = (this[i, j] + this[j, i]) * s; + q[k] = (this[i, k] + this[k, i]) * s; + + quat.X = q[0]; + quat.Y = q[1]; + quat.Z = q[2]; + quat.W = q[3]; + } + + return quat; + } + #endregion Public Methods #region Static Methods @@ -2183,16 +2280,6 @@ namespace libsecondlife ); } - public static LLVector3 Transform(LLVector3 vector, LLMatrix3 matrix) - { - // Operates "from the right" on row vector - return new LLVector3( - vector.X * matrix.M11 + vector.Y * matrix.M21 + vector.Z * matrix.M31, - vector.X * matrix.M12 + vector.Y * matrix.M22 + vector.Z * matrix.M32, - vector.X * matrix.M13 + vector.Y * matrix.M23 + vector.Z * matrix.M33 - ); - } - /// /// Transposes a matrix /// @@ -2300,11 +2387,6 @@ namespace libsecondlife return LLMatrix3.Multiply(left, right); ; } - public static LLVector3 operator *(LLVector3 vector, LLMatrix3 matrix) - { - return LLMatrix3.Transform(vector, matrix); - } - public LLVector3 this[int row] { get diff --git a/libsecondlife/libsecondlife.Tests/PrimObjectTests.cs b/libsecondlife/libsecondlife.Tests/PrimObjectTests.cs index 1c8c12c2..afdc4278 100644 --- a/libsecondlife/libsecondlife.Tests/PrimObjectTests.cs +++ b/libsecondlife/libsecondlife.Tests/PrimObjectTests.cs @@ -15,11 +15,11 @@ namespace libsecondlife.Tests { for (byte i = 0; i < byte.MaxValue; i++) { - float floatValue = LLObject.PathBeginFloat(i); - ushort result = LLObject.PathBeginUInt16(floatValue); + float floatValue = LLObject.UnpackBeginCut(i); + ushort result = LLObject.PackBeginCut(floatValue); Assert.IsTrue(result == i, "Started with " + i + ", float value was " + floatValue + - ", and ended up with " + result); + ", and ended up with " + result); } } @@ -28,24 +28,11 @@ namespace libsecondlife.Tests { for (byte i = 0; i < byte.MaxValue; i++) { - float floatValue = LLObject.PathEndFloat(i); - ushort result = LLObject.PathEndUInt16(floatValue); + float floatValue = LLObject.UnpackEndCut(i); + ushort result = LLObject.PackEndCut(floatValue); Assert.IsTrue(result == i, "Started with " + i + ", float value was " + floatValue + - ", and ended up with " + result); - } - } - - [Test] - public void PathRadiusOffset() - { - for (sbyte i = sbyte.MinValue; i < sbyte.MaxValue; i++) - { - float floatValue = LLObject.PathRadiusOffsetFloat(i); - sbyte result = LLObject.PathRadiusOffsetByte(floatValue); - - Assert.IsTrue(result == i, "Started with " + i + ", float value was " + floatValue + - ", and ended up with " + result); + ", and ended up with " + result); } } @@ -54,11 +41,11 @@ namespace libsecondlife.Tests { for (byte i = 0; i < byte.MaxValue; i++) { - float floatValue = LLObject.PathRevolutionsFloat(i); - byte result = LLObject.PathRevolutionsByte(floatValue); + float floatValue = LLObject.UnpackPathRevolutions(i); + byte result = LLObject.PackPathRevolutions(floatValue); Assert.IsTrue(result == i, "Started with " + i + ", float value was " + floatValue + - ", and ended up with " + result); + ", and ended up with " + result); } } @@ -67,11 +54,11 @@ namespace libsecondlife.Tests { for (byte i = 0; i < byte.MaxValue; i++) { - float floatValue = LLObject.PathScaleFloat(i); - byte result = LLObject.PathScaleByte(floatValue); + float floatValue = LLObject.UnpackPathScale(i); + byte result = LLObject.PackPathScale(floatValue); Assert.IsTrue(result == i, "Started with " + i + ", float value was " + floatValue + - ", and ended up with " + result); + ", and ended up with " + result); } } @@ -80,21 +67,8 @@ namespace libsecondlife.Tests { for (byte i = 0; i < byte.MaxValue; i++) { - float floatValue = LLObject.PathShearFloat(i); - byte result = LLObject.PathShearByte(floatValue); - - Assert.IsTrue(result == i, "Started with " + i + ", float value was " + floatValue + - ", and ended up with " + result); - } - } - - [Test] - public void PathSkew() - { - for (sbyte i = sbyte.MinValue; i < sbyte.MaxValue; i++) - { - float floatValue = LLObject.PathSkewFloat(i); - sbyte result = LLObject.PathSkewByte(floatValue); + float floatValue = LLObject.UnpackPathShear(i); + byte result = LLObject.PackPathShear(floatValue); Assert.IsTrue(result == i, "Started with " + i + ", float value was " + floatValue + ", and ended up with " + result); @@ -106,34 +80,8 @@ namespace libsecondlife.Tests { for (sbyte i = sbyte.MinValue; i < sbyte.MaxValue; i++) { - float floatValue = LLObject.PathTaperFloat(i); - sbyte result = LLObject.PathTaperByte(floatValue); - - Assert.IsTrue(result == i, "Started with " + i + ", float value was " + floatValue + - ", and ended up with " + result); - } - } - - [Test] - public void ProfileBegin() - { - for (byte i = 0; i < byte.MaxValue; i++) - { - float floatValue = LLObject.ProfileBeginFloat(i); - ushort result = LLObject.ProfileBeginUInt16(floatValue); - - Assert.IsTrue(result == i, "Started with " + i + ", float value was " + floatValue + - ", and ended up with " + result); - } - } - - [Test] - public void ProfileEnd() - { - for (byte i = 0; i < byte.MaxValue; i++) - { - float floatValue = LLObject.ProfileEndFloat(i); - ushort result = LLObject.ProfileEndUInt16(floatValue); + float floatValue = LLObject.UnpackPathTaper(i); + sbyte result = LLObject.PackPathTaper(floatValue); Assert.IsTrue(result == i, "Started with " + i + ", float value was " + floatValue + ", and ended up with " + result); @@ -155,12 +103,6 @@ namespace libsecondlife.Tests } } - //[Test] - //public void TextureEntryRotations() - //{ - // ; - //} - [Test] public void TextureEntry() { diff --git a/libsecondlife/libsecondlife.Tests/TypeTests.cs b/libsecondlife/libsecondlife.Tests/TypeTests.cs index e721fe9c..c82ee75a 100644 --- a/libsecondlife/libsecondlife.Tests/TypeTests.cs +++ b/libsecondlife/libsecondlife.Tests/TypeTests.cs @@ -84,7 +84,13 @@ namespace libsecondlife.Tests [Test] public void VectorQuaternionMath() { - ; + // Convert a vector to a quaternion and back + LLVector3 a = new LLVector3(1f, 0.5f, 0.75f); + LLQuaternion b = a.ToQuaternion(); + LLVector3 c; + b.GetEulerAngles(out c.X, out c.Y, out c.Z); + + Assert.IsTrue(a == c, c.ToString() + " does not equal " + a.ToString()); } [Test]