Skip to content

Commit

Permalink
Vector improvements - Adding functions for distance, lerp and slerp (#13
Browse files Browse the repository at this point in the history
)

* Added distance, lerp and slerp functions

* Change files

* Update version

* Tests + wrapper code

* Update vectorWrapper.test.ts
  • Loading branch information
AlexDenfordSkyboxLabs authored Feb 27, 2024
1 parent 43cc1e9 commit 4b2923a
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Added distance, lerp and slerp functions",
"packageName": "@minecraft/math",
"email": "[email protected]",
"dependentChangeType": "patch"
}
6 changes: 6 additions & 0 deletions libraries/math/api-report/math.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,15 @@ export class Vector3Builder implements Vector3 {
max?: Partial<Vector3>;
}): this;
cross(vec: Vector3): this;
distance(vec: Vector3): number;
dot(vec: Vector3): number;
equals(v: Vector3): boolean;
floor(): this;
lerp(vec: Vector3, t: number): this;
magnitude(): number;
normalize(): this;
scale(val: number): this;
slerp(vec: Vector3, t: number): this;
subtract(v: Vector3): this;
toString(options?: {
decimals?: number;
Expand All @@ -107,12 +110,15 @@ export class Vector3Utils {
max?: Partial<Vector3>;
}): Vector3;
static cross(a: Vector3, b: Vector3): Vector3;
static distance(a: Vector3, b: Vector3): number;
static dot(a: Vector3, b: Vector3): number;
static equals(v1: Vector3, v2: Vector3): boolean;
static floor(v: Vector3): Vector3;
static lerp(a: Vector3, b: Vector3, t: number): Vector3;
static magnitude(v: Vector3): number;
static normalize(v: Vector3): Vector3;
static scale(v1: Vector3, scale: number): Vector3;
static slerp(a: Vector3, b: Vector3, t: number): Vector3;
static subtract(v1: Vector3, v2: Vector3): Vector3;
static toString(v: Vector3, options?: {
decimals?: number;
Expand Down
2 changes: 1 addition & 1 deletion libraries/math/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@minecraft/math",
"version": "1.1.1",
"version": "1.2.0",
"author": "Raphael Landaverde ([email protected])",
"description": "Math utilities for use with minecraft scripting modules",
"main": "lib/index.js",
Expand Down
19 changes: 19 additions & 0 deletions libraries/math/src/vector3/coreHelpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ describe('Vector3 operations', () => {
expect(result).toBeCloseTo(3.74, 2);
});

it('calculates the distance between two vectors', () => {
const result: number = Vector3Utils.distance(v1, v2);
expect(result).toBeCloseTo(5.2, 2);
});

it('computes the floor of the vector', () => {
const input: Vector3 = { x: 1.33, y: 2.14, z: 3.55 };
const expected: Vector3 = { x: 1, y: 2, z: 3 };
Expand Down Expand Up @@ -170,4 +175,18 @@ describe('Vector3 operations', () => {
expect(result).toEqual({ x: 2, y: 1e6, z: 2.5 });
});
});

it('calculates the lerp halfway between two vectors', () => {
const result: Vector3 = Vector3Utils.lerp(v1, v2, 0.5);
expect(result).toEqual({ x: 2.5, y: 3.5, z: 4.5});
});

it('calculates the slerp halfway between two vectors', () => {
const vecA: Vector3 = { x: 1, y: 0, z: 0 };
const vecB: Vector3 = { x: 0, y: -1, z: 0 };
const result: Vector3 = Vector3Utils.slerp(vecA, vecB, 0.5);
expect(result.x).toBeCloseTo(0.7071, 3);
expect(result.y).toBeCloseTo(-0.7071, 3);
expect(result.z).toBeCloseTo(0);
});
});
36 changes: 36 additions & 0 deletions libraries/math/src/vector3/coreHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,15 @@ export class Vector3Utils {
return Math.sqrt(v.x ** 2 + v.y ** 2 + v.z ** 2);
}

/**
* distance
*
* Calculate the distance between two vectors
*/
static distance(a: Vector3, b: Vector3): number {
return Vector3Utils.magnitude(Vector3Utils.subtract(a, b));
}

/**
* normalize
*
Expand Down Expand Up @@ -124,6 +133,32 @@ export class Vector3Utils {
z: clampNumber(v.z, limits?.min?.z ?? Number.MIN_SAFE_INTEGER, limits?.max?.z ?? Number.MAX_SAFE_INTEGER),
};
}

/**
* lerp
*
* Constructs a new vector using linear interpolation on each component from two vectors.
*/
static lerp(a: Vector3, b: Vector3, t: number): Vector3 {
return {
x: a.x + (b.x - a.x) * t,
y: a.y + (b.y - a.y) * t,
z: a.z + (b.z - a.z) * t,
};
}

/**
* slerp
*
* Constructs a new vector using spherical linear interpolation on each component from two vectors.
*/
static slerp(a: Vector3, b: Vector3, t: number): Vector3 {
const theta = Math.acos(Vector3Utils.dot(a, b));
const sinTheta = Math.sin(theta);
const ta = Math.sin((1.0 - t) * theta) / sinTheta;
const tb = Math.sin(t * theta) / sinTheta;
return Vector3Utils.add(Vector3Utils.scale(a, ta), Vector3Utils.scale(b, tb));
}
}

