From ff5a83d192105e4674cff261b13a447ff0d1e478 Mon Sep 17 00:00:00 2001 From: John Cochran Date: Thu, 5 Jan 2012 07:37:08 -0600 Subject: Fixed llAngleBetween() to allow denormal rotations --- .../Shared/Api/Implementation/LSL_Api.cs | 14 ++++--- .../ScriptEngine/Shared/Tests/LSL_ApiTest.cs | 47 +++++++++++++++------- 2 files changed, 41 insertions(+), 20 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index a35e75f..d6de39f 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -4698,15 +4698,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return (double)Math.Asin(val); } - // Xantor 30/apr/2008 + // jcochran 5/jan/2012 public LSL_Float llAngleBetween(LSL_Rotation a, LSL_Rotation b) { m_host.AddScriptLPS(1); - double angle = Math.Acos(a.x * b.x + a.y * b.y + a.z * b.z + a.s * b.s) * 2; - if (angle < 0) angle = -angle; - if (angle > Math.PI) return (Math.PI * 2 - angle); - return angle; + double aa = (a.x * a.x + a.y * a.y + a.z * a.z + a.s * a.s); + double bb = (b.x * b.x + b.y * b.y + b.z * b.z + b.s * b.s); + double aa_bb = aa * bb; + if (aa_bb == 0) return 0.0; + double ab = (a.x * b.x + a.y * b.y + a.z * b.z + a.s * b.s); + double quotient = (ab * ab) / aa_bb; + if (quotient >= 1.0) return 0.0; + return Math.Acos(2 * quotient - 1); } public LSL_String llGetInventoryKey(string name) diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs index 99c1cf4..3baa723 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs @@ -75,32 +75,49 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests [Test] public void TestllAngleBetween() { - CheckllAngleBetween(new Vector3(1, 0, 0), 0); - CheckllAngleBetween(new Vector3(1, 0, 0), 90); - CheckllAngleBetween(new Vector3(1, 0, 0), 180); + CheckllAngleBetween(new Vector3(1, 0, 0), 0, 1, 1); + CheckllAngleBetween(new Vector3(1, 0, 0), 90, 1, 1); + CheckllAngleBetween(new Vector3(1, 0, 0), 180, 1, 1); - CheckllAngleBetween(new Vector3(0, 1, 0), 0); - CheckllAngleBetween(new Vector3(0, 1, 0), 90); - CheckllAngleBetween(new Vector3(0, 1, 0), 180); + CheckllAngleBetween(new Vector3(0, 1, 0), 0, 1, 1); + CheckllAngleBetween(new Vector3(0, 1, 0), 90, 1, 1); + CheckllAngleBetween(new Vector3(0, 1, 0), 180, 1, 1); - CheckllAngleBetween(new Vector3(0, 0, 1), 0); - CheckllAngleBetween(new Vector3(0, 0, 1), 90); - CheckllAngleBetween(new Vector3(0, 0, 1), 180); + CheckllAngleBetween(new Vector3(0, 0, 1), 0, 1, 1); + CheckllAngleBetween(new Vector3(0, 0, 1), 90, 1, 1); + CheckllAngleBetween(new Vector3(0, 0, 1), 180, 1, 1); - CheckllAngleBetween(new Vector3(1, 1, 1), 0); - CheckllAngleBetween(new Vector3(1, 1, 1), 90); - CheckllAngleBetween(new Vector3(1, 1, 1), 180); + CheckllAngleBetween(new Vector3(1, 1, 1), 0, 1, 1); + CheckllAngleBetween(new Vector3(1, 1, 1), 90, 1, 1); + CheckllAngleBetween(new Vector3(1, 1, 1), 180, 1, 1); + + CheckllAngleBetween(new Vector3(1, 0, 0), 0, 1.6f, 1.8f); + CheckllAngleBetween(new Vector3(1, 0, 0), 90, 0.3f, 3.9f); + CheckllAngleBetween(new Vector3(1, 0, 0), 180, 8.8f, 7.4f); + + CheckllAngleBetween(new Vector3(0, 1, 0), 0, 9.8f, -9.4f); + CheckllAngleBetween(new Vector3(0, 1, 0), 90, 8.4f, -8.2f); + CheckllAngleBetween(new Vector3(0, 1, 0), 180, 0.4f, -5.8f); + + CheckllAngleBetween(new Vector3(0, 0, 1), 0, -6.8f, 3.4f); + CheckllAngleBetween(new Vector3(0, 0, 1), 90, -3.6f, 5.6f); + CheckllAngleBetween(new Vector3(0, 0, 1), 180, -3.8f, 1.1f); + + CheckllAngleBetween(new Vector3(1, 1, 1), 0, -7.7f, -2.0f); + CheckllAngleBetween(new Vector3(1, 1, 1), 90, -3.0f, -9.1f); + CheckllAngleBetween(new Vector3(1, 1, 1), 180, -7.9f, -8.0f); } - private void CheckllAngleBetween(Vector3 axis,float originalAngle) + private void CheckllAngleBetween(Vector3 axis,float originalAngle, float denorm1, float denorm2) { Quaternion rotation1 = Quaternion.CreateFromAxisAngle(axis, 0); Quaternion rotation2 = Quaternion.CreateFromAxisAngle(axis, ToRadians(originalAngle)); + rotation1 *= denorm1; + rotation2 *= denorm2; double deducedAngle = FromLslFloat(m_lslApi.llAngleBetween(ToLslQuaternion(rotation2), ToLslQuaternion(rotation1))); - Assert.Greater(deducedAngle, ToRadians(originalAngle) - ANGLE_ACCURACY_IN_RADIANS); - Assert.Less(deducedAngle, ToRadians(originalAngle) + ANGLE_ACCURACY_IN_RADIANS); + Assert.That(deducedAngle, Is.EqualTo(ToRadians(originalAngle)).Within(ANGLE_ACCURACY_IN_RADIANS), "TestllAngleBetween check fail"); } #region Conversions to and from LSL_Types -- cgit v1.1