* 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:
@@ -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
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user