Skip to content

Commit 73bcd00

Browse files
committed
Fix angleBetween for parallel and antiparallel vectors
Due to floating-point rounding issues angleBetween sometimes returned NaN
1 parent 4449d63 commit 73bcd00

File tree

2 files changed

+36
-1
lines changed

2 files changed

+36
-1
lines changed

src/math/p5.Vector.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -636,7 +636,13 @@ p5.Vector.prototype.rotate = function (a) {
636636
* </div>
637637
*/
638638
p5.Vector.prototype.angleBetween = function (v) {
639-
var angle = Math.acos(this.dot(v) / (this.mag() * v.mag()));
639+
var dotmagmag = this.dot(v) / (this.mag() * v.mag());
640+
// Mathematically speaking: the dotmagmag variable will be between -1 and 1
641+
// inclusive. Practically though it could be slightly outside this range due
642+
// to floating-point rounding issues. This can make Math.acos return NaN.
643+
//
644+
// Solution: we'll clamp the value to the -1,1 range
645+
var angle = Math.acos(Math.min(1, Math.max(-1, dotmagmag)));
640646
if (this.p5) {
641647
if (this.p5._angleMode === constants.DEGREES) {
642648
angle = polarGeometry.radiansToDegrees(angle);

test/unit/math/p5.Vector.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,35 @@ suite('p5.Vector', function() {
114114
assert.closeTo(v.z, 0, 0.001);
115115
});
116116
});
117+
118+
suite('p5.prototype.angleBetween()', function() {
119+
test('should not trip on rounding issues in 2D space', function() {
120+
var v1 = myp5.createVector(-11, -20);
121+
var v2 = myp5.createVector(-5.5, -10);
122+
expect(v1.angleBetween(v2)).to.be.closeTo(0, 0.00001);
123+
124+
var v3 = myp5.createVector(-11, -20);
125+
var v4 = myp5.createVector(5.5, 10);
126+
expect(v3.angleBetween(v4)).to.be.closeTo(180, 0.00001);
127+
});
128+
129+
test('should not trip on rounding issues in 3D space', function() {
130+
var v1 = myp5.createVector(1, 1.1, 1.2);
131+
var v2 = myp5.createVector(2, 2.2, 2.4);
132+
133+
var angle = v1.angleBetween(v2);
134+
expect(angle).to.be.closeTo(0, 0.00001);
135+
});
136+
137+
test('should return NaN for zero vector', function() {
138+
var v1 = myp5.createVector(0, 0, 0);
139+
var v2 = myp5.createVector(2, 3, 4);
140+
141+
expect(v1.angleBetween(v2)).to.be.NaN; // jshint ignore:line
142+
expect(v2.angleBetween(v1)).to.be.NaN; // jshint ignore:line
143+
});
144+
145+
});
117146
});
118147

119148
// describe('set()', function() {

0 commit comments

Comments
 (0)