Skip to content

Commit

Permalink
Added a couple more vectormath operations (#35)
Browse files Browse the repository at this point in the history
* Add multiply, rotateX, rotateY, and rotateZ and add tests

* Implimented multiply, rotateX, rotateY, and rotateZ to the Vector3Builder

* Change files

* Convert rotation functions to right hand rule & fix linting errors

* Fix minor typing issue

* Made rotateY counterclockwise again
  • Loading branch information
Incoherent-Code authored Nov 26, 2024
1 parent 9850896 commit 9d6cb50
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Implimented multiply, rotateX, rotateY, and rotateZ as new vectormath operations",
"packageName": "@minecraft/math",
"email": "[email protected]",
"dependentChangeType": "patch"
}
8 changes: 8 additions & 0 deletions libraries/math/api-report/math.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,11 @@ export class Vector3Builder implements Vector3 {
floor(): this;
lerp(vec: Vector3, t: number): this;
magnitude(): number;
multiply(vec: Vector3): this;
normalize(): this;
rotateX(a: number): this;
rotateY(a: number): this;
rotateZ(a: number): this;
scale(val: number): this;
slerp(vec: Vector3, t: number): this;
subtract(v: Vector3): this;
Expand Down Expand Up @@ -116,7 +120,11 @@ export class Vector3Utils {
static floor(v: Vector3): Vector3;
static lerp(a: Vector3, b: Vector3, t: number): Vector3;
static magnitude(v: Vector3): number;
static multiply(a: Vector3, b: Vector3): Vector3;
static normalize(v: Vector3): Vector3;
static rotateX(v: Vector3, a: number): Vector3;
static rotateY(v: Vector3, a: number): Vector3;
static rotateZ(v: Vector3, a: number): Vector3;
static scale(v1: Vector3, scale: number): Vector3;
static slerp(a: Vector3, b: Vector3, t: number): Vector3;
static subtract(v1: Vector3, v2: Vector3): Vector3;
Expand Down
30 changes: 29 additions & 1 deletion libraries/math/src/vector3/coreHelpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import { Vector2, Vector3 } from '@minecraft/server';
import { describe, expect, it } from 'vitest';
import { Vector2Utils, Vector3Utils } from './coreHelpers';
import { Vector2Utils, VECTOR3_LEFT, VECTOR3_UP, Vector3Utils } from './coreHelpers';

describe('Vector3 operations', () => {
const v1: Vector3 = { x: 1, y: 2, z: 3 };
Expand Down Expand Up @@ -189,4 +189,32 @@ describe('Vector3 operations', () => {
expect(result.y).toBeCloseTo(-0.7071, 3);
expect(result.z).toBeCloseTo(0);
});

it('calculates two vectors multiplied together', () => {
const result: Vector3 = Vector3Utils.multiply(v1, v2);
expect(result).toEqual({ x: 4, y: 10, z: 18 });
});

describe('Vector3 rotation functions', () => {
it(`calculates a vector rotated along the x axis`, () => {
const result = Vector3Utils.rotateX(VECTOR3_UP, Math.PI / 2);
expect(result.x).toBeCloseTo(0);
expect(result.y).toBeCloseTo(0);
expect(result.z).toBeCloseTo(1);
});

it(`calculates a vector rotated along the y axis`, () => {
const result = Vector3Utils.rotateY(VECTOR3_LEFT, Math.PI / 2);
expect(result.x).toBeCloseTo(0);
expect(result.y).toBeCloseTo(0);
expect(result.z).toBeCloseTo(1);
});

it(`calculates a vector rotated along the z axis`, () => {
const result = Vector3Utils.rotateZ(VECTOR3_UP, Math.PI / 2);
expect(result.x).toBeCloseTo(-1);
expect(result.y).toBeCloseTo(0);
expect(result.z).toBeCloseTo(0);
});
});
});
62 changes: 62 additions & 0 deletions libraries/math/src/vector3/coreHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,68 @@ export class Vector3Utils {
const tb = Math.sin(t * theta) / sinTheta;
return Vector3Utils.add(Vector3Utils.scale(a, ta), Vector3Utils.scale(b, tb));
}

/**
* multiply
*
* Element-wise multiplication of two vectors together.
* Not to be confused with {@link Vector3Utils.dot} product or {@link Vector3Utils.cross} product
*/
static multiply(a: Vector3, b: Vector3): Vector3 {
return {
x: a.x * b.x,
y: a.y * b.y,
z: a.z * b.z,
};
}

/**
* rotateX
*
* Rotates the vector around the x axis counterclockwise (left hand rule)
* @param a - Angle in radians
*/
static rotateX(v: Vector3, a: number): Vector3 {
let cos = Math.cos(a);
let sin = Math.sin(a);
return {
x: v.x,
y: v.y * cos - v.z * sin,
z: v.z * cos + v.y * sin,
};
}

/**
* rotateY
*
* Rotates the vector around the y axis counterclockwise (left hand rule)
* @param a - Angle in radians
*/
static rotateY(v: Vector3, a: number): Vector3 {
let cos = Math.cos(a);
let sin = Math.sin(a);
return {
x: v.x * cos + v.z * sin,
y: v.y,
z: v.z * cos - v.x * sin,
};
}

/**
* rotateZ
*
* Rotates the vector around the z axis counterclockwise (left hand rule)
* @param a - Angle in radians
*/
static rotateZ(v: Vector3, a: number): Vector3 {
let cos = Math.cos(a);
let sin = Math.sin(a);
return {
x: v.x * cos - v.y * sin,
y: v.y * cos + v.x * sin,
z: v.z,
};
}
}

/**
Expand Down
40 changes: 40 additions & 0 deletions libraries/math/src/vector3/vectorWrapper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,46 @@ describe('Vector3Builder', () => {
const resultB = vectorA.slerp(vectorB, ratio);
expect(resultA).toEqual(resultB);
});

it('should be able to multiply with the same result as the coreHelpers function', () => {
const vectorA = new Vector3Builder(5, 6, 3);
const vectorB = new Vector3Builder(4, 2, 6);

const resultA = Vector3Utils.multiply(vectorA, vectorB);

const resultB = vectorA.multiply(vectorB);
expect(resultA).toEqual(resultB);
});

it('should be able to rotate over x with the same result as the coreHelpers function', () => {
const vectorA = new Vector3Builder(5, 6, 3);
const angle = Math.PI / 2;

const resultA = Vector3Utils.rotateX(vectorA, angle);

const resultB = vectorA.rotateX(angle);
expect(resultA).toEqual(resultB);
});

it('should be able to rotate over y with the same result as the coreHelpers function', () => {
const vectorA = new Vector3Builder(5, 6, 3);
const angle = Math.PI / 2;

const resultA = Vector3Utils.rotateY(vectorA, angle);

const resultB = vectorA.rotateY(angle);
expect(resultA).toEqual(resultB);
});

it('should be able to rotate over z with the same result as the coreHelpers function', () => {
const vectorA = new Vector3Builder(5, 6, 3);
const angle = Math.PI / 2;

const resultA = Vector3Utils.rotateZ(vectorA, angle);

const resultB = vectorA.rotateZ(angle);
expect(resultA).toEqual(resultB);
});
});

describe('Vector2Builder', () => {
Expand Down
40 changes: 40 additions & 0 deletions libraries/math/src/vector3/vectorWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,46 @@ export class Vector3Builder implements Vector3 {
slerp(vec: Vector3, t: number): this {
return this.assign(Vector3Utils.slerp(this, vec, t));
}

/**
* multiply
*
* Element-wise multiplication of two vectors together.
* Not to be confused with {@link Vector3Builder.dot} product or {@link Vector3Builder.cross} product
*/
multiply(vec: Vector3): this {
return this.assign(Vector3Utils.multiply(this, vec));
}

/**
* rotateX
*
* Rotates the vector around the x axis counterclockwise (left hand rule)
* @param a - Angle in radians
*/
rotateX(a: number): this {
return this.assign(Vector3Utils.rotateX(this, a));
}

/**
* rotateY
*
* Rotates the vector around the y axis counterclockwise (left hand rule)
* @param a - Angle in radians
*/
rotateY(a: number): this {
return this.assign(Vector3Utils.rotateY(this, a));
}

/**
* rotateZ
*
* Rotates the vector around the z axis counterclockwise (left hand rule)
* @param a - Angle in radians
*/
rotateZ(a: number): this {
return this.assign(Vector3Utils.rotateZ(this, a));
}
}

/**
Expand Down

0 comments on commit 9d6cb50

Please sign in to comment.