/**
Expand Down Expand Up @@ -244,3 +279,4 @@ export const VECTOR3_NORTH: Vector3 = { x: 0, y: 0, z: 1 };
* @public
*/
export const VECTOR3_SOUTH: Vector3 = { x: 0, y: 0, z: -1 };

28 changes: 28 additions & 0 deletions libraries/math/src/vector3/vectorWrapper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,14 @@ describe('Vector3Builder', () => {
expect(vectorA.magnitude()).toEqual(mag);
});

it('should be able to compute the distance between two vectors with the same result as the coreHelpers function', () => {
const vectorA = new Vector3Builder(1, 2, 3);
const vectorB = new Vector3Builder(4, 5, 6);
const mag = Vector3Utils.distance(vectorA, vectorB);

expect(vectorA.distance(vectorB)).toEqual(mag);
});

it('should be able to normalize the vector with the same result as the coreHelpers function', () => {
const vectorA = new Vector3Builder(1, 2, 3);
const vectorB = Vector3Utils.normalize(vectorA);
Expand Down Expand Up @@ -152,6 +160,26 @@ describe('Vector3Builder', () => {
const result = vectorA.toString({ decimals: 1, delimiter: ' ' });
expect(result).toEqual(vectorB);
});

it('should be able compute the lerp halfway between two vectors with the same result as the coreHelpers function', () => {
const vectorA = new Vector3Builder(5, 6, 3);
const vectorB = new Vector3Builder(4, 2, 6);
const ratio: number = 0.4;
const resultA = Vector3Utils.lerp(vectorA, vectorB, ratio);

const resultB = vectorA.lerp(vectorB, ratio);
expect(resultA).toEqual(resultB);
});

it('should be able compute the slerp halfway between two vectors with the same result as the coreHelpers function', () => {
const vectorA = new Vector3Builder(5, 6, 3);
const vectorB = new Vector3Builder(4, 2, 6);
const ratio: number = 0.4;
const resultA = Vector3Utils.slerp(vectorA, vectorB, ratio);

const resultB = vectorA.slerp(vectorB, ratio);
expect(resultA).toEqual(resultB);
});
});

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

/**
* distance
*
* Calculate the distance between two vectors
*/
distance(vec: Vector3): number {
return Vector3Utils.distance(this, vec);
}

/**
* normalize
*
Expand Down Expand Up @@ -140,6 +149,25 @@ export class Vector3Builder implements Vector3 {
clamp(limits: { min?: Partial<Vector3>; max?: Partial<Vector3> }): this {
return this.assign(Vector3Utils.clamp(this, limits));
}


/**
* lerp
*
* Constructs a new vector using linear interpolation on each component from two vectors.
*/
lerp(vec: Vector3, t: number): this {
return this.assign(Vector3Utils.lerp(this, vec, t));
}

/**
* slerp
*
* Constructs a new vector using spherical linear interpolation on each component from two vectors.
*/
slerp(vec: Vector3, t: number): this {
return this.assign(Vector3Utils.slerp(this, vec, t));
}
}

/**
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 4b2923a

Please sign in to comment.