From e548ed8d865763b2bd9d41875565427c01cb89ec Mon Sep 17 00:00:00 2001 From: elexis Date: Sun, 8 Oct 2017 15:25:21 +0000 Subject: [PATCH] Fix Vector.js rotate oversight in rP20263 (this.x may not be modified before reading again and sin/cos should not be computed twice). Extend the tests of rotate in rP20262 to reveal the bug. Add non-static clone functions for vectors (as the static ones were incorrectly removed in rP20125). Math.pow performance is investigated separately, refs P85. Checks and balances by mimo, leper, FeXoR and fatherbushido git-svn-id: https://svn.wildfiregames.com/public/ps/trunk@20272 3db68df2-c116-0410-a063-a993310a9797 --- binaries/data/mods/public/globalscripts/vector.js | 21 +++++++++- .../simulation/components/tests/test_Vector.js | 49 +++++++++++++++++++++- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/binaries/data/mods/public/globalscripts/vector.js b/binaries/data/mods/public/globalscripts/vector.js index 3c451658d4..f792830a45 100644 --- a/binaries/data/mods/public/globalscripts/vector.js +++ b/binaries/data/mods/public/globalscripts/vector.js @@ -16,6 +16,11 @@ function Vector2D(x, y) this.set(0, 0); } +Vector2D.prototype.clone = function() +{ + return new Vector2D(this.x, this.y); +}; + // Mutating 2D functions // // These functions modify the current object, @@ -70,8 +75,15 @@ Vector2D.prototype.normalize = function() */ Vector2D.prototype.rotate = function(a) { - this.x = this.x * Math.cos(a) + this.y * Math.sin(a); - this.y = this.y * Math.cos(a) - this.x * Math.sin(a); + let sin = Math.sin(a); + let cos = Math.cos(a); + + let x = this.x * cos + this.y * sin; + let y = this.y * cos - this.x * sin; + + this.x = x; + this.y = y; + return this; }; @@ -179,6 +191,11 @@ function Vector3D(x, y, z) this.set(0, 0, 0); } +Vector3D.prototype.clone = function() +{ + return new Vector3D(this.x, this.y, this.z); +}; + // Mutating 3D functions // // These functions modify the current object, diff --git a/binaries/data/mods/public/simulation/components/tests/test_Vector.js b/binaries/data/mods/public/simulation/components/tests/test_Vector.js index e89dbffe4b..c70e35bd55 100644 --- a/binaries/data/mods/public/simulation/components/tests/test_Vector.js +++ b/binaries/data/mods/public/simulation/components/tests/test_Vector.js @@ -35,6 +35,43 @@ var brokenVector = { TS_ASSERT_EQUALS(v4.x, -2); TS_ASSERT_EQUALS(v4.y, 5); + // Result of rotating (1, 0) + let unitCircle = [ + { + "angle": Math.PI / 2, + "x": 0, + "y": 1 + }, + { + "angle": Math.PI / 3, + "x": 1/2, + "y": Math.sqrt(3) / 2 + }, + { + "angle": Math.PI / 4, + "x": Math.sqrt(2) / 2, + "y": Math.sqrt(2) / 2 + }, + { + "angle": Math.PI / 6, + "x": Math.sqrt(3) / 2, + "y": 1/2 + } + ]; + + let epsilon = 0.00000001; + + for (let expectedVector of unitCircle) + { + let computedVector = new Vector2D(1, 0).rotate(-expectedVector.angle); + for (let s of ["x", "y"]) + if (Math.abs(expectedVector[s] - computedVector[s]) > epsilon) + { + TS_FAIL("Expected " + uneval(expectedVector) + " got " + uneval(computedVector)); + break; + } + } + TS_ASSERT_EQUALS(new Vector2D(2, 3).dot(new Vector2D(4, 5)), 23); TS_ASSERT_EQUALS(new Vector2D(3, 5).cross(new Vector2D(-4, -1/3)), 19); TS_ASSERT_EQUALS(new Vector2D(20, 21).length(), 29); @@ -44,6 +81,11 @@ var brokenVector = { TS_ASSERT_EQUALS(v5.compareLength(new Vector2D(500, 800)), -1); TS_ASSERT_EQUALS(v5.compareLength(new Vector2D(10, 20)), 0); TS_ASSERT(isNaN(v5.compareLength(brokenVector))); + + let v6 = v5.clone(); + TS_ASSERT_EQUALS(v5.x, v6.x); + TS_ASSERT_EQUALS(v5.y, v6.y); + TS_ASSERT(Math.abs(v5.dot(v6.rotate(Math.PI / 2))) < epsilon); } // Test Vector3D @@ -59,4 +101,9 @@ var brokenVector = { TS_ASSERT_EQUALS(new Vector3D(1, 2, 3).dot(new Vector3D(4, 5, 6)), 32); -} \ No newline at end of file + let v3 = new Vector3D(9, 10, 11); + let v4 = v3.clone(); + TS_ASSERT_EQUALS(v3.x, v4.x); + TS_ASSERT_EQUALS(v3.y, v4.y); + TS_ASSERT_EQUALS(v3.z, v4.z); +} -- 2.11.4.GIT