Skip to content

Commit d03371d

Browse files
GDOR-11toji
authored andcommitted
Improved calculation of angles for vec2
provided a new implementation of vec2.angle which is about 1.2 times faster and created a new function, called vec2.signedAngle, which returns the same value as vec2.angle but negative when the first vector is to the left of the second (it's useful when you want to know the rotation matrix which aligns both vectors, for example) updated the tests for vec2.angle and created new tests for vec2.signedAngle in order to make sure both behave as expected, returning values in the expected intervals
1 parent 1f872b8 commit d03371d

File tree

2 files changed

+52
-19
lines changed

2 files changed

+52
-19
lines changed

spec/gl-matrix/vec2-spec.js

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -601,15 +601,41 @@ describe("vec2", function() {
601601
});
602602

603603
describe("angle", function() {
604-
beforeEach(function() {
605-
vecA = [1,0];
606-
vecB = [1,2];
607-
result = vec2.angle(vecA, vecB);
604+
it("should always return the positive angle between 0 and pi", function() {
605+
expect(vec2.angle([1, 0], [1, 2]))
606+
.toBeEqualish(1.10714);
607+
expect(vec2.angle([1, 2], [1, 0]))
608+
.toBeEqualish(1.10714);
609+
expect(vec2.angle([-1, 0], [1, 2]))
610+
.toBeEqualish(2.03445);
611+
expect(vec2.angle([1, 2], [-1, 0]))
612+
.toBeEqualish(2.03445);
613+
});
614+
it("should not modify the arguments", function() {
615+
let a = [1, 0], b = [1, 2];
616+
vec2.angle(a, b);
617+
expect(a).toBeEqualish([1, 0]);
618+
expect(b).toBeEqualish([1, 2]);
619+
});
620+
});
621+
622+
describe("signedAngle", function() {
623+
it("should always return the signed angle between -pi and pi", function() {
624+
expect(vec2.signedAngle([1, 0], [1, 2]))
625+
.toBeEqualish(1.10714);
626+
expect(vec2.signedAngle([1, 2], [1, 0]))
627+
.toBeEqualish(-1.10714);
628+
expect(vec2.signedAngle([-1, 0], [1, 2]))
629+
.toBeEqualish(-2.03445);
630+
expect(vec2.signedAngle([1, 2], [-1, 0]))
631+
.toBeEqualish(2.03445);
632+
});
633+
it("should not modify the arguments", function() {
634+
let a = [1, 0], b = [1, 2];
635+
vec2.signedAngle(a, b);
636+
expect(a).toBeEqualish([1, 0]);
637+
expect(b).toBeEqualish([1, 2]);
608638
});
609-
610-
it("should return the angle", function() { expect(result).toBeEqualish(1.10714); });
611-
it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 0]); });
612-
it("should not modify vecB", function() { expect(vecB).toBeEqualish([1, 2]); });
613639
});
614640

615641
describe("str", function() {

src/vec2.js

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -470,24 +470,31 @@ export function rotate(out, a, b, rad) {
470470
}
471471

472472
/**
473-
* Get the angle between two 2D vectors
473+
* Get the smallest angle between two 2D vectors
474474
* @param {ReadonlyVec2} a The first operand
475475
* @param {ReadonlyVec2} b The second operand
476476
* @returns {Number} The angle in radians
477477
*/
478478
export function angle(a, b) {
479-
let x1 = a[0],
480-
y1 = a[1],
481-
x2 = b[0],
482-
y2 = b[1],
483-
// mag is the product of the magnitudes of a and b
484-
mag = Math.sqrt((x1 * x1 + y1 * y1) * (x2 * x2 + y2 * y2)),
485-
// mag &&.. short circuits if mag == 0
486-
cosine = mag && (x1 * x2 + y1 * y2) / mag;
487-
// Math.min(Math.max(cosine, -1), 1) clamps the cosine between -1 and 1
488-
return Math.acos(Math.min(Math.max(cosine, -1), 1));
479+
let ax = a[0], ay = a[1],
480+
bx = b[0], by = b[1];
481+
return Math.abs(Math.atan2(ay * bx - ax * by, ax * bx + ay * by));
489482
}
490483

484+
/**
485+
* Get the signed angle in the interval [-pi,pi] between two 2D vectors (positive if `a` is to the right of `b`)
486+
*
487+
* @param {ReadonlyVec2} a The first vector
488+
* @param {ReadonlyVec2} b The second vector
489+
* @returns {number} The signed angle in radians
490+
*/
491+
export function signedAngle(a, b) {
492+
let ax = a[0], ay = a[1],
493+
bx = b[0], by = b[1];
494+
return Math.atan2(ax * by - ay * bx, ax * bx + ay * by);
495+
}
496+
497+
491498
/**
492499
* Set the components of a vec2 to zero
493500
*

0 commit comments

Comments
 (0)