Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions src/math/p5.Vector.js
Original file line number Diff line number Diff line change
Expand Up @@ -1419,31 +1419,37 @@ class Vector {
* // META:norender
* function setup() {
* // Create p5.Vector objects.
* let v1 = createVector(1, 0);
* let v2 = createVector(3, 4);
* let v1 = createVector(1, 0, 0);
* let v2 = createVector(0, 1, 0);
*
* // Calculate the cross product.
* let cp = v1.cross(v2);
*
* // Prints "p5.Vector Object : [0, 0, 4]" to the console.
* // Prints "vector[0, 0, 1]" to the console.
* print(cp.toString());
* }
*
* @example
* // META:norender
* function setup() {
* // Create p5.Vector objects.
* let v1 = createVector(1, 0);
* let v2 = createVector(3, 4);
* let v1 = createVector(1, 0, 0);
* let v2 = createVector(0, 1, 0);
*
* // Calculate the cross product.
* let cp = p5.Vector.cross(v1, v2);
*
* // Prints "p5.Vector Object : [0, 0, 4]" to the console.
* // Prints "vector[0, 0, 1]" to the console.
* print(cp.toString());
* }
*/
cross(v) {
if (this.dimensions !== 3 || v.dimensions !== 3){
this._friendlyError(
'cross() is designed for 3D vectors. It uses only the x, y, and z components, so the result may not be meaningful when either vector is not 3D.',
'p5.Vector.cross'
);
}
const x = this.y * v.z - this.z * v.y;
const y = this.z * v.x - this.x * v.z;
const z = this.x * v.y - this.y * v.x;
Expand Down
35 changes: 35 additions & 0 deletions test/unit/math/p5.Vector.js
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,15 @@ suite('p5.Vector', function () {
v2 = new Vector(-219, -560);
expect(v1.angleBetween(v2)).to.be.closeTo(Math.PI, 0.0000001);
});

test('should not surface cross()\'s 3D warning for genuine 2D vectors', function () {
// angleBetween supports 2D vectors and calls this.cross(v) internally.
// It should not leak cross()'s 3D friendly error to the user.
// RED until #8926 decouples angleBetween from cross().
FESCalled = false;
new Vector(-11, -20).angleBetween(new Vector(-5.5, -10));
assert.equal(FESCalled, false);
});
});

suite('p5.Vector.angleBetween() [CLASS]', function () {
Expand Down Expand Up @@ -1157,6 +1166,23 @@ suite('p5.Vector', function () {
expect(res.z).to.eql(-3);
});
});
test('should trigger a friendly error when either vector is not 3D', function () {
// 2D inputs
FESCalled = false;
new Vector(1, 0).cross(new Vector(0, 1));
assert.equal(FESCalled, true);

// >3D inputs
FESCalled = false;
new Vector(1, 0, 0, 2).cross(new Vector(0, 0, 1, -1));
assert.equal(FESCalled, true);
});

test('should not trigger a friendly error for two 3D vectors', function () {
FESCalled = false;
new Vector(1, 0, 0).cross(new Vector(0, 1, 0));
assert.equal(FESCalled, false);
});
});

suite('dist', function () {
Expand Down Expand Up @@ -1607,6 +1633,15 @@ suite('p5.Vector', function () {
expect(v.y).to.eql(22);
expect(v.z).to.eql(32);
});

test('should not surface cross()\'s 3D warning for genuine 2D vectors', function () {
// slerp uses this.cross(v) to find the rotation axis. Calling it with
// genuine 2-component vectors should not leak cross()'s 3D friendly error.
// RED until #8928 decouples slerp from cross().
FESCalled = false;
new Vector(2, 3).slerp(new Vector(3, -2), 0.3);
assert.equal(FESCalled, false);
});
});

suite('p5.Vector.slerp(v1, v2, amt)', function () {
Expand Down