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]