Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(math): Add Vec2.rotate() #944

Merged
merged 1 commit into from
Aug 9, 2024
Merged
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
32 changes: 31 additions & 1 deletion src/math/Vec2.js
Original file line number Diff line number Diff line change
@@ -474,7 +474,7 @@ export class Vec2 {
}

/**
* Computes the cross product between this and another vector and changes the value of this vector.
* Computes the cross product between this and another vector.
*
* [Cross product visualisation](https://www.geogebra.org/m/psMTGDgc) (in 3d)
*
@@ -525,6 +525,36 @@ export class Vec2 {
return this.set(other);
}

/**
* Rotates the vector (around 0, 0) and modifies it.
* Positive angles rotate the vector clockwise. (Positive x is right, positive y is down)
*
* For instance, say you have a `Vec2<1, 1>`:
* ```none
* o
* \
* \
* V
* ```
* then calling `rotate(Math.PI * 0.5)` results in a `Vec2<-1, 1>`:
* ```none
* o
* /
* /
* V
* ```
* @param {number} angle Angle in radians.
*/
rotate(angle) {
const cos = Math.cos(angle);
const sin = Math.sin(angle);

return this.set(
this._x * cos - this._y * sin,
this._x * sin + this._y * cos,
);
}

/**
* @returns {[x: number, y: number]}
*/
53 changes: 53 additions & 0 deletions test/unit/src/math/Vec2.test.js
Original file line number Diff line number Diff line change
@@ -736,6 +736,48 @@ Deno.test({
},
});

Deno.test({
name: "rotate()",
fn() {
const tests = [
{ vec: [0, 1], angle: 0, result: [0, 1] },
{ vec: [0, 1], angle: Math.PI, result: [0, -1] },
{ vec: [1, 0], angle: Math.PI * 0.5, result: [0, 1] },
{ vec: [1, 1], angle: Math.PI * 0.5, result: [-1, 1] },
{ vec: [0, 0], angle: 100, result: [0, 0] },
{ vec: [12, 34], angle: Math.PI * 2, result: [12, 34] },
{ vec: [12, 34], angle: 0.1, result: [8.54571, 35.02814] },
];

for (const { vec, angle, result } of tests) {
const actual = new Vec2(vec).rotate(angle);

assertVecAlmostEquals(actual, result);
}
},
});

Deno.test({
name: "rotate() angle matches the direction of clockwiseAngleTo",
fn() {
const tests = [
[0.123, -0.456],
[0.5, 2],
[-10, 20],
[-10, -20],
];

for (const test of tests) {
const vec = new Vec2(test);
const newVec = new Vec2(0, 1);
const angle = newVec.clockwiseAngleTo(vec);
newVec.rotate(angle);
newVec.magnitude = vec.magnitude;
assertVecAlmostEquals(newVec, test);
}
},
});

// ======== onChange Callbacks ========

Deno.test({
@@ -894,6 +936,17 @@ Deno.test({
fireResults.push(-1);
expectedResult.push(-1);

vec.set(0, 1);
expectedResult.push(0x11);

vec.rotate(0);
// rotating 0 radians shouldn't fire the callback
fireResults.push(-1);
expectedResult.push(-1);

vec.rotate(0.5);
expectedResult.push(0x11);

assertEquals(fireResults, expectedResult);
},
});