import { Point } from "./point.js";
/**
* Utility helpers for math, easing, and index conversions.
* @class
*/
class Utils {
/**
* Remaps a number from one range to another.
* @param {number} value the number to remap
* @param {number} old_min the lower bound of the value's current range
* @param {number} old_max the upper bound of the value's current range
* @param {number} new_min the lower bound of the value's target range
* @param {number} new_max the upper bound of the value's target range
* @returns {number} remapped value
*/
static remap(value, old_min, old_max, new_min, new_max) {
return (
new_min + ((value - old_min) * (new_max - new_min)) / (old_max - old_min)
);
}
/**
* Clamps a number between a minimum and maximum value.
* @param {number} value the number to clamp
* @param {number} min the minimum value
* @param {number} max the maximum value
* @returns {number} clamped value
*/
static clamp(value, min, max) {
return Math.min(Math.max(value, min), max);
}
/**
* Wraps a value into the range [min, max).
* @param {number} value the number to wrap
* @param {number} min the inclusive lower bound
* @param {number} max the exclusive upper bound
* @returns {number} wrapped value
*/
static wrap(value, min, max) {
if (min >= max) throw new Error("Utils: min must be less than max");
const range = max - min;
return ((((value - min) % range) + range) % range) + min;
}
/**
* Linearly interpolates between two values.
* @param {number} a start value
* @param {number} b end value
* @param {number} t interpolation factor in range [0, 1]
* @returns {number} interpolated value
*/
static lerp(a, b, t) {
if (t < 0 || t > 1)
throw new Error("Utils: interpolation factor must be in range [0, 1]");
return a + (b - a) * t;
}
/**
* Polynomial easing in out function. Returns a number in range [0, 1].
* @param {number} t input number in range [0, 1]
* @param {number} n power of the easing function. Default is 2 (quadratic easing)
* @returns {number} eased value
*/
static ease_in_out_poly(t, n = 2) {
if (t < 0 || t > 1) throw new Error("Utils: input must be in range [0, 1]");
if (t < 0.5) return (2 * t) ** n / 2;
return 1 - (-2 * t + 2) ** n / 2;
}
/**
* Polynomial easing in function. Returns a number in range [0, 1].
* @param {number} t input number in range [0, 1]
* @param {number} n power of the easing function. Default is 2 (quadratic easing)
* @returns {number} eased value
*/
static ease_in_poly(t, n = 2) {
if (t < 0 || t > 1) throw new Error("Utils: input must be in range [0, 1]");
return t ** n;
}
static ease_out_poly(t, n = 2) {
if (t < 0 || t > 1) throw new Error("Utils: input must be in range [0, 1]");
return 1 - (1 - t) ** n;
}
/**
* Sinusoidal easing in-out function. Returns a number in range [0, 1].
* @param {number} t input number in range [0, 1]
* @returns {number} eased value
*/
static ease_in_out_sin(t) {
if (t < 0 || t > 1) throw new Error("Utils: input must be in range [0, 1]");
return Math.sin((t * Math.PI) / 2);
}
/**
* Sinusoidal easing in function. Returns a number in range [0, 1].
* @param {number} t input number in range [0, 1]
* @returns {number} eased value
*/
static ease_in_sin(t) {
if (t < 0 || t > 1) throw new Error("Utils: input must be in range [0, 1]");
return 1 - Math.cos((t * Math.PI) / 2);
}
/**
* Sinusoidal easing out function. Returns a number in range [0, 1].
* @param {number} t input number in range [0, 1]
* @returns {number} eased value
*/
static ease_out_sin(t) {
if (t < 0 || t > 1) throw new Error("Utils: input must be in range [0, 1]");
return Math.sin((t * Math.PI) / 2);
}
/**
* Exponential easing in-out function. Returns a number in range [0, 1].
* @param {number} t input number in range [0, 1]
* @returns {number} eased value
*/
static ease_in_out_exp(t) {
if (t < 0 || t > 1) throw new Error("Utils: input must be in range [0, 1]");
if (t === 0) return 0;
if (t === 1) return 1;
if (t < 0.5) return 2 ** (20 * t - 10) / 2;
return (2 - 2 ** (-20 * t + 10)) / 2;
}
/**
* Exponential easing in function. Returns a number in range [0, 1].
* @param {number} t input number in range [0, 1]
* @returns {number} eased value
*/
static ease_in_exp(t) {
if (t < 0 || t > 1) throw new Error("Utils: input must be in range [0, 1]");
if (t === 0) return 0;
return 2 ** (10 * t - 10);
}
/**
* Exponential easing out function. Returns a number in range [0, 1].
* @param {number} t input number in range [0, 1]
* @returns {number} eased value
*/
static ease_out_exp(t) {
if (t < 0 || t > 1) throw new Error("Utils: input must be in range [0, 1]");
if (t === 1) return 1;
return 1 - 2 ** (-10 * t);
}
/**
* Converts a linear index to 2D coordinates.
* @param {number} i linear index
* @param {number} width row width
* @returns {number[]} tuple of [x, y]
*/
static i_to_xy(i, width) {
const x = i % width;
const y = Math.floor(i / width);
return [x, y];
}
/**
* Converts 2D coordinates to a linear index.
* @param {number} x x coordinate
* @param {number} y y coordinate
* @param {number} width row width
* @returns {number} linear index
*/
static xy_to_i(x, y, width) {
return y * width + x;
}
/**
* Converts a linear index to a Point instance.
* @param {number} i linear index
* @param {number} width row width
* @returns {Point} point at the computed coordinates
*/
static i_to_point(i, width) {
const [x, y] = Utils.i_to_xy(i, width);
return new Point(x, y);
}
/**
* Converts a Point instance to a linear index.
* @param {Point} point point to convert
* @param {number} width row width
* @returns {number} linear index
*/
static point_to_i(point, width) {
return Utils.xy_to_i(point.x, point.y, width);
}
}
export { Utils };