diff --git a/change/@minecraft-math-6bce4916-e540-448e-b3bb-bf9e6d6b19a3.json b/change/@minecraft-math-6bce4916-e540-448e-b3bb-bf9e6d6b19a3.json new file mode 100644 index 0000000..3360ea4 --- /dev/null +++ b/change/@minecraft-math-6bce4916-e540-448e-b3bb-bf9e6d6b19a3.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "Implimented multiply, rotateX, rotateY, and rotateZ as new vectormath operations", + "packageName": "@minecraft/math", + "email": "aiaub1212@gmail.com", + "dependentChangeType": "patch" +} diff --git a/libraries/math/api-report/math.api.md b/libraries/math/api-report/math.api.md index 91a655d..6b6ca6c 100644 --- a/libraries/math/api-report/math.api.md +++ b/libraries/math/api-report/math.api.md @@ -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; @@ -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; diff --git a/libraries/math/src/vector3/coreHelpers.test.ts b/libraries/math/src/vector3/coreHelpers.test.ts index 1d854d5..53cb7b8 100644 --- a/libraries/math/src/vector3/coreHelpers.test.ts +++ b/libraries/math/src/vector3/coreHelpers.test.ts @@ -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 }; @@ -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); + }); + }); }); diff --git a/libraries/math/src/vector3/coreHelpers.ts b/libraries/math/src/vector3/coreHelpers.ts index ff83ed4..459e0df 100644 --- a/libraries/math/src/vector3/coreHelpers.ts +++ b/libraries/math/src/vector3/coreHelpers.ts @@ -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, + }; + } } /** diff --git a/libraries/math/src/vector3/vectorWrapper.test.ts b/libraries/math/src/vector3/vectorWrapper.test.ts index a95d9e0..012ae5c 100644 --- a/libraries/math/src/vector3/vectorWrapper.test.ts +++ b/libraries/math/src/vector3/vectorWrapper.test.ts @@ -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', () => { diff --git a/libraries/math/src/vector3/vectorWrapper.ts b/libraries/math/src/vector3/vectorWrapper.ts index d3512bd..9a4b67e 100644 --- a/libraries/math/src/vector3/vectorWrapper.ts +++ b/libraries/math/src/vector3/vectorWrapper.ts @@ -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)); + } } /**