From 061d45f6fd447110c9193c78424bcc5ce2aa36cf Mon Sep 17 00:00:00 2001 From: robonen Date: Mon, 30 Sep 2024 06:19:16 +0700 Subject: [PATCH] =?UTF-8?q?refactor(packages/stdlib):=20separate=20math=20?= =?UTF-8?q?utils=20=D1=88=D1=82=D0=B5=D1=89=20basic=20and=20bigint=20versi?= =?UTF-8?q?ons?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/math/{ => basic}/clamp/index.test.ts | 0 packages/stdlib/src/math/basic/clamp/index.ts | 13 ++++ .../stdlib/src/math/basic/lerp/index.test.ts | 61 +++++++++++++++++++ packages/stdlib/src/math/basic/lerp/index.ts | 27 ++++++++ .../stdlib/src/math/basic/remap/index.test.ts | 46 ++++++++++++++ .../math/{mapRange => basic/remap}/index.ts | 14 ++--- packages/stdlib/src/math/clamp/index.ts | 16 ----- .../stdlib/src/math/mapRange/index.test.ts | 46 -------------- 8 files changed, 154 insertions(+), 69 deletions(-) rename packages/stdlib/src/math/{ => basic}/clamp/index.test.ts (100%) create mode 100644 packages/stdlib/src/math/basic/clamp/index.ts create mode 100644 packages/stdlib/src/math/basic/lerp/index.test.ts create mode 100644 packages/stdlib/src/math/basic/lerp/index.ts create mode 100644 packages/stdlib/src/math/basic/remap/index.test.ts rename packages/stdlib/src/math/{mapRange => basic/remap}/index.ts (52%) delete mode 100644 packages/stdlib/src/math/clamp/index.ts delete mode 100644 packages/stdlib/src/math/mapRange/index.test.ts diff --git a/packages/stdlib/src/math/clamp/index.test.ts b/packages/stdlib/src/math/basic/clamp/index.test.ts similarity index 100% rename from packages/stdlib/src/math/clamp/index.test.ts rename to packages/stdlib/src/math/basic/clamp/index.test.ts diff --git a/packages/stdlib/src/math/basic/clamp/index.ts b/packages/stdlib/src/math/basic/clamp/index.ts new file mode 100644 index 0000000..bd57a9c --- /dev/null +++ b/packages/stdlib/src/math/basic/clamp/index.ts @@ -0,0 +1,13 @@ +/** + * Clamps a number between a minimum and maximum value + * + * @param {number} value The number to clamp + * @param {number} min Minimum value + * @param {number} max Maximum value + * @returns {number} The clamped number + * + * @since 0.0.1 + */ +export function clamp(value: number, min: number, max: number) { + return Math.min(Math.max(value, min), max); +} diff --git a/packages/stdlib/src/math/basic/lerp/index.test.ts b/packages/stdlib/src/math/basic/lerp/index.test.ts new file mode 100644 index 0000000..0e0dd74 --- /dev/null +++ b/packages/stdlib/src/math/basic/lerp/index.test.ts @@ -0,0 +1,61 @@ +import {describe, it, expect} from 'vitest'; +import {inverseLerp, lerp} from './index'; + +describe('lerp', () => { + it('interpolates between two values', () => { + const result = lerp(0, 10, 0.5); + expect(result).toBe(5); + }); + + it('returns start value when t is 0', () => { + const result = lerp(0, 10, 0); + expect(result).toBe(0); + }); + + it('returns end value when t is 1', () => { + const result = lerp(0, 10, 1); + expect(result).toBe(10); + }); + + it('handles negative interpolation values', () => { + const result = lerp(0, 10, -0.5); + expect(result).toBe(-5); + }); + + it('handles interpolation values greater than 1', () => { + const result = lerp(0, 10, 1.5); + expect(result).toBe(15); + }); +}); + +describe('inverseLerp', () => { + it('returns 0 when value is start', () => { + const result = inverseLerp(0, 10, 0); + expect(result).toBe(0); + }); + + it('returns 1 when value is end', () => { + const result = inverseLerp(0, 10, 10); + expect(result).toBe(1); + }); + + it('interpolates correctly between two values', () => { + const result = inverseLerp(0, 10, 5); + expect(result).toBe(0.5); + }); + + it('handles values less than start', () => { + const result = inverseLerp(0, 10, -5); + expect(result).toBe(-0.5); + }); + + it('handles values greater than end', () => { + const result = inverseLerp(0, 10, 15); + expect(result).toBe(1.5); + }); + + it('handles same start and end values', () => { + const result = inverseLerp(10, 10, 10); + expect(result).toBe(0); + }); +}); diff --git a/packages/stdlib/src/math/basic/lerp/index.ts b/packages/stdlib/src/math/basic/lerp/index.ts new file mode 100644 index 0000000..42cf4e3 --- /dev/null +++ b/packages/stdlib/src/math/basic/lerp/index.ts @@ -0,0 +1,27 @@ +/** + * Linearly interpolates between two values + * + * @param {number} start The start value + * @param {number} end The end value + * @param {number} t The interpolation value + * @returns {number} The interpolated value + * + * @since 0.0.2 + */ +export function lerp(start: number, end: number, t: number) { + return start + t * (end - start); +} + +/** + * Inverse linear interpolation between two values + * + * @param {number} start The start value + * @param {number} end The end value + * @param {number} value The value to interpolate + * @returns {number} The interpolated value + * + * @since 0.0.2 + */ +export function inverseLerp(start: number, end: number, value: number) { + return start === end ? 0 : (value - start) / (end - start); +} diff --git a/packages/stdlib/src/math/basic/remap/index.test.ts b/packages/stdlib/src/math/basic/remap/index.test.ts new file mode 100644 index 0000000..0597f80 --- /dev/null +++ b/packages/stdlib/src/math/basic/remap/index.test.ts @@ -0,0 +1,46 @@ +import {describe, expect, it} from 'vitest'; +import {remap} from './index'; + +describe('remap', () => { + it('map values from one range to another', () => { + // value at midpoint + expect(remap(5, 0, 10, 0, 100)).toBe(50); + + // value at min + expect(remap(0, 0, 10, 0, 100)).toBe(0); + + // value at max + expect(remap(10, 0, 10, 0, 100)).toBe(100); + + // value outside range (below) + expect(remap(-5, 0, 10, 0, 100)).toBe(0); + + // value outside range (above) + expect(remap(15, 0, 10, 0, 100)).toBe(100); + + // value at midpoint of negative range + expect(remap(75, 50, 100, -50, 50)).toBe(0); + + // value at midpoint of negative range + expect(remap(-25, -50, 0, 0, 100)).toBe(50); + }); + + it('handle floating-point numbers correctly', () => { + // floating-point value + expect(remap(3.5, 0, 10, 0, 100)).toBe(35); + + // positive floating-point ranges + expect(remap(1.25, 0, 2.5, 0, 100)).toBe(50); + + // negative floating-point value + expect(remap(-2.5, -5, 0, 0, 100)).toBe(50); + + // negative floating-point ranges + expect(remap(-1.25, -2.5, 0, 0, 100)).toBe(50); + }); + + it('handle edge cases', () => { + // input range is zero (should return output min) + expect(remap(5, 0, 0, 0, 100)).toBe(0); + }); +}); \ No newline at end of file diff --git a/packages/stdlib/src/math/mapRange/index.ts b/packages/stdlib/src/math/basic/remap/index.ts similarity index 52% rename from packages/stdlib/src/math/mapRange/index.ts rename to packages/stdlib/src/math/basic/remap/index.ts index f82dd41..c2dbc83 100644 --- a/packages/stdlib/src/math/mapRange/index.ts +++ b/packages/stdlib/src/math/basic/remap/index.ts @@ -1,4 +1,5 @@ -import { clamp } from "../clamp"; +import { clamp } from '../clamp'; +import {inverseLerp, lerp} from '../lerp'; /** * Map a value from one range to another @@ -9,15 +10,14 @@ import { clamp } from "../clamp"; * @param {number} out_min The minimum value of the output range * @param {number} out_max The maximum value of the output range * @returns {number} The mapped value + * + * @since 0.0.1 */ -export function mapRange(value: number, in_min: number, in_max: number, out_min: number, out_max: number): number { - // Zero input range means invalid input, so return lowest output range value +export function remap(value: number, in_min: number, in_max: number, out_min: number, out_max: number) { if (in_min === in_max) return out_min; - - // To ensure the value is within the input range, clamp it + const clampedValue = clamp(value, in_min, in_max); - // Finally, map the value from the input range to the output range - return (clampedValue - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; + return lerp(out_min, out_max, inverseLerp(in_min, in_max, clampedValue)); } \ No newline at end of file diff --git a/packages/stdlib/src/math/clamp/index.ts b/packages/stdlib/src/math/clamp/index.ts deleted file mode 100644 index b8532eb..0000000 --- a/packages/stdlib/src/math/clamp/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Clamps a number between a minimum and maximum value - * - * @param {number} value The number to clamp - * @param {number} min Minimum value - * @param {number} max Maximum value - * @returns {number} The clamped number - */ -export function clamp(value: number, min: number, max: number): number { - // The clamp function takes a value, a minimum, and a maximum as parameters. - // It ensures that the value falls within the range defined by the minimum and maximum values. - // If the value is less than the minimum, it returns the minimum value. - // If the value is greater than the maximum, it returns the maximum value. - // Otherwise, it returns the original value. - return Math.min(Math.max(value, min), max); -} diff --git a/packages/stdlib/src/math/mapRange/index.test.ts b/packages/stdlib/src/math/mapRange/index.test.ts deleted file mode 100644 index 17a4292..0000000 --- a/packages/stdlib/src/math/mapRange/index.test.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { mapRange } from './index'; - -describe('mapRange', () => { - it('map values from one range to another', () => { - // value at midpoint - expect(mapRange(5, 0, 10, 0, 100)).toBe(50); - - // value at min - expect(mapRange(0, 0, 10, 0, 100)).toBe(0); - - // value at max - expect(mapRange(10, 0, 10, 0, 100)).toBe(100); - - // value outside range (below) - expect(mapRange(-5, 0, 10, 0, 100)).toBe(0); - - // value outside range (above) - expect(mapRange(15, 0, 10, 0, 100)).toBe(100); - - // value at midpoint of negative range - expect(mapRange(75, 50, 100, -50, 50)).toBe(0); - - // value at midpoint of negative range - expect(mapRange(-25, -50, 0, 0, 100)).toBe(50); - }); - - it('handle floating-point numbers correctly', () => { - // floating-point value - expect(mapRange(3.5, 0, 10, 0, 100)).toBe(35); - - // positive floating-point ranges - expect(mapRange(1.25, 0, 2.5, 0, 100)).toBe(50); - - // negative floating-point value - expect(mapRange(-2.5, -5, 0, 0, 100)).toBe(50); - - // negative floating-point ranges - expect(mapRange(-1.25, -2.5, 0, 0, 100)).toBe(50); - }); - - it('handle edge cases', () => { - // input range is zero (should return output min) - expect(mapRange(5, 0, 0, 0, 100)).toBe(0); - }); -}); \ No newline at end of file