diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 5bfd8e10e2..856cac3fbc 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -47,7 +47,12 @@ namespace OpenSim.Framework private static Dictionary capsURLS = new Dictionary(); #region Vector Equasions - + /// + /// Get the distance between two 3d vectors + /// + /// A 3d vector + /// A 3d vector + /// The distance between the two vectors public static double GetDistanceTo(LLVector3 a, LLVector3 b) { float dx = a.X - b.X; @@ -55,14 +60,43 @@ namespace OpenSim.Framework float dz = a.Z - b.Z; return Math.Sqrt(dx*dx + dy*dy + dz*dz); } + + /// + /// Get the magnitude of a 3d vector + /// + /// A 3d vector + /// The magnitude of the vector public static double GetMagnitude(LLVector3 a) { return Math.Sqrt((a.X * a.X) + (a.Y * a.Y) + (a.Z * a.Z)); } - public static LLVector3 GetNormal(LLVector3 a) + + /// + /// Get a normalized form of a 3d vector + /// + /// A 3d vector + /// A new vector which is normalized form of the vector + /// The vector paramater cannot be <0,0,0> + public static LLVector3 GetNormalizedVector(LLVector3 a) { + if (IsZeroVector(a)) + throw new ArgumentException("Vector paramater cannot be a zero vector."); + float Mag = (float)GetMagnitude(a); return new LLVector3(a.X / Mag, a.Y / Mag, a.Z / Mag); + } + /// + /// Returns if a vector is a zero vector (has all zero components) + /// + /// + public static bool IsZeroVector( LLVector3 v ) + { + if( v.X == 0 && v.Y == 0 && v.Z == 0) + { + return true; + } + + return false; } # endregion diff --git a/OpenSim/Tests/Common/ANumericalToleranceConstraint.cs b/OpenSim/Tests/Common/ANumericalToleranceConstraint.cs new file mode 100644 index 0000000000..289e4bbb7a --- /dev/null +++ b/OpenSim/Tests/Common/ANumericalToleranceConstraint.cs @@ -0,0 +1,30 @@ +using System; +using NUnit.Framework.Constraints; + +namespace OpenSim.Tests.Common +{ + public abstract class ANumericalToleranceConstraint : Constraint + { + protected double _tolerance; + + public ANumericalToleranceConstraint(double tolerance) + { + if (tolerance < 0) + { + throw new ArgumentException("Tolerance cannot be negative."); + } + _tolerance = tolerance; + } + + + protected bool IsWithinDoubleConstraint(double doubleValue, double baseValue) + { + if (doubleValue >= baseValue - _tolerance && doubleValue <= baseValue + _tolerance) + { + return true; + } + + return false; + } + } +} diff --git a/OpenSim/Tests/Common/DoubleToleranceConstraint.cs b/OpenSim/Tests/Common/DoubleToleranceConstraint.cs new file mode 100644 index 0000000000..f3da236c6c --- /dev/null +++ b/OpenSim/Tests/Common/DoubleToleranceConstraint.cs @@ -0,0 +1,52 @@ +using System; +using NUnit.Framework; +using NUnit.Framework.Constraints; +using OpenSim.Tests.Common; + +namespace OpenSim.Tests.Common +{ + public class DoubleToleranceConstraint : ANumericalToleranceConstraint + { + + private double _baseValue; + private double _valueToBeTested; + + public DoubleToleranceConstraint(double baseValue, double tolerance) : base(tolerance) + { + _baseValue = baseValue; + } + + /// + ///Test whether the constraint is satisfied by a given value + /// + ///The value to be tested + /// + ///True for success, false for failure + /// + public override bool Matches(object valueToBeTested) + { + if (valueToBeTested == null) + { + throw new ArgumentException("Constraint cannot be used upon null values."); + } + if( valueToBeTested.GetType() != typeof(double)) + { + throw new ArgumentException("Constraint cannot be used upon non double-values."); + } + + _valueToBeTested = (double)valueToBeTested; + + return IsWithinDoubleConstraint(_valueToBeTested, _baseValue ); + } + + public override void WriteDescriptionTo(MessageWriter writer) + { + writer.WriteExpectedValue(string.Format("A value {0} within tolerance of plus or minus {1}",_baseValue,_tolerance)); + } + + public override void WriteActualValueTo(MessageWriter writer) + { + writer.WriteActualValue(_valueToBeTested); + } + } +} diff --git a/OpenSim/Tests/Common/TestHelper.cs b/OpenSim/Tests/Common/TestHelper.cs new file mode 100644 index 0000000000..f59c1575c0 --- /dev/null +++ b/OpenSim/Tests/Common/TestHelper.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenSim.Tests.Common +{ + public delegate void TestDelegate(); + + public class TestHelper + { + public static bool AssertThisDelegateCausesArgumentException(TestDelegate d) + { + try + { + d(); + } + catch(ArgumentException e) + { + return true; + } + + return false; + } + } +} diff --git a/OpenSim/Tests/Common/VectorToleranceConstraint.cs b/OpenSim/Tests/Common/VectorToleranceConstraint.cs new file mode 100644 index 0000000000..1faf7dd5f1 --- /dev/null +++ b/OpenSim/Tests/Common/VectorToleranceConstraint.cs @@ -0,0 +1,58 @@ +using System; +using libsecondlife; +using NUnit.Framework; + +namespace OpenSim.Tests.Common +{ + public class VectorToleranceConstraint : ANumericalToleranceConstraint + { + private LLVector3 _baseValue; + private LLVector3 _valueToBeTested; + + public VectorToleranceConstraint(LLVector3 baseValue, double tolerance) : base(tolerance) + { + _baseValue = baseValue; + } + + /// + ///Test whether the constraint is satisfied by a given value + /// + ///The value to be tested + /// + ///True for success, false for failure + /// + public override bool Matches(object valueToBeTested) + { + if (valueToBeTested == null) + { + throw new ArgumentException("Constraint cannot be used upon null values."); + } + if (valueToBeTested.GetType() != typeof (LLVector3)) + { + throw new ArgumentException("Constraint cannot be used upon non vector values."); + } + + _valueToBeTested = (LLVector3) valueToBeTested; + + if ( IsWithinDoubleConstraint(_valueToBeTested.X,_baseValue.X) && + IsWithinDoubleConstraint(_valueToBeTested.Y,_baseValue.Y) && + IsWithinDoubleConstraint(_valueToBeTested.Z,_baseValue.Z) ) + { + return true; + } + + return false; + } + + public override void WriteDescriptionTo(MessageWriter writer) + { + writer.WriteExpectedValue( + string.Format("A value {0} within tolerance of plus or minus {1}", _baseValue, _tolerance)); + } + + public override void WriteActualValueTo(MessageWriter writer) + { + writer.WriteActualValue(_valueToBeTested); + } + } +} diff --git a/OpenSim/Tests/OpenSim/Framework/UtilTest.cs b/OpenSim/Tests/OpenSim/Framework/UtilTest.cs new file mode 100644 index 0000000000..ef42eeed50 --- /dev/null +++ b/OpenSim/Tests/OpenSim/Framework/UtilTest.cs @@ -0,0 +1,115 @@ +using libsecondlife; +using NUnit.Framework; +using NUnit.Framework.SyntaxHelpers; + +using OpenSim.Tests.Common; + +namespace OpenSim.Framework.Tests +{ + [TestFixture] + public class UtilTests + { + [Test] + public void VectorOperationTests() + { + LLVector3 v1, v2; + double expectedDistance; + double expectedMagnitude; + double lowPrecisionTolerance = 0.001; + + //Lets test a simple case of <0,0,0> and <5,5,5> + { + v1 = new LLVector3(0, 0, 0); + v2 = new LLVector3(5, 5, 5); + expectedDistance = 8.66; + Assert.That(Util.GetDistanceTo(v1, v2), + new DoubleToleranceConstraint(expectedDistance, lowPrecisionTolerance), + "Calculated distance between two vectors was not within tolerances."); + + expectedMagnitude = 0; + Assert.That(Util.GetMagnitude(v1), Is.EqualTo(0), "Magnitude of null vector was not zero."); + + expectedMagnitude = 8.66; + Assert.That(Util.GetMagnitude(v2), + new DoubleToleranceConstraint(expectedMagnitude, lowPrecisionTolerance), + "Magnitude of vector was incorrect."); + + TestDelegate d = delegate() { Util.GetNormalizedVector(v1); }; + bool causesArgumentException = TestHelper.AssertThisDelegateCausesArgumentException(d); + Assert.That(causesArgumentException, Is.True, + "Getting magnitude of null vector did not cause argument exception."); + + LLVector3 expectedNormalizedVector = new LLVector3(.577f, .577f, .577f); + double expectedNormalizedMagnitude = 1; + LLVector3 normalizedVector = Util.GetNormalizedVector(v2); + Assert.That(normalizedVector, + new VectorToleranceConstraint(expectedNormalizedVector, lowPrecisionTolerance), + "Normalized vector generated from vector was not what was expected."); + Assert.That(Util.GetMagnitude(normalizedVector), + new DoubleToleranceConstraint(expectedNormalizedMagnitude, lowPrecisionTolerance), + "Normalized vector generated from vector does not have magnitude of 1."); + } + + //Lets test a simple case of <0,0,0> and <0,0,0> + { + v1 = new LLVector3(0, 0, 0); + v2 = new LLVector3(0, 0, 0); + expectedDistance = 0; + Assert.That(Util.GetDistanceTo(v1, v2), + new DoubleToleranceConstraint(expectedDistance, lowPrecisionTolerance), + "Calculated distance between two vectors was not within tolerances."); + + expectedMagnitude = 0; + Assert.That(Util.GetMagnitude(v1), Is.EqualTo(0), "Magnitude of null vector was not zero."); + + expectedMagnitude = 0; + Assert.That(Util.GetMagnitude(v2), + new DoubleToleranceConstraint(expectedMagnitude, lowPrecisionTolerance), + "Magnitude of vector was incorrect."); + + TestDelegate d = delegate() { Util.GetNormalizedVector(v1); }; + bool causesArgumentException = TestHelper.AssertThisDelegateCausesArgumentException(d); + Assert.That(causesArgumentException, Is.True, + "Getting magnitude of null vector did not cause argument exception."); + + d = delegate() { Util.GetNormalizedVector(v2); }; + causesArgumentException = TestHelper.AssertThisDelegateCausesArgumentException(d); + Assert.That(causesArgumentException, Is.True, + "Getting magnitude of null vector did not cause argument exception."); + } + + //Lets test a simple case of <0,0,0> and <-5,-5,-5> + { + v1 = new LLVector3(0, 0, 0); + v2 = new LLVector3(-5, -5, -5); + expectedDistance = 8.66; + Assert.That(Util.GetDistanceTo(v1, v2), + new DoubleToleranceConstraint(expectedDistance, lowPrecisionTolerance), + "Calculated distance between two vectors was not within tolerances."); + + expectedMagnitude = 0; + Assert.That(Util.GetMagnitude(v1), Is.EqualTo(0), "Magnitude of null vector was not zero."); + + expectedMagnitude = 8.66; + Assert.That(Util.GetMagnitude(v2), + new DoubleToleranceConstraint(expectedMagnitude, lowPrecisionTolerance), + "Magnitude of vector was incorrect."); + + TestDelegate d = delegate() { Util.GetNormalizedVector(v1); }; + bool causesArgumentException = TestHelper.AssertThisDelegateCausesArgumentException(d); + Assert.That(causesArgumentException, Is.True, + "Getting magnitude of null vector did not cause argument exception."); + + LLVector3 expectedNormalizedVector = new LLVector3(-.577f, -.577f, -.577f); + double expectedNormalizedMagnitude = 1; + LLVector3 normalizedVector = Util.GetNormalizedVector(v2); + Assert.That(normalizedVector, + new VectorToleranceConstraint(expectedNormalizedVector, lowPrecisionTolerance), + "Normalized vector generated from vector was not what was expected."); + Assert.That(Util.GetMagnitude(normalizedVector), + new DoubleToleranceConstraint(expectedNormalizedMagnitude, lowPrecisionTolerance), + "Normalized vector generated from vector does not have magnitude of 1."); + } + } + } +} diff --git a/prebuild.xml b/prebuild.xml index e58c94acd3..f956e7ee46 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -81,6 +81,58 @@ + + + + ../../../bin/ + + + + + ../../../bin/ + + + + ../../../bin/ + + + + + + + + + + + + + + ../../../../bin/ + + + + + ../../../../bin/ + + + + ../../../../bin/ + + + + + + + + + + + + + + + +