* 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
This commit is contained in:
John Hurliman
2007-12-27 23:20:45 +00:00
parent adae01ab87
commit 65f224ad2b
3 changed files with 141 additions and 111 deletions

View File

@@ -653,28 +653,22 @@ namespace libsecondlife
this = LLVector3.Zero;
}
//FIXME: Need comprehensive testing for this
/// <summary>
/// Assumes this vector represents euler rotations along the X, Y, and
/// Z axis and creates a quaternion representation of the rotations
/// </summary>
/// <returns>A quaternion representation of the euler rotations</returns>
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
);
}
/// <summary>
/// Generate an LLVector3 from a string
/// </summary>
@@ -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
/// <summary>An LLVector3 with a value of 0,0,0</summary>
@@ -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
/// <summary>
/// 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
);
}
/// <summary>
/// Transposes a matrix
/// </summary>
@@ -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

View File

@@ -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()
{

View File

@@ -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]