@inglorious/utils
Version:
A set of general-purpose utility functions designed with functional programming principles in mind.
346 lines (265 loc) • 9.73 kB
JavaScript
import { expect, test } from "vitest"
import { v } from "../v.js"
import { sqrt } from "./numbers.js"
import { cos, pi, sin } from "./trigonometry.js"
import {
abs,
angle,
clamp,
conjugate,
createVector,
divide,
divideBy,
from2D,
fromAngle,
isVector,
magnitude,
mod,
modOf,
multiply,
normalize,
power,
powerOf,
rotate,
setAngle,
setMagnitude,
shift,
snap,
to2D,
toCartesian,
toCylindrical,
toPolar,
toSpherical,
toString,
unit,
zero,
} from "./vector.js"
test("it should compute the absolute value of a vector's coordinates", () => {
const vector = v(-2, 0, 3)
const expectedResult = v(2, 0, 3)
expect(abs(vector)).toStrictEqual(expectedResult)
})
test("it should compute the angle of a 2D vector", () => {
const vector = v(1, 1)
const expectedResult = pi() / 4
expect(angle(vector)).toBe(expectedResult)
})
test("it should compute the angle of a 3D vector", () => {
const vector = v(1, 0, 1)
const expectedResult = pi() / 4
expect(angle(vector)).toBe(expectedResult)
})
test("it should clamp the magnitude of a vector to a certain length if too long", () => {
const vector = v(6, 8)
const min = 0
const max = 5
const expectedResult = v(3, 4)
expect(clamp(vector, min, max)).toStrictEqual(expectedResult)
})
test("it should not clamp the magnitude of a vector to a certain length if not too long", () => {
const vector = v(3, 4)
const min = 0
const max = 6
const expectedResult = v(3, 4)
expect(clamp(vector, min, max)).toStrictEqual(expectedResult)
})
test("it should clamp the magnitude of a vector to the values of other vector bounds", () => {
const vector = v(6, 8)
const lowerBound = [0, 0]
const upperBound = [3, 4]
const expectedResult = v(3, 4)
expect(clamp(vector, lowerBound, upperBound)).toStrictEqual(expectedResult)
})
test("it should conjugate a vector", () => {
const vector = v(1, 2, 3)
const expectedResult = v(1, -2, -3)
expect(conjugate(vector)).toStrictEqual(expectedResult)
})
test("it should create a 3D vector given its magnitude and angle", () => {
const magnitude = sqrt(2)
const angle = pi() / 4
const expectedResult = v(1, -0, 1.0000000000000002) // close to v(1, 0, 1)
expect(createVector(magnitude, angle)).toStrictEqual(expectedResult)
})
test("it should divide a vector by a scalar", () => {
const vector = v(4, 8, 12)
const scalar = 4
const expectedResult = v(1, 2, 3)
expect(divide(vector, scalar)).toStrictEqual(expectedResult)
})
test("it should divide a scalar by a vector", () => {
const scalar = 12
const vector = v(4, 8, 12)
const expectedResult = v(3, 1.5, 1)
expect(divideBy(scalar, vector)).toStrictEqual(expectedResult)
})
test("it should build a 3D vector from a 2D one", () => {
const vector = v(3, 4)
const expectedResult = v(3, 0, 4)
expect(from2D(vector)).toStrictEqual(expectedResult)
})
test("it should create a 3D unit vector from an angle", () => {
const angle = pi() / 4
const expectedResult = v(0.7071067811865475, -0, 0.7071067811865476) // close to [cos(angle), 0, sin(angle)]
expect(fromAngle(angle)).toStrictEqual(expectedResult)
})
test("it should compute the magnitude of a vector (aka length)", () => {
const vector = v(3, 4)
const expectedResult = 5
expect(magnitude(vector)).toBe(expectedResult)
})
test("it should check if a value is a vector", () => {
expect(isVector([1, 2, 3])).toBe(false)
expect(isVector(v(1, 2, 3))).toBe(true)
})
test("it should check if a value is not a vector", () => {
expect(isVector([1, "a", 3])).toBe(false)
expect(isVector({ x: 1, y: 2 })).toBe(false)
expect(isVector(null)).toBe(false)
expect(isVector("vector")).toBe(false)
expect(isVector(123)).toBe(false)
})
test("it should apply the mod operator (aka remainder) on a vector", () => {
const vector = v(10, 12, -18)
const divisor = 12
const expectedResult = v(10, 0, 6)
expect(mod(vector, divisor)).toStrictEqual(expectedResult)
})
test("it should apply the mod operator of a scalar with a vector", () => {
const scalar = 18
const vector = v(10, 12, -18)
const expectedResult = v(8, 6, -0)
expect(modOf(scalar, vector)).toStrictEqual(expectedResult)
})
test("it should multiply a vector with a scalar (aka times)", () => {
const vector = v(1, 2, 3)
const scalar = 4
const expectedResult = v(4, 8, 12)
expect(multiply(vector, scalar)).toStrictEqual(expectedResult)
})
test("it should normalize a vector so it has unit length", () => {
const vector = v(3, 4)
const expectedResult = v(0.6, 0.8)
expect(normalize(vector)).toStrictEqual(expectedResult)
})
test("it should normalize a negative vector", () => {
const vector = v(-3, -4)
const expectedResult = v(-0.6, -0.8)
expect(normalize(vector)).toStrictEqual(expectedResult)
})
test("it should raise each component of a vector to the given exponent (aka pow)", () => {
const vector = v(1, 2, 3)
const exponent = 2
const expectedResult = v(1, 4, 9)
expect(power(vector, exponent)).toStrictEqual(expectedResult)
})
test("it should raise a scalar to the power of each component of a vector", () => {
const scalar = 2
const vector = v(1, 2, 3)
const expectedResult = v(2, 4, 8)
expect(powerOf(scalar, vector)).toStrictEqual(expectedResult)
})
test("it should rotate a 2D vector by a certain angle", () => {
const vector = v(1, 0)
const angle = pi() / 4
const expectedResult = v(0.7071067811865475, 0.7071067811865476) // close to [cos(pi/4), sin(pi/4)]
expect(rotate(vector, angle)).toStrictEqual(expectedResult)
})
test("it should not rotate a vector when the angle is zero", () => {
const vector = v(1, 0, 0)
const angle = 0
const expectedResult = v(1, 0, 0)
expect(rotate(vector, angle)).toStrictEqual(expectedResult)
})
test("it should rotate a vector by a certain angle", () => {
const vector = v(1, 0, 0)
const angle = pi() / 4
const expectedResult = v(0.7071067811865475, -0, 0.7071067811865476) // close to [cos(pi/4), 0, sin(pi/4)]
expect(rotate(vector, angle)).toStrictEqual(expectedResult)
})
test("it should rotate a vector that faces left by a certain angle", () => {
const vector = v(-1, 0, 0)
const angle = pi() / 4
const expectedResult = v(-0.7071067811865475, -0, -0.7071067811865476) // close to [cos(-3/4pi), 0, sin(-3/4pi)]
expect(rotate(vector, angle)).toStrictEqual(expectedResult)
})
test("it should change the angle of a vector", () => {
const vector = v(cos(pi() / 4), 0, sin(pi() / 4))
const expectedResult = v(6.123233995736766e-17, 0, 1) // close to v(0, 0, 1)
expect(setAngle(vector, 1.5707963267948966)).toStrictEqual(expectedResult)
})
test("it should change magnitude of a vector (aka setLength)", () => {
const vector = v(3, 4)
const magnitude = 10
const expectedResult = v(6, 8)
expect(setMagnitude(vector, magnitude)).toStrictEqual(expectedResult)
})
test("it should change magnitude of a negative vector", () => {
const vector = v(-3, -4)
const magnitude = 10
const expectedResult = v(-6, -8)
expect(setMagnitude(vector, magnitude)).toStrictEqual(expectedResult)
})
test("it should shift a vector at a certain index", () => {
const vector = v(1, 2, 3, 4, 5)
const index = 2
const expectedResult = v(3, 4, 5, 1, 2)
expect(shift(vector, index)).toStrictEqual(expectedResult)
})
test("it should snap a floating vector to a certain precision", () => {
const vector = v(1, 1.5, 1.7)
const precision = 1
const expectedResult = v(1, 1, 2)
expect(snap(vector, precision)).toStrictEqual(expectedResult)
})
test("it should build a 2D vector from a 3D one", () => {
const vector = v(3, 0, 4)
const expectedResult = v(3, 4)
expect(to2D(vector)).toStrictEqual(expectedResult)
})
test("it should convert a 2D polar vector to cartesian coordinates", () => {
const vector = v(sqrt(2), pi() / 4)
const expectedResult = v(1.0000000000000002, 1)
expect(toCartesian(vector)).toStrictEqual(expectedResult)
})
test("it should convert a 3D cartesian vector to cylindrical coordinates", () => {
const vector = v(1, 1, 1)
const expectedResult = v(1.2247448713915892, 1.224744871391589, 1)
expect(toCylindrical(vector)).toStrictEqual(expectedResult)
})
test("it should convert a 2D cartesian vector to polar coordinates", () => {
const vector = v(1, 1)
const expectedResult = v(sqrt(2), pi() / 4)
expect(toPolar(vector)).toStrictEqual(expectedResult)
})
test("it should convert a 3D cartesian vector to spherical coordinates", () => {
const vector = v(1, 1, 1)
const expectedResult = v(sqrt(3), Math.acos(1 / sqrt(3)), pi() / 4)
expect(toSpherical(vector)).toStrictEqual(expectedResult)
})
test("it should create a string representation of an integer vector", () => {
const vector = v(3, 4)
const expectedResult = "[3, 4]"
expect(toString(vector)).toBe(expectedResult)
})
test("it should create a string representation of a float vector", () => {
const vector = v(pi() / 4, pi() / 4)
const decimals = 2
const expectedResult = "[0.79, 0.79]"
expect(toString(vector, decimals)).toBe(expectedResult)
})
test("it should create a unit vector oriented on the X-axis", () => {
expect(unit()).toStrictEqual(v(1, 0, 0))
})
test("it should create a unit vector oriented on the Z-axis", () => {
expect(unit(pi() / 2)).toStrictEqual(v(6.123233995736766e-17, 0, 1)) // close to v(0, 0, 1)
})
test("it should create a vector from a list of coordinates", () => {
expect(v(1, 2, 3)).toStrictEqual([1, 2, 3])
expect(v()).toStrictEqual([])
expect(v(0, -5.5)).toStrictEqual([0, -5.5])
})
test("it should create a 3D zero vector", () => {
const expectedResult = v(0, 0, 0)
expect(zero()).toStrictEqual(expectedResult)
})