Socket
Socket
Sign inDemoInstall

@thi.ng/math

Package Overview
Dependencies
Maintainers
1
Versions
160
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@thi.ng/math - npm Package Compare versions

Comparing version 5.7.6 to 5.7.7

8

abs.js
import { EPS } from "./api.js";
export const absDiff = (x, y) => Math.abs(x - y);
export const sign = (x, eps = EPS) => (x > eps ? 1 : x < -eps ? -1 : 0);
const absDiff = (x, y) => Math.abs(x - y);
const sign = (x, eps = EPS) => x > eps ? 1 : x < -eps ? -1 : 0;
export {
absDiff,
sign
};
import { DEG2RAD, HALF_PI, INV_HALF_PI, PI, RAD2DEG, TAU } from "./api.js";
/**
* Returns vector of `[sin(theta)*n, cos(theta)*n]`.
*
* @param theta -
* @param n -
*/
export const sincos = (theta, n = 1) => [
Math.sin(theta) * n,
Math.cos(theta) * n,
const sincos = (theta, n = 1) => [
Math.sin(theta) * n,
Math.cos(theta) * n
];
/**
* Returns vector of `[cos(theta)*n, sin(theta)*n]`.
*
* @param theta -
* @param n -
*/
export const cossin = (theta, n = 1) => [
Math.cos(theta) * n,
Math.sin(theta) * n,
const cossin = (theta, n = 1) => [
Math.cos(theta) * n,
Math.sin(theta) * n
];
/**
* Projects `theta` into [0 .. 2π] interval.
*
* @param theta -
*/
export const absTheta = (theta) => ((theta %= TAU), theta < 0 ? TAU + theta : theta);
export const absInnerAngle = (theta) => ((theta = Math.abs(theta)), theta > PI ? TAU - theta : theta);
/**
* Returns smallest absolute angle difference between `a` and `b`.
* Result will be in [0 .. π] interval.
*
* @param a -
* @param b -
*/
export const angleDist = (a, b) => absInnerAngle(absTheta((b % TAU) - (a % TAU)));
/**
* Like `Math.atan2`, but always returns angle in [0 .. TAU) interval.
*
* @param y -
* @param x -
*/
export const atan2Abs = (y, x) => absTheta(Math.atan2(y, x));
/**
* Returns quadrant ID (0-3) of given angle (in radians).
*
* @param theta -
*/
export const quadrant = (theta) => (absTheta(theta) * INV_HALF_PI) | 0;
/**
* Converts angle to degrees.
*
* @param theta - angle in radians
*/
export const deg = (theta) => theta * RAD2DEG;
/**
* Converts angle to radians.
*
* @param theta - angle in degrees
*/
export const rad = (theta) => theta * DEG2RAD;
/**
* Cosecant. Approaches `±Infinity` for `theta` near multiples of π.
*
* @param theta - angle in radians
*/
export const csc = (theta) => 1 / Math.sin(theta);
/**
* Secant. Approaches `±Infinity` for `theta` near π/2 ± nπ
*
* @param theta - angle in radians
*/
export const sec = (theta) => 1 / Math.cos(theta);
/**
* Cotangent. Approaches `±Infinity` for `theta` near multiples of π.
*
* @param theta - angle in radians
*/
export const cot = (theta) => 1 / Math.tan(theta);
/**
* Law of Cosines. Takes length of two sides of a triangle and the inner
* angle (in radians) between them. Returns length of third side.
*
* @param a -
* @param b -
* @param gamma -
*/
export const loc = (a, b, gamma) => Math.sqrt(a * a + b * b - 2 * a * b * Math.cos(gamma));
/**
* Approximates cos(xπ) for x in [-1,1]
*
* @param x -
*/
export const normCos = (x) => {
const x2 = x * x;
return 1.0 + x2 * (-4 + 2 * x2);
const absTheta = (theta) => (theta %= TAU, theta < 0 ? TAU + theta : theta);
const absInnerAngle = (theta) => (theta = Math.abs(theta), theta > PI ? TAU - theta : theta);
const angleDist = (a, b) => absInnerAngle(absTheta(b % TAU - a % TAU));
const atan2Abs = (y, x) => absTheta(Math.atan2(y, x));
const quadrant = (theta) => absTheta(theta) * INV_HALF_PI | 0;
const deg = (theta) => theta * RAD2DEG;
const rad = (theta) => theta * DEG2RAD;
const csc = (theta) => 1 / Math.sin(theta);
const sec = (theta) => 1 / Math.cos(theta);
const cot = (theta) => 1 / Math.tan(theta);
const loc = (a, b, gamma) => Math.sqrt(a * a + b * b - 2 * a * b * Math.cos(gamma));
const normCos = (x) => {
const x2 = x * x;
return 1 + x2 * (-4 + 2 * x2);
};
const __fastCos = (x) => {
const x2 = x * x;
return 0.99940307 + x2 * (-0.49558072 + 0.03679168 * x2);
const x2 = x * x;
return 0.99940307 + x2 * (-0.49558072 + 0.03679168 * x2);
};
/**
* Fast cosine approximation using {@link normCos} (polynomial). Max. error
* ~0.00059693
*
* In [0 .. 2π] interval, approx. 18-20% faster than `Math.cos` on V8.
*
* @param theta - in radians
*/
export const fastCos = (theta) => {
theta %= TAU;
theta < 0 && (theta = -theta);
switch ((theta * INV_HALF_PI) | 0) {
case 0:
return __fastCos(theta);
case 1:
return -__fastCos(PI - theta);
case 2:
return -__fastCos(theta - PI);
default:
return __fastCos(TAU - theta);
}
const fastCos = (theta) => {
theta %= TAU;
theta < 0 && (theta = -theta);
switch (theta * INV_HALF_PI | 0) {
case 0:
return __fastCos(theta);
case 1:
return -__fastCos(PI - theta);
case 2:
return -__fastCos(theta - PI);
default:
return __fastCos(TAU - theta);
}
};
/**
* {@link fastCos}
*
* @param theta - in radians
*/
export const fastSin = (theta) => fastCos(HALF_PI - theta);
const fastSin = (theta) => fastCos(HALF_PI - theta);
export {
absInnerAngle,
absTheta,
angleDist,
atan2Abs,
cossin,
cot,
csc,
deg,
fastCos,
fastSin,
loc,
normCos,
quadrant,
rad,
sec,
sincos
};

@@ -1,20 +0,42 @@

export const PI = Math.PI;
export const TAU = PI * 2;
export const HALF_PI = PI / 2;
export const THIRD_PI = PI / 3;
export const QUARTER_PI = PI / 4;
export const SIXTH_PI = PI / 6;
export const INV_PI = 1 / PI;
export const INV_TAU = 1 / TAU;
export const INV_HALF_PI = 1 / HALF_PI;
export const DEG2RAD = PI / 180;
export const RAD2DEG = 180 / PI;
export const PHI = (1 + Math.sqrt(5)) / 2;
export const SQRT2 = Math.SQRT2;
export const SQRT3 = Math.sqrt(3);
export const SQRT2_2 = SQRT2 / 2;
export const SQRT3_2 = SQRT3 / 2;
export const THIRD = 1 / 3;
export const TWO_THIRD = 2 / 3;
export const SIXTH = 1 / 6;
export let EPS = 1e-6;
const PI = Math.PI;
const TAU = PI * 2;
const HALF_PI = PI / 2;
const THIRD_PI = PI / 3;
const QUARTER_PI = PI / 4;
const SIXTH_PI = PI / 6;
const INV_PI = 1 / PI;
const INV_TAU = 1 / TAU;
const INV_HALF_PI = 1 / HALF_PI;
const DEG2RAD = PI / 180;
const RAD2DEG = 180 / PI;
const PHI = (1 + Math.sqrt(5)) / 2;
const SQRT2 = Math.SQRT2;
const SQRT3 = Math.sqrt(3);
const SQRT2_2 = SQRT2 / 2;
const SQRT3_2 = SQRT3 / 2;
const THIRD = 1 / 3;
const TWO_THIRD = 2 / 3;
const SIXTH = 1 / 6;
let EPS = 1e-6;
export {
DEG2RAD,
EPS,
HALF_PI,
INV_HALF_PI,
INV_PI,
INV_TAU,
PHI,
PI,
QUARTER_PI,
RAD2DEG,
SIXTH,
SIXTH_PI,
SQRT2,
SQRT2_2,
SQRT3,
SQRT3_2,
TAU,
THIRD,
THIRD_PI,
TWO_THIRD
};
# Change Log
- **Last updated**: 2023-12-09T19:12:03Z
- **Last updated**: 2023-12-11T10:07:09Z
- **Generator**: [thi.ng/monopub](https://thi.ng/monopub)

@@ -5,0 +5,0 @@

import { EPS } from "./api.js";
import { eqDelta } from "./eqdelta.js";
/**
* Returns true if line A rises up over B.
*
* @example
* ```ts
* b1 a2
* \/
* /\
* a1 b2
* ```
*
* @param a1 -
* @param a2 -
* @param b1 -
* @param b2 -
*/
export const isCrossOver = (a1, a2, b1, b2) => a1 < b1 && a2 > b2;
/**
* Returns true if line A rises up over B.
*
* @example
* ```ts
* a1 b2
* \/
* /\
* b1 a2
* ```
*
* @param a1 -
* @param a2 -
* @param b1 -
* @param b2 -
*/
export const isCrossUnder = (a1, a2, b1, b2) => a1 > b1 && a2 < b2;
/**
* Returns {@link Crossing} classifier indicating the relationship of line A
* to line B. The optional epsilon value is used to determine if both
* lines are considered equal or flat.
*
* - {@link isCrossOver}
* - {@link isCrossUnder}
* - {@link Crossing}
*
* @param a1 -
* @param a2 -
* @param b1 -
* @param b2 -
* @param eps -
*/
export const classifyCrossing = (a1, a2, b1, b2, eps = EPS) => eqDelta(a1, b1, eps) && eqDelta(a2, b2, eps)
? eqDelta(a1, b2, eps)
? "flat"
: "equal"
: isCrossOver(a1, a2, b1, b2)
? "over"
: isCrossUnder(a1, a2, b1, b2)
? "under"
: "other";
const isCrossOver = (a1, a2, b1, b2) => a1 < b1 && a2 > b2;
const isCrossUnder = (a1, a2, b1, b2) => a1 > b1 && a2 < b2;
const classifyCrossing = (a1, a2, b1, b2, eps = EPS) => eqDelta(a1, b1, eps) && eqDelta(a2, b2, eps) ? eqDelta(a1, b2, eps) ? "flat" : "equal" : isCrossOver(a1, a2, b1, b2) ? "over" : isCrossUnder(a1, a2, b1, b2) ? "under" : "other";
export {
classifyCrossing,
isCrossOver,
isCrossUnder
};
import { EPS } from "./api.js";
const abs = Math.abs;
const max = Math.max;
/**
* Similar to {@link eqDeltaScaled}, but uses given `eps` as is.
*
* @param a - left value
* @param b - right value
* @param eps - epsilon / tolerance, default `1e-6`
*/
export const eqDelta = (a, b, eps = EPS) => abs(a - b) <= eps;
/**
* Checks if `|a - b| <= ε` and adapts given epsilon value to the given
* arguments:
*
* ε is factored with the largest absolute value of `a` or `b` (but
* never lesser than the given `eps` value):
*
* `ε = ε * max(1, |a|, |b|)`
*
* @param a - left value
* @param b - right value
* @param eps - epsilon / tolerance, default `1e-6`
*/
export const eqDeltaScaled = (a, b, eps = EPS) => abs(a - b) <= eps * max(1, abs(a), abs(b));
const eqDelta = (a, b, eps = EPS) => abs(a - b) <= eps;
const eqDeltaScaled = (a, b, eps = EPS) => abs(a - b) <= eps * max(1, abs(a), abs(b));
export {
eqDelta,
eqDeltaScaled
};

@@ -1,74 +0,32 @@

/**
* Returns true if `b` is a local minima, i.e. iff a > b and b < c.
*
* @param a -
* @param b -
* @param c -
*/
export const isMinima = (a, b, c) => a > b && b < c;
/**
* Returns true if `b` is a local maxima, i.e. iff a < b and b > c.
*
* @param a -
* @param b -
* @param c -
*/
export const isMaxima = (a, b, c) => a < b && b > c;
const isMinima = (a, b, c) => a > b && b < c;
const isMaxima = (a, b, c) => a < b && b > c;
const index = (pred, values, from = 0, to = values.length) => {
to--;
for (let i = from + 1; i < to; i++) {
if (pred(values[i - 1], values[i], values[i + 1])) {
return i;
}
to--;
for (let i = from + 1; i < to; i++) {
if (pred(values[i - 1], values[i], values[i + 1])) {
return i;
}
return -1;
}
return -1;
};
/**
* Returns index of the first local & internal minima found in given
* `values` array, or -1 if no such minima exists. The search range can
* be optionally defined via semi-open [from, to) index interval.
*
* @param values -
* @param from -
* @param to -
*/
export const minimaIndex = (values, from = 0, to = values.length) => index(isMinima, values, from, to);
/**
* Returns index of the first local & internal maxima found in given
* `values` array, or -1 if no such maxima exists. The search range can
* be optionally defined via semi-open [from, to) index interval.
*
* @param values -
* @param from -
* @param to -
*/
export const maximaIndex = (values, from = 0, to = values.length) => index(isMaxima, values, from, to);
const minimaIndex = (values, from = 0, to = values.length) => index(isMinima, values, from, to);
const maximaIndex = (values, from = 0, to = values.length) => index(isMaxima, values, from, to);
function* indices(fn, vals, from = 0, to = vals.length) {
while (from < to) {
const i = fn(vals, from, to);
if (i < 0)
return;
yield i;
from = i + 1;
}
while (from < to) {
const i = fn(vals, from, to);
if (i < 0)
return;
yield i;
from = i + 1;
}
}
/**
* Returns an iterator yielding all minima indices in given `values`
* array. The search range can be optionally defined via semi-open
* [from, to) index interval.
*
* @param values -
* @param from -
* @param to -
*/
export const minimaIndices = (values, from = 0, to = values.length) => indices(minimaIndex, values, from, to);
/**
* Returns an iterator yielding all maxima indices in given `values`
* array. The search range can be optionally defined via semi-open
* [from, to) index interval.
*
* @param values -
* @param from -
* @param to -
*/
export const maximaIndices = (values, from = 0, to = values.length) => indices(minimaIndex, values, from, to);
const minimaIndices = (values, from = 0, to = values.length) => indices(minimaIndex, values, from, to);
const maximaIndices = (values, from = 0, to = values.length) => indices(minimaIndex, values, from, to);
export {
isMaxima,
isMinima,
maximaIndex,
maximaIndices,
minimaIndex,
minimaIndices
};
import { clamp01, clamp11 } from "./interval.js";
/**
* Returns normalized value of `x` WRT to interval `a .. b`. If `a`
* equals `b`, returns 0.
*
* @param x -
* @param a -
* @param b -
*/
export const norm = (x, a, b) => (b !== a ? (x - a) / (b - a) : 0);
/**
* Returns a number in the `[c,d]` interval which is relative to `x` in the
* `[a,b]` interval. **No** clamping will be performed if `x` lies outside the
* original range (for that use {@link fitClamped} instead).
*
* @param x
* @param a
* @param b
* @param c
* @param d
*/
export const fit = (x, a, b, c, d) => c + (d - c) * norm(x, a, b);
/**
* Clamped version of {@link fit}, i.e. before mapping `x` into the target
* interval `[c,d]`, it will be clamped to the source interval `[a,b]`.
*
* @param x
* @param a
* @param b
* @param c
* @param d
*/
export const fitClamped = (x, a, b, c, d) => c + (d - c) * clamp01(norm(x, a, b));
/**
* Similar to {@link fitClamped}, assuming [0,1] as source interval.
*
* @param x
* @param a
* @param b
*/
export const fit01 = (x, a, b) => a + (b - a) * clamp01(x);
/**
* Similar to {@link fitClamped}, assuming the reverse ordered [1,0] as source
* interval.
*
* @param x
* @param a
* @param b
*/
export const fit10 = (x, a, b) => b + (a - b) * clamp01(x);
/**
* Similar to {@link fitClamped}, assuming [-1,1] as source interval.
*
* @param x
* @param a
* @param b
*/
export const fit11 = (x, a, b) => a + (b - a) * (0.5 + 0.5 * clamp11(x));
const norm = (x, a, b) => b !== a ? (x - a) / (b - a) : 0;
const fit = (x, a, b, c, d) => c + (d - c) * norm(x, a, b);
const fitClamped = (x, a, b, c, d) => c + (d - c) * clamp01(norm(x, a, b));
const fit01 = (x, a, b) => a + (b - a) * clamp01(x);
const fit10 = (x, a, b) => b + (a - b) * clamp01(x);
const fit11 = (x, a, b) => a + (b - a) * (0.5 + 0.5 * clamp11(x));
export {
fit,
fit01,
fit10,
fit11,
fitClamped,
norm
};

@@ -1,64 +0,128 @@

const M8 = 0xff;
const M16 = 0xffff;
export const signExtend8 = (a) => ((a &= M8), a & 0x80 ? a | ~M8 : a);
export const signExtend16 = (a) => ((a &= M16), a & 0x8000 ? a | ~M16 : a);
export const addi8 = (a, b) => signExtend8((a | 0) + (b | 0));
export const divi8 = (a, b) => signExtend8((a | 0) / (b | 0));
export const muli8 = (a, b) => signExtend8((a | 0) * (b | 0));
export const subi8 = (a, b) => signExtend8((a | 0) - (b | 0));
export const andi8 = (a, b) => signExtend8((a | 0) & (b | 0));
export const ori8 = (a, b) => signExtend8(a | 0 | (b | 0));
export const xori8 = (a, b) => signExtend8((a | 0) ^ (b | 0));
export const noti8 = (a) => signExtend8(~a);
export const lshifti8 = (a, b) => signExtend8((a | 0) << (b | 0));
export const rshifti8 = (a, b) => signExtend8((a | 0) >> (b | 0));
export const addi16 = (a, b) => signExtend16((a | 0) + (b | 0));
export const divi16 = (a, b) => signExtend16((a | 0) / (b | 0));
export const muli16 = (a, b) => signExtend16((a | 0) * (b | 0));
export const subi16 = (a, b) => signExtend16((a | 0) - (b | 0));
export const andi16 = (a, b) => signExtend16((a | 0) & (b | 0));
export const ori16 = (a, b) => signExtend16(a | 0 | (b | 0));
export const xori16 = (a, b) => signExtend16((a | 0) ^ (b | 0));
export const noti16 = (a) => signExtend16(~a);
export const lshifti16 = (a, b) => signExtend16((a | 0) << (b | 0));
export const rshifti16 = (a, b) => signExtend16((a | 0) >> (b | 0));
export const addi32 = (a, b) => ((a | 0) + (b | 0)) | 0;
export const divi32 = (a, b) => ((a | 0) / (b | 0)) | 0;
export const muli32 = (a, b) => ((a | 0) * (b | 0)) | 0;
export const subi32 = (a, b) => ((a | 0) - (b | 0)) | 0;
export const andi32 = (a, b) => (a | 0) & (b | 0);
export const ori32 = (a, b) => a | 0 | (b | 0);
export const xori32 = (a, b) => (a | 0) ^ (b | 0);
export const lshifti32 = (a, b) => (a | 0) << (b | 0);
export const rshifti32 = (a, b) => (a | 0) >> (b | 0);
export const noti32 = (a) => ~a;
export const addu8 = (a, b) => ((a & M8) + (b & M8)) & M8;
export const divu8 = (a, b) => ((a & M8) / (b & M8)) & M8;
export const mulu8 = (a, b) => ((a & M8) * (b & M8)) & M8;
export const subu8 = (a, b) => ((a & M8) - (b & M8)) & M8;
export const andu8 = (a, b) => a & M8 & (b & M8) & M8;
export const oru8 = (a, b) => ((a & M8) | (b & M8)) & M8;
export const xoru8 = (a, b) => ((a & M8) ^ (b & M8)) & M8;
export const notu8 = (a) => ~a & M8;
export const lshiftu8 = (a, b) => ((a & M8) << (b & M8)) & M8;
export const rshiftu8 = (a, b) => ((a & M8) >>> (b & M8)) & M8;
export const addu16 = (a, b) => ((a & M16) + (b & M16)) & M16;
export const divu16 = (a, b) => ((a & M16) / (b & M16)) & M16;
export const mulu16 = (a, b) => ((a & M16) * (b & M16)) & M16;
export const subu16 = (a, b) => ((a & M16) - (b & M16)) & M16;
export const andu16 = (a, b) => a & M16 & (b & M16) & M16;
export const oru16 = (a, b) => ((a & M16) | (b & M16)) & M16;
export const xoru16 = (a, b) => ((a & M16) ^ (b & M16)) & M16;
export const notu16 = (a) => ~a & M16;
export const lshiftu16 = (a, b) => ((a & M16) << (b & M16)) & M16;
export const rshiftu16 = (a, b) => ((a & M16) >>> (b & M16)) & M16;
export const addu32 = (a, b) => ((a >>> 0) + (b >>> 0)) >>> 0;
export const divu32 = (a, b) => ((a >>> 0) / (b >>> 0)) >>> 0;
export const mulu32 = (a, b) => ((a >>> 0) * (b >>> 0)) >>> 0;
export const subu32 = (a, b) => ((a >>> 0) - (b >>> 0)) >>> 0;
export const andu32 = (a, b) => ((a >>> 0) & (b >>> 0)) >>> 0;
export const oru32 = (a, b) => ((a >>> 0) | (b >>> 0)) >>> 0;
export const xoru32 = (a, b) => ((a >>> 0) ^ (b >>> 0)) >>> 0;
export const notu32 = (a) => ~a >>> 0;
export const lshiftu32 = (a, b) => ((a >>> 0) << (b >>> 0)) >>> 0;
export const rshiftu32 = (a, b) => ((a >>> 0) >>> (b >>> 0)) >>> 0;
const M8 = 255;
const M16 = 65535;
const signExtend8 = (a) => (a &= M8, a & 128 ? a | ~M8 : a);
const signExtend16 = (a) => (a &= M16, a & 32768 ? a | ~M16 : a);
const addi8 = (a, b) => signExtend8((a | 0) + (b | 0));
const divi8 = (a, b) => signExtend8((a | 0) / (b | 0));
const muli8 = (a, b) => signExtend8((a | 0) * (b | 0));
const subi8 = (a, b) => signExtend8((a | 0) - (b | 0));
const andi8 = (a, b) => signExtend8((a | 0) & (b | 0));
const ori8 = (a, b) => signExtend8(a | 0 | (b | 0));
const xori8 = (a, b) => signExtend8((a | 0) ^ (b | 0));
const noti8 = (a) => signExtend8(~a);
const lshifti8 = (a, b) => signExtend8((a | 0) << (b | 0));
const rshifti8 = (a, b) => signExtend8((a | 0) >> (b | 0));
const addi16 = (a, b) => signExtend16((a | 0) + (b | 0));
const divi16 = (a, b) => signExtend16((a | 0) / (b | 0));
const muli16 = (a, b) => signExtend16((a | 0) * (b | 0));
const subi16 = (a, b) => signExtend16((a | 0) - (b | 0));
const andi16 = (a, b) => signExtend16((a | 0) & (b | 0));
const ori16 = (a, b) => signExtend16(a | 0 | (b | 0));
const xori16 = (a, b) => signExtend16((a | 0) ^ (b | 0));
const noti16 = (a) => signExtend16(~a);
const lshifti16 = (a, b) => signExtend16((a | 0) << (b | 0));
const rshifti16 = (a, b) => signExtend16((a | 0) >> (b | 0));
const addi32 = (a, b) => (a | 0) + (b | 0) | 0;
const divi32 = (a, b) => (a | 0) / (b | 0) | 0;
const muli32 = (a, b) => (a | 0) * (b | 0) | 0;
const subi32 = (a, b) => (a | 0) - (b | 0) | 0;
const andi32 = (a, b) => (a | 0) & (b | 0);
const ori32 = (a, b) => a | 0 | (b | 0);
const xori32 = (a, b) => (a | 0) ^ (b | 0);
const lshifti32 = (a, b) => (a | 0) << (b | 0);
const rshifti32 = (a, b) => (a | 0) >> (b | 0);
const noti32 = (a) => ~a;
const addu8 = (a, b) => (a & M8) + (b & M8) & M8;
const divu8 = (a, b) => (a & M8) / (b & M8) & M8;
const mulu8 = (a, b) => (a & M8) * (b & M8) & M8;
const subu8 = (a, b) => (a & M8) - (b & M8) & M8;
const andu8 = (a, b) => a & M8 & (b & M8) & M8;
const oru8 = (a, b) => (a & M8 | b & M8) & M8;
const xoru8 = (a, b) => (a & M8 ^ b & M8) & M8;
const notu8 = (a) => ~a & M8;
const lshiftu8 = (a, b) => (a & M8) << (b & M8) & M8;
const rshiftu8 = (a, b) => (a & M8) >>> (b & M8) & M8;
const addu16 = (a, b) => (a & M16) + (b & M16) & M16;
const divu16 = (a, b) => (a & M16) / (b & M16) & M16;
const mulu16 = (a, b) => (a & M16) * (b & M16) & M16;
const subu16 = (a, b) => (a & M16) - (b & M16) & M16;
const andu16 = (a, b) => a & M16 & (b & M16) & M16;
const oru16 = (a, b) => (a & M16 | b & M16) & M16;
const xoru16 = (a, b) => (a & M16 ^ b & M16) & M16;
const notu16 = (a) => ~a & M16;
const lshiftu16 = (a, b) => (a & M16) << (b & M16) & M16;
const rshiftu16 = (a, b) => (a & M16) >>> (b & M16) & M16;
const addu32 = (a, b) => (a >>> 0) + (b >>> 0) >>> 0;
const divu32 = (a, b) => (a >>> 0) / (b >>> 0) >>> 0;
const mulu32 = (a, b) => (a >>> 0) * (b >>> 0) >>> 0;
const subu32 = (a, b) => (a >>> 0) - (b >>> 0) >>> 0;
const andu32 = (a, b) => (a >>> 0 & b >>> 0) >>> 0;
const oru32 = (a, b) => (a >>> 0 | b >>> 0) >>> 0;
const xoru32 = (a, b) => (a >>> 0 ^ b >>> 0) >>> 0;
const notu32 = (a) => ~a >>> 0;
const lshiftu32 = (a, b) => a >>> 0 << (b >>> 0) >>> 0;
const rshiftu32 = (a, b) => a >>> 0 >>> (b >>> 0) >>> 0;
export {
addi16,
addi32,
addi8,
addu16,
addu32,
addu8,
andi16,
andi32,
andi8,
andu16,
andu32,
andu8,
divi16,
divi32,
divi8,
divu16,
divu32,
divu8,
lshifti16,
lshifti32,
lshifti8,
lshiftu16,
lshiftu32,
lshiftu8,
muli16,
muli32,
muli8,
mulu16,
mulu32,
mulu8,
noti16,
noti32,
noti8,
notu16,
notu32,
notu8,
ori16,
ori32,
ori8,
oru16,
oru32,
oru8,
rshifti16,
rshifti32,
rshifti8,
rshiftu16,
rshiftu32,
rshiftu8,
signExtend16,
signExtend8,
subi16,
subi32,
subi8,
subu16,
subu32,
subu8,
xori16,
xori32,
xori8,
xoru16,
xoru32,
xoru8
};

@@ -1,207 +0,75 @@

/**
* Clamps value `x` to given closed interval.
*
* @param x - value to clamp
* @param min - lower bound
* @param max - upper bound
*/
export const clamp = (x, min, max) => (x < min ? min : x > max ? max : x);
/**
* Clamps value `x` to closed [0 .. ∞] interval.
*
* @param x -
*/
export const clamp0 = (x) => (x > 0 ? x : 0);
/**
* Clamps value `x` to closed [0 .. 1] interval.
*
* @param x -
*/
export const clamp01 = (x) => (x < 0 ? 0 : x > 1 ? 1 : x);
/**
* Clamps value `x` to closed [-1 .. 1] interval.
*
* @param x -
*/
export const clamp11 = (x) => (x < -1 ? -1 : x > 1 ? 1 : x);
/**
* Clamps value `x` to closed [0 .. 0.5] interval.
*
* @param x -
*/
export const clamp05 = (x) => (x < 0 ? 0 : x > 0.5 ? 0.5 : x);
/**
* Returns 2-tuple of [min(x,y), max(x,y)].
*
* @param x
* @param y
*/
export const minMax = (x, y) => x < y ? [x, y] : [y, x];
/**
* Folds `x` back inside closed [min..max] interval. Also see
* {@link wrapOnce}.
*
* @param x -
* @param min -
* @param max -
*/
export const wrap = (x, min, max) => {
if (min === max)
return min;
if (x > max) {
const d = max - min;
x -= d;
if (x > max)
x -= d * (((x - min) / d) | 0);
}
else if (x < min) {
const d = max - min;
x += d;
if (x < min)
x += d * (((min - x) / d + 1) | 0);
}
return x;
const clamp = (x, min, max) => x < min ? min : x > max ? max : x;
const clamp0 = (x) => x > 0 ? x : 0;
const clamp01 = (x) => x < 0 ? 0 : x > 1 ? 1 : x;
const clamp11 = (x) => x < -1 ? -1 : x > 1 ? 1 : x;
const clamp05 = (x) => x < 0 ? 0 : x > 0.5 ? 0.5 : x;
const minMax = (x, y) => x < y ? [x, y] : [y, x];
const wrap = (x, min, max) => {
if (min === max)
return min;
if (x > max) {
const d = max - min;
x -= d;
if (x > max)
x -= d * ((x - min) / d | 0);
} else if (x < min) {
const d = max - min;
x += d;
if (x < min)
x += d * ((min - x) / d + 1 | 0);
}
return x;
};
/**
* Like {@link wrap}, but optimized for cases where `x` is guaranteed to
* be in `[min - d, max + d]` interval, where `d = max - min`. Result
* will be in closed `[min..max]` interval.
*
* @param x -
* @param min -
* @param max -
*/
export const wrapOnce = (x, min, max) => x < min ? x - min + max : x > max ? x - max + min : x;
/**
* Similar to {@link wrapOnce} for [0..1] interval.
*
* @param x -
*/
export const wrap01 = (x) => (x < 0 ? x + 1 : x > 1 ? x - 1 : x);
/**
* Similar to {@link wrapOnce} for [-1..1] interval.
*
* @param x -
*/
export const wrap11 = (x) => (x < -1 ? x + 2 : x > 1 ? x - 2 : x);
export const min2id = (a, b) => (a <= b ? 0 : 1);
export const min3id = (a, b, c) => a <= b ? (a <= c ? 0 : 2) : b <= c ? 1 : 2;
export const min4id = (a, b, c, d) => a <= b
? a <= c
? a <= d
? 0
: 3
: c <= d
? 2
: 3
: b <= c
? b <= d
? 1
: 3
: c <= d
? 2
: 3;
export const max2id = (a, b) => (a >= b ? 0 : 1);
export const max3id = (a, b, c) => a >= b ? (a >= c ? 0 : 2) : b >= c ? 1 : 2;
export const max4id = (a, b, c, d) => a >= b
? a >= c
? a >= d
? 0
: 3
: c >= d
? 2
: 3
: b >= c
? b >= d
? 1
: 3
: c >= d
? 2
: 3;
/**
* Returns the non-zero minimum value of the given `a`, `b` args.
*
* @param a -
* @param b -
*/
export const minNonZero2 = (a, b) => a !== 0 ? (b !== 0 ? Math.min(a, b) : a) : b;
/**
* Returns the non-zero minimum value of the given `a`, `b`, `c` args.
*
* @param a -
* @param b -
* @param c -
*/
export const minNonZero3 = (a, b, c) => minNonZero2(minNonZero2(a, b), c);
/**
* See `smax()`.
*
* @param a -
* @param b -
* @param k - smooth exponent (MUST be > 0)
*/
export const smin = (a, b, k) => smax(a, b, -k);
/**
* Smooth maximum. Note: Result values will be slightly larger than max value
* near max(a,b) + eps due to exponential decay. Higher `k` values reduce the
* error, but also reduce the smoothing. Recommended k=16.
*
* https://en.wikipedia.org/wiki/Smooth_maximum
*
* @param a -
* @param b -
* @param k - smooth exponent (MUST be > 0)
*/
export const smax = (a, b, k) => {
const ea = Math.exp(a * k);
const eb = Math.exp(b * k);
return (a * ea + b * eb) / (ea + eb);
const wrapOnce = (x, min, max) => x < min ? x - min + max : x > max ? x - max + min : x;
const wrap01 = (x) => x < 0 ? x + 1 : x > 1 ? x - 1 : x;
const wrap11 = (x) => x < -1 ? x + 2 : x > 1 ? x - 2 : x;
const min2id = (a, b) => a <= b ? 0 : 1;
const min3id = (a, b, c) => a <= b ? a <= c ? 0 : 2 : b <= c ? 1 : 2;
const min4id = (a, b, c, d) => a <= b ? a <= c ? a <= d ? 0 : 3 : c <= d ? 2 : 3 : b <= c ? b <= d ? 1 : 3 : c <= d ? 2 : 3;
const max2id = (a, b) => a >= b ? 0 : 1;
const max3id = (a, b, c) => a >= b ? a >= c ? 0 : 2 : b >= c ? 1 : 2;
const max4id = (a, b, c, d) => a >= b ? a >= c ? a >= d ? 0 : 3 : c >= d ? 2 : 3 : b >= c ? b >= d ? 1 : 3 : c >= d ? 2 : 3;
const minNonZero2 = (a, b) => a !== 0 ? b !== 0 ? Math.min(a, b) : a : b;
const minNonZero3 = (a, b, c) => minNonZero2(minNonZero2(a, b), c);
const smin = (a, b, k) => smax(a, b, -k);
const smax = (a, b, k) => {
const ea = Math.exp(a * k);
const eb = Math.exp(b * k);
return (a * ea + b * eb) / (ea + eb);
};
/**
* Same as `smin(smax(x, min, k), max, k)`.
*
* @param x -
* @param min -
* @param max -
* @param k -
*/
export const sclamp = (x, min, max, k) => smin(smax(x, min, k), max, k);
export const absMin = (a, b) => (Math.abs(a) < Math.abs(b) ? a : b);
export const absMax = (a, b) => (Math.abs(a) > Math.abs(b) ? a : b);
/**
* If `abs(x) > abs(e)`, recursively mirrors `x` back into `[-e .. +e]`
* interval at respective positive/negative boundary.
*
* @remarks
* References:
* - https://www.desmos.com/calculator/lkyf2ag3ta
* - https://www.musicdsp.org/en/latest/Effects/203-fold-back-distortion.html
*
* @param e - threshold (> 0)
* @param x - input value
*/
export const foldback = (e, x) => x < -e || x > e ? Math.abs(Math.abs((x - e) % (4 * e)) - 2 * e) - e : x;
/**
* Similar to {@link foldback}, but with fixed target range: Folds `x` into the
* closed [0..1] interval, using infinite internal reflection on either side of
* the interval.
*
* @param x
*/
export const foldback01 = (x) => ((x = Math.abs(x) % 2) > 1 ? 2 - x : x);
/**
* Returns true iff `x` is in closed interval `[min .. max]`
*
* @param x -
* @param min -
* @param max -
*/
export const inRange = (x, min, max) => x >= min && x <= max;
/**
* Returns true iff `x` is in open interval `(min .. max)`
*
* @param x -
* @param min -
* @param max -
*/
export const inOpenRange = (x, min, max) => x > min && x < max;
const sclamp = (x, min, max, k) => smin(smax(x, min, k), max, k);
const absMin = (a, b) => Math.abs(a) < Math.abs(b) ? a : b;
const absMax = (a, b) => Math.abs(a) > Math.abs(b) ? a : b;
const foldback = (e, x) => x < -e || x > e ? Math.abs(Math.abs((x - e) % (4 * e)) - 2 * e) - e : x;
const foldback01 = (x) => (x = Math.abs(x) % 2) > 1 ? 2 - x : x;
const inRange = (x, min, max) => x >= min && x <= max;
const inOpenRange = (x, min, max) => x > min && x < max;
export {
absMax,
absMin,
clamp,
clamp0,
clamp01,
clamp05,
clamp11,
foldback,
foldback01,
inOpenRange,
inRange,
max2id,
max3id,
max4id,
min2id,
min3id,
min4id,
minMax,
minNonZero2,
minNonZero3,
sclamp,
smax,
smin,
wrap,
wrap01,
wrap11,
wrapOnce
};

@@ -1,109 +0,40 @@

/**
* Returns a value with the magnitude of `x` and the sign of `y`.
*
* @param x -
* @param y -
*/
export const copysign = (x, y) => Math.sign(y) * Math.abs(x);
/**
* Returns `2^x`.
*
* @param x -
*/
export const exp2 = (x) => 2 ** x;
/**
* Returns the positive difference between `x` and `y`, i.e. `x - y` iff `x > y`,
* otherwise zero.
*
* @param x -
* @param y -
*/
export const fdim = (x, y) => Math.max(x - y, 0);
/**
* Returns `x * y + z`.
*
* @param x -
* @param y -
* @param z -
*/
export const fma = (x, y, z) => x * y + z;
/**
* Similar to {@link mod}, {@link remainder}. Returns `x - y * trunc(x / y)`,
* i.e. essentially the same as JS `%` operator. Result will always have the
* sign of `x`.
*
* @remarks
* **Caution:** Due to the introduction of libc math functions in v4.0.0 and the
* resulting name/behavior clashes between the modulo logic in JS, C & GLSL, the
* previous `fmod` function has been renamed to {@link mod} to align w/ its GLSL
* version and now exhibits a different behavior to this current {@link fmod}
* function.
*
* Reference: https://www.cplusplus.com/reference/cmath/fmod/
*
* @param x -
* @param y -
*/
export const fmod = (x, y) => x % y;
//export const fmod: FnN2 = (x, y) => x - y * Math.trunc(x / y);
/**
* Inverse op of {@link ldexp}. Breaks the number `x` into its binary
* significand (a floating point with an abs value in `[0.5,1.0)` interval and
* an integral exponent for 2, such that: `x = significand * 2^exp`. Returns
* tuple of `[sig, exp]`.
*
* @remarks
* - If `x` is zero, both parts (significand and exponent) are zero.
* - If `x` is negative, the significand returned by this function is negative.
*
* Based on:
* https://github.com/locutusjs/locutus/blob/master/src/c/math/frexp.js
*
* @param x -
*/
export const frexp = (x) => {
if (x === 0 || !isFinite(x))
return [x, 0];
const abs = Math.abs(x);
let exp = Math.max(-1023, Math.floor(Math.log2(abs)) + 1);
let y = abs * 2 ** -exp;
while (y < 0.5) {
y *= 2;
exp--;
}
while (y >= 1) {
y *= 0.5;
exp++;
}
return [x < 0 ? -y : y, exp];
const copysign = (x, y) => Math.sign(y) * Math.abs(x);
const exp2 = (x) => 2 ** x;
const fdim = (x, y) => Math.max(x - y, 0);
const fma = (x, y, z) => x * y + z;
const fmod = (x, y) => x % y;
const frexp = (x) => {
if (x === 0 || !isFinite(x))
return [x, 0];
const abs = Math.abs(x);
let exp = Math.max(-1023, Math.floor(Math.log2(abs)) + 1);
let y = abs * 2 ** -exp;
while (y < 0.5) {
y *= 2;
exp--;
}
while (y >= 1) {
y *= 0.5;
exp++;
}
return [x < 0 ? -y : y, exp];
};
/**
* Inverse op of {@link frexp}. Returns `x * 2^exp`
*
* @param x -
* @param exp -
*/
export const ldexp = (x, exp) => x * 2 ** exp;
/**
* Similar to {@link fmod}, {@link mod}. Returns `x - y * round(x / y)`.
*
* @remarks
* https://www.cplusplus.com/reference/cmath/remainder/
*
* @param x -
* @param y -
*/
export const remainder = (x, y) => x - y * Math.round(x / y);
/**
* Computes both the quotient and remainder of the integer division of the
* numerator `x` by the denominator `y`.
*
* @param x -
* @param y -
*/
export const ldiv = (x, y) => {
x |= 0;
y |= 0;
const q = (x / y) | 0;
return [q, x - q * y];
const ldexp = (x, exp) => x * 2 ** exp;
const remainder = (x, y) => x - y * Math.round(x / y);
const ldiv = (x, y) => {
x |= 0;
y |= 0;
const q = x / y | 0;
return [q, x - q * y];
};
export {
copysign,
exp2,
fdim,
fma,
fmod,
frexp,
ldexp,
ldiv,
remainder
};
import { EPS } from "./api.js";
/**
* Recursively evaluates function `fn` for `res` uniformly spaced values
* `t` in the closed parametric interval `[start,end]` and computes
* corresponding sample values `p`. For each `p` then calls `error`
* function to compute the error to query target value `q` and
* eventually returns the `t` producing the overall minimum error. At
* each level of recursion the search interval is increasingly narrowed
* / centered around the best `t` of the current iteration.
*
* The search is terminated early if the best error value is less than
* `eps`.
*
* The interval end points `start` and `end` MUST be normalized values
* in the closed [0,1] interval.
*
* @param fn - function to evaluate
* @param error - error function
* @param q - target value
* @param res - number of samples per interval
* @param iter - max number of iterations / recursion limit
* @param start - interval start
* @param end - interval end
*/
export const minError = (fn, error, q, res = 16, iter = 8, start = 0, end = 1, eps = EPS) => {
if (iter <= 0)
return (start + end) / 2;
const delta = (end - start) / res;
let minT = start;
let minE = Infinity;
for (let i = 0; i <= res; i++) {
const t = start + i * delta;
const e = error(q, fn(t));
if (e < minE) {
if (e <= eps)
return t;
minE = e;
minT = t;
}
const minError = (fn, error, q, res = 16, iter = 8, start = 0, end = 1, eps = EPS) => {
if (iter <= 0)
return (start + end) / 2;
const delta = (end - start) / res;
let minT = start;
let minE = Infinity;
for (let i = 0; i <= res; i++) {
const t = start + i * delta;
const e = error(q, fn(t));
if (e < minE) {
if (e <= eps)
return t;
minE = e;
minT = t;
}
return minError(fn, error, q, res, iter - 1, Math.max(minT - delta, 0), Math.min(minT + delta, 1));
}
return minError(
fn,
error,
q,
res,
iter - 1,
Math.max(minT - delta, 0),
Math.min(minT + delta, 1)
);
};
export {
minError
};
import { EPS, HALF_PI, PI } from "./api.js";
/**
* Linear interpolation without clamping. Computes `a + (b - a) * t`
*
* @param a - start value
* @param b - end value
* @param t - interpolation factor [0..1]
*/
export const mix = (a, b, t) => a + (b - a) * t;
/**
* Bilinear interpolation of given values (`a`,`b`,`c`,`d`).
*
* @example
* ```ts
* c d
* +----+
* | |
* +----+
* a b
* ```
*
* @param a - BL value
* @param b - BR value
* @param c - TL value
* @param d - TR value
* @param u - 1st interpolation factor
* @param v - 2nd interpolation factor
*/
export const mixBilinear = (a, b, c, d, u, v) => {
const iu = 1 - u;
const iv = 1 - v;
return a * iu * iv + b * u * iv + c * iu * v + d * u * v;
const mix = (a, b, t) => a + (b - a) * t;
const mixBilinear = (a, b, c, d, u, v) => {
const iu = 1 - u;
const iv = 1 - v;
return a * iu * iv + b * u * iv + c * iu * v + d * u * v;
};
/**
* Computes quadratic bezier interpolation for normalized value `t`.
*
* @param a
* @param b
* @param c
* @param t
*/
export const mixQuadratic = (a, b, c, t) => {
const s = 1 - t;
return a * s * s + b * 2 * s * t + c * t * t;
const mixQuadratic = (a, b, c, t) => {
const s = 1 - t;
return a * s * s + b * 2 * s * t + c * t * t;
};
/**
* Computes cubic bezier interpolation for normalized value `t`.
*
* @param a
* @param b
* @param c
* @param d
* @param t
*/
export const mixCubic = (a, b, c, d, t) => {
const t2 = t * t;
const s = 1 - t;
const s2 = s * s;
return a * s2 * s + b * 3 * s2 * t + c * 3 * t2 * s + d * t2 * t;
const mixCubic = (a, b, c, d, t) => {
const t2 = t * t;
const s = 1 - t;
const s2 = s * s;
return a * s2 * s + b * 3 * s2 * t + c * 3 * t2 * s + d * t2 * t;
};
/**
* Returns hermite interpolation of `a, b, c, d` at normalized position `t`,
* where `a` and `d` are used as predecessor/successor of `b` / `c` and only
* inform the tangent of the interpolation curve. The interpolated result is
* that of `b` and `c`.
*
* Assumes all inputs are uniformly spaced. If that's not the case, use
* {@link mixCubicHermite} with one of the tangent generators supporting
* non-uniform spacing of points.
*
* See: https://www.desmos.com/calculator/j4gf8g9vkr
*
* Source:
* https://www.musicdsp.org/en/latest/Other/93-hermite-interpollation.html
*
* - {@link mixCubicHermite}
* - {@link tangentCardinal}
* - {@link tangentDiff3}
*
* @param a -
* @param b -
* @param c -
* @param d -
* @param t -
*/
export const mixHermite = (a, b, c, d, t) => {
const y1 = 0.5 * (c - a);
const y2 = 1.5 * (b - c) + 0.5 * (d - a);
return ((y2 * t + a - b + y1 - y2) * t + y1) * t + b;
const mixHermite = (a, b, c, d, t) => {
const y1 = 0.5 * (c - a);
const y2 = 1.5 * (b - c) + 0.5 * (d - a);
return ((y2 * t + a - b + y1 - y2) * t + y1) * t + b;
};
/**
* Computes cubic-hermite interpolation between `a` / `b` at normalized
* time `t` and using respective tangents `ta` / `tb`.
*
* https://en.wikipedia.org/wiki/Cubic_Hermite_spline
*
* - {@link mixHermite}
* - {@link tangentCardinal}
* - {@link tangentDiff3}
*
* @param a -
* @param ta -
* @param b -
* @param tb -
* @param t -
*/
export const mixCubicHermite = (a, ta, b, tb, t) => {
const s = t - 1;
const t2 = t * t;
const s2 = s * s;
const h00 = (1 + 2 * t) * s2;
const h10 = t * s2;
const h01 = t2 * (3 - 2 * t);
const h11 = t2 * s;
return h00 * a + h10 * ta + h01 * b + h11 * tb;
const mixCubicHermite = (a, ta, b, tb, t) => {
const s = t - 1;
const t2 = t * t;
const s2 = s * s;
const h00 = (1 + 2 * t) * s2;
const h10 = t * s2;
const h01 = t2 * (3 - 2 * t);
const h11 = t2 * s;
return h00 * a + h10 * ta + h01 * b + h11 * tb;
};
/**
* Similar to {@link mixCubicHermite}, but takes 4 control values (uniformly
* spaced) and computes tangents automatically. Returns `b` iff `t=0` and `c`
* iff `t=1.0`.
*
* @param a -
* @param b -
* @param c -
* @param d -
* @param t -
*/
export const mixCubicHermiteFromPoints = (a, b, c, d, t) => {
d *= 0.5;
const aa = -0.5 * a + 1.5 * b - 1.5 * c + d;
const bb = a - 2.5 * b + 2 * c - d;
const cc = -0.5 * a + 0.5 * c;
const dd = b;
const t2 = t * t;
return t * t2 * aa + t2 * bb + t * cc + dd;
const mixCubicHermiteFromPoints = (a, b, c, d, t) => {
d *= 0.5;
const aa = -0.5 * a + 1.5 * b - 1.5 * c + d;
const bb = a - 2.5 * b + 2 * c - d;
const cc = -0.5 * a + 0.5 * c;
const dd = b;
const t2 = t * t;
return t * t2 * aa + t2 * bb + t * cc + dd;
};
/**
* Bicubic interpolation of given 4x4 sample values (in row major order, i.e.
* `s00..s03` = 1st row).
*
* @remarks
* Result will not be clamped and might fall outside the total range of the
* input samples.
*
* @param s00 -
* @param s01 -
* @param s02 -
* @param s03 -
* @param s10 -
* @param s11 -
* @param s12 -
* @param s13 -
* @param s20 -
* @param s21 -
* @param s22 -
* @param s23 -
* @param s30 -
* @param s31 -
* @param s32 -
* @param s33 -
* @param u -
* @param v -
*/
export const mixBicubic = (s00, s01, s02, s03, s10, s11, s12, s13, s20, s21, s22, s23, s30, s31, s32, s33, u, v) => mixCubicHermiteFromPoints(mixCubicHermiteFromPoints(s00, s01, s02, s03, u), mixCubicHermiteFromPoints(s10, s11, s12, s13, u), mixCubicHermiteFromPoints(s20, s21, s22, s23, u), mixCubicHermiteFromPoints(s30, s31, s32, s33, u), v);
/**
* Helper function for {@link mixCubicHermite}. Computes cardinal tangents based
* on point neighbors of a point B (not given), i.e. `a` (predecessor) and `c`
* (successor) and their times (defaults to uniformly spaced). The optional
* `tension` parameter can be used to scale the tangent where 0.0 produces a
* Cardinal spline tangent and 1.0 a Catmull-Rom (opposite to the Wikipedia
* ref).
*
* https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Cardinal_spline
*
* @param prev -
* @param next -
* @param scale -
* @param ta -
* @param tc -
*/
export const tangentCardinal = (prev, next, scale = 0.5, ta = 0, tc = 2) => scale * ((next - prev) / (tc - ta));
/**
* Helper function for {@link mixCubicHermite}. Computes tangent for `curr`,
* based on 3-point finite difference, where `prev` & `next` are `curr`'s
* neighbors and the `tX` the three points' respective time values. The latter
* are equally spaced by default (each 1.0 apart).
*
* Using this function with equal spacing of 1.0 and together with
* {@link mixCubicHermite} will produce same results as the somewhat optimized
* variant {@link mixHermite}.
*
* https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Finite_difference
*
* @param prev -
* @param curr -
* @param next -
* @param ta -
* @param tb -
* @param tc -
*/
export const tangentDiff3 = (prev, curr, next, ta = 0, tb = 1, tc = 2) => 0.5 * ((next - curr) / (tc - tb) + (curr - prev) / (tb - ta));
/**
* HOF interpolator. Takes a timing function `f` and interval `[from,to]`.
* Returns function which takes normalized time (in [0,1] range) as single arg
* and returns interpolated value.
*
* @param f -
* @param from -
* @param to -
*/
export const tween = (f, from, to) => (t) => mix(from, to, f(t));
/**
* Circular interpolation (ease out): `sqrt(1 - (1 - t)^2)`
*
* @remarks
* Reference: https://www.desmos.com/calculator/tisoiazdrw
*
* @param t - interpolation factor [0..1]
*/
export const circular = (t) => {
t = 1 - t;
return Math.sqrt(1 - t * t);
const mixBicubic = (s00, s01, s02, s03, s10, s11, s12, s13, s20, s21, s22, s23, s30, s31, s32, s33, u, v) => mixCubicHermiteFromPoints(
mixCubicHermiteFromPoints(s00, s01, s02, s03, u),
mixCubicHermiteFromPoints(s10, s11, s12, s13, u),
mixCubicHermiteFromPoints(s20, s21, s22, s23, u),
mixCubicHermiteFromPoints(s30, s31, s32, s33, u),
v
);
const tangentCardinal = (prev, next, scale = 0.5, ta = 0, tc = 2) => scale * ((next - prev) / (tc - ta));
const tangentDiff3 = (prev, curr, next, ta = 0, tb = 1, tc = 2) => 0.5 * ((next - curr) / (tc - tb) + (curr - prev) / (tb - ta));
const tween = (f, from, to) => (t) => mix(from, to, f(t));
const circular = (t) => {
t = 1 - t;
return Math.sqrt(1 - t * t);
};
/**
* Inverse/flipped version of {@link circular} (ease in).
*
* @remarks
* Reference: https://www.desmos.com/calculator/tisoiazdrw
*
* @param t - interpolation factor [0..1]
*/
export const invCircular = (t) => 1 - circular(1 - t);
/**
* Zoomlens interpolation with customizable lens position, behavior and
* strength.
*
* @remarks
* Lens position must be given in (0..1) interval. Lens strength must be in
* [-1,1] range. If negative, the lens will be bundling values near `pos`, if
* positive the lens has dilating characteristics and will spread values near
* `pos` towards the edges.
*
* Also see {@link schlick} for an alternative approach.
*
* @example
* ```ts
* // interpolated position in [100..400] interval for given `t`
* y = mix(100, 400, lens(0.5, 1, t));
*
* // or build tween function via `tween()`
* f = tween(partial(lens, 0.5, 1), 100, 400);
*
* f(t)
* ```
*
* @param pos - lens pos
* @param strength - lens strength
* @param t - interpolation factor [0..1]
*/
export const lens = (pos, strength, t) => {
const impl = strength > 0 ? invCircular : circular;
const tp = 1 - pos;
const tl = t <= pos ? impl(t / pos) * pos : 1 - impl((1 - t) / tp) * tp;
return mix(t, tl, Math.abs(strength));
const invCircular = (t) => 1 - circular(1 - t);
const lens = (pos, strength, t) => {
const impl = strength > 0 ? invCircular : circular;
const tp = 1 - pos;
const tl = t <= pos ? impl(t / pos) * pos : 1 - impl((1 - t) / tp) * tp;
return mix(t, tl, Math.abs(strength));
};
export const cosine = (t) => 1 - (Math.cos(t * PI) * 0.5 + 0.5);
export const decimated = (n, t) => Math.floor(t * n) / n;
/**
* Spring oscillator with damping.
*
* @remarks
* Interactive graph:
* https://www.desmos.com/calculator/tywbpw8pck
*
* @param k
* @param amp
* @param t
*/
export const bounce = (k, amp, t) => {
const tk = t * k;
return 1 - ((amp * Math.sin(tk)) / tk) * Math.cos(t * HALF_PI);
const cosine = (t) => 1 - (Math.cos(t * PI) * 0.5 + 0.5);
const decimated = (n, t) => Math.floor(t * n) / n;
const bounce = (k, amp, t) => {
const tk = t * k;
return 1 - amp * Math.sin(tk) / tk * Math.cos(t * HALF_PI);
};
/**
* Exponential easing.
*
* - `ease = 1` -> linear
* - `ease > 1` -> ease in
* - `ease < 1` -> ease out
*
* @param ease - easing behavior [0.0 .. ∞]
* @param t -
*/
export const ease = (ease, t) => Math.pow(t, ease);
/**
* Impulse generator. Peaks at `t = 1/k`
*
* @param k - impulse width (higher values => shorter impulse)
*/
export const impulse = (k, t) => {
const h = k * t;
return h * Math.exp(1 - h);
const ease = (ease2, t) => Math.pow(t, ease2);
const impulse = (k, t) => {
const h = k * t;
return h * Math.exp(1 - h);
};
export const gain = (k, t) => t < 0.5 ? 0.5 * Math.pow(2 * t, k) : 1 - 0.5 * Math.pow(2 - 2 * t, k);
export const parabola = (k, t) => Math.pow(4.0 * t * (1.0 - t), k);
export const cubicPulse = (w, c, t) => {
t = Math.abs(t - c);
return t > w ? 0 : ((t /= w), 1 - t * t * (3 - 2 * t));
const gain = (k, t) => t < 0.5 ? 0.5 * Math.pow(2 * t, k) : 1 - 0.5 * Math.pow(2 - 2 * t, k);
const parabola = (k, t) => Math.pow(4 * t * (1 - t), k);
const cubicPulse = (w, c, t) => {
t = Math.abs(t - c);
return t > w ? 0 : (t /= w, 1 - t * t * (3 - 2 * t));
};
/**
* Unnormalized Sinc function: sin(x)/x. Returns 1 for t=0.
*
* @remarks
* https://en.wikipedia.org/wiki/Sinc_function
*
* @param k -
* @param t -
*/
export const sinc = (t) => (t !== 0 ? Math.sin(t) / t : 1);
/**
* Normalized Sinc function, returns sinc(π*k*t).
*
* @remarks
* https://en.wikipedia.org/wiki/Sinc_function
*
* @see {@link sinc}
*
* @param k -
* @param t -
*/
export const sincNormalized = (k, t) => sinc(PI * k * t);
/**
* Lanczos filter. Returns `sinc(πt)sinc(πt/a)` iff `t` in (-a,a) interval, else
* returns 0.
*
* @remarks
* Interactive graph: https://www.desmos.com/calculator/pmypqgefle
*
* @param a -
* @param t -
*/
export const lanczos = (a, t) => t !== 0 ? (-a < t && t < a ? sinc(PI * t) * sinc((PI * t) / a) : 0) : 1;
/**
* Sigmoid function for inputs arounds center bias.
*
* @remarks
* Updated in v3.0.0 to add bias value to satisfy more use cases. Use
* {@link sigmoid01} for old behavior.
*
* @param bias - center value (for which result = 0.5)
* @param k - steepness
* @param t - input value
*/
export const sigmoid = (bias, k, t) => t != bias ? 1 / (1 + Math.exp(-k * (t - bias))) : 0.5;
/**
* Sigmoid function for inputs in [0..1] interval. Center bias = 0.5.
*
* @param k - steepness
* @param t - input value
*/
export const sigmoid01 = (k, t) => sigmoid(0.5, k, t);
/**
* Sigmoid function for inputs in [-1..+1] interval. Center bias = 0
*
* @param k -
* @param t -
*/
export const sigmoid11 = (k, t) => sigmoid(0, k, t);
/**
* Generalized Schlick bias gain curve, based on:
* https://arxiv.org/abs/2010.09714
*
* @remarks
* Interactive graph:
* https://www.desmos.com/calculator/u6bkm5rb7t
*
* @param a - curve strength. recommended (0..64]
* @param b - pivot position [0..1]
* @param t - input val [0..1]
*/
export const schlick = (a, b, t) => t <= b
? (b * t) / (t + a * (b - t) + EPS)
: ((1 - b) * (t - 1)) / (1 - t - a * (b - t) + EPS) + 1;
/**
* Computes exponential factor to interpolate from `a` to `b` over
* `num` steps. I.e. multiplying `a` with the returned factor will yield
* `b` after `num` steps. All args must be > 0.
*
* @param a -
* @param b -
* @param num -
*/
export const expFactor = (a, b, num) => (b / a) ** (1 / num);
/**
* Computes gaussian bell curve for given center `bias` and `sigma` (spread).
*
* @remarks
* Interactive graph: https://www.desmos.com/calculator/aq6hdzxprv
*
* @param bias -
* @param sigma -
* @param t -
*/
export const gaussian = (bias, sigma, t) => Math.exp(-((t - bias) ** 2) / (2 * sigma * sigma));
const sinc = (t) => t !== 0 ? Math.sin(t) / t : 1;
const sincNormalized = (k, t) => sinc(PI * k * t);
const lanczos = (a, t) => t !== 0 ? -a < t && t < a ? sinc(PI * t) * sinc(PI * t / a) : 0 : 1;
const sigmoid = (bias, k, t) => t != bias ? 1 / (1 + Math.exp(-k * (t - bias))) : 0.5;
const sigmoid01 = (k, t) => sigmoid(0.5, k, t);
const sigmoid11 = (k, t) => sigmoid(0, k, t);
const schlick = (a, b, t) => t <= b ? b * t / (t + a * (b - t) + EPS) : (1 - b) * (t - 1) / (1 - t - a * (b - t) + EPS) + 1;
const expFactor = (a, b, num) => (b / a) ** (1 / num);
const gaussian = (bias, sigma, t) => Math.exp(-((t - bias) ** 2) / (2 * sigma * sigma));
export {
bounce,
circular,
cosine,
cubicPulse,
decimated,
ease,
expFactor,
gain,
gaussian,
impulse,
invCircular,
lanczos,
lens,
mix,
mixBicubic,
mixBilinear,
mixCubic,
mixCubicHermite,
mixCubicHermiteFromPoints,
mixHermite,
mixQuadratic,
parabola,
schlick,
sigmoid,
sigmoid01,
sigmoid11,
sinc,
sincNormalized,
tangentCardinal,
tangentDiff3,
tween
};
{
"name": "@thi.ng/math",
"version": "5.7.6",
"version": "5.7.7",
"description": "Assorted common math functions & utilities",

@@ -30,3 +30,5 @@ "type": "module",

"scripts": {
"build": "yarn clean && tsc --declaration",
"build": "yarn build:esbuild && yarn build:decl",
"build:decl": "tsc --declaration --emitDeclarationOnly",
"build:esbuild": "esbuild --format=esm --platform=neutral --target=es2022 --tsconfig=tsconfig.json --outdir=. src/**/*.ts",
"clean": "rimraf --glob '*.js' '*.d.ts' '*.map' doc",

@@ -40,6 +42,7 @@ "doc": "typedoc --excludePrivate --excludeInternal --out doc src/index.ts",

"dependencies": {
"@thi.ng/api": "^8.9.11"
"@thi.ng/api": "^8.9.12"
},
"devDependencies": {
"@microsoft/api-extractor": "^7.38.3",
"esbuild": "^0.19.8",
"rimraf": "^5.0.5",

@@ -141,3 +144,3 @@ "tools": "^0.0.1",

},
"gitHead": "25f2ac8ff795a432a930119661b364d4d93b59a0\n"
"gitHead": "5e7bafedfc3d53bc131469a28de31dd8e5b4a3ff\n"
}

@@ -1,48 +0,19 @@

/**
* Computes factorial for `n`. Throws an error if `n < 0`.
*
* @param n
*/
export const factorial = (n) => {
if (n < 0)
throw new Error(`illegal argument: ${n}`);
let res = 1;
for (let i = 1; i <= n; i++)
res *= i;
return res;
const factorial = (n) => {
if (n < 0)
throw new Error(`illegal argument: ${n}`);
let res = 1;
for (let i = 1; i <= n; i++)
res *= i;
return res;
};
/**
* Computes `n ** k`
*
* @param n number of choices
* @param k number of selected
*/
export const permutationsWithRep = (n, k) => n ** k;
/**
* Computes `n! / (n - k)!`
*
* @remarks
* Reference:
* https://en.wikipedia.org/wiki/Permutation#k-permutations_of_n
*
* @param n number of choices
* @param k number of selected
*/
export const permutationsWithoutRep = (n, k) => factorial(n) / factorial(n - k);
/**
* Computes `(n + k - 1)! / (k! * (n - 1)!)`
*
* @param n number of choices
* @param k number of selected
*/
export const combinationsWithRep = (n, k) => factorial(n + k - 1) / (factorial(k) * factorial(n - 1));
/**
* Computes `n! / (k! * (n - k)!)`
*
* @remarks
* https://en.wikipedia.org/wiki/Combination#Number_of_k-combinations
*
* @param n number of choices
* @param k number of selected
*/
export const combinationsWithoutRep = (n, k) => factorial(n) / (factorial(k) * factorial(n - k));
const permutationsWithRep = (n, k) => n ** k;
const permutationsWithoutRep = (n, k) => factorial(n) / factorial(n - k);
const combinationsWithRep = (n, k) => factorial(n + k - 1) / (factorial(k) * factorial(n - 1));
const combinationsWithoutRep = (n, k) => factorial(n) / (factorial(k) * factorial(n - k));
export {
combinationsWithRep,
combinationsWithoutRep,
factorial,
permutationsWithRep,
permutationsWithoutRep
};
import { EPS } from "./api.js";
/**
* Similar to {@link fmod}, {@link remainder}. Returns `a - b * floor(a / b)`
* (same as GLSL `mod(a, b)`)
*
* @remarks
* **Caution:** Due to the introduction of libc math functions in v4.0.0 and the
* resulting name/behavior clashes between the modulo logic in JS, C & GLSL,
* this function previously _was_ called `fmod`, but going forward has been
* renamed to align w/ its GLSL version and exhibits a different behavior to the
* current {@link fmod} function.
*
* https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/mod.xhtml
*
* @param a -
* @param b -
*/
export const mod = (a, b) => a - b * Math.floor(a / b);
export const fract = (x) => x - Math.floor(x);
export const trunc = (x) => (x < 0 ? Math.ceil(x) : Math.floor(x));
export const roundTo = (x, prec = 1) => Math.round(x / prec) * prec;
export const floorTo = (x, prec = 1) => Math.floor(x / prec) * prec;
export const ceilTo = (x, prec = 1) => Math.ceil(x / prec) * prec;
/**
* Only rounds `x` to nearest int if `fract(x)` <= `eps` or >= `1-eps`.
*
* @param x -
* @param eps -
*/
export const roundEps = (x, eps = EPS) => {
const f = fract(x);
return f <= eps || f >= 1 - eps ? Math.round(x) : x;
const mod = (a, b) => a - b * Math.floor(a / b);
const fract = (x) => x - Math.floor(x);
const trunc = (x) => x < 0 ? Math.ceil(x) : Math.floor(x);
const roundTo = (x, prec = 1) => Math.round(x / prec) * prec;
const floorTo = (x, prec = 1) => Math.floor(x / prec) * prec;
const ceilTo = (x, prec = 1) => Math.ceil(x / prec) * prec;
const roundEps = (x, eps = EPS) => {
const f = fract(x);
return f <= eps || f >= 1 - eps ? Math.round(x) : x;
};
export {
ceilTo,
floorTo,
fract,
mod,
roundEps,
roundTo,
trunc
};

@@ -1,54 +0,37 @@

/**
* Returns iterator of all prime numbers ≤ given `x` using Sieve of
* Eratosthenes.
*
* @remarks
* Reference: https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
*
* @param x -
*/
export function* primesUntil(x) {
if (x < 1)
return;
yield 1;
const sieve = [];
const max = Math.sqrt(x) | 0;
for (let i = 2; i <= x; i++) {
if (!sieve[i]) {
yield i;
__updateSieve(sieve, i, x, max);
}
function* primesUntil(x) {
if (x < 1)
return;
yield 1;
const sieve = [];
const max = Math.sqrt(x) | 0;
for (let i = 2; i <= x; i++) {
if (!sieve[i]) {
yield i;
__updateSieve(sieve, i, x, max);
}
}
}
/**
* Returns largest prime number ≤ given `x` using Sieve of Eratosthenes. Returns
* -1 if x < 1.
*
* @remarks
* Reference: https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
*
* @param x -
*/
export const nearestPrime = (x) => {
if (x < 1)
return -1;
let prime = 1;
const sieve = [];
const max = Math.sqrt(x) | 0;
for (let i = 2; i <= x; i++) {
if (!sieve[i]) {
prime = i;
__updateSieve(sieve, i, x, max);
}
const nearestPrime = (x) => {
if (x < 1)
return -1;
let prime = 1;
const sieve = [];
const max = Math.sqrt(x) | 0;
for (let i = 2; i <= x; i++) {
if (!sieve[i]) {
prime = i;
__updateSieve(sieve, i, x, max);
}
return prime;
}
return prime;
};
/**
* @internal
*/
const __updateSieve = (sieve, i, x, max) => {
if (i <= max) {
for (let j = i * i; j <= x; j += i)
sieve[j] = true;
}
if (i <= max) {
for (let j = i * i; j <= x; j += i)
sieve[j] = true;
}
};
export {
nearestPrime,
primesUntil
};

@@ -1,18 +0,20 @@

export const simplifyRatio = (num, denom) => {
let e1 = Math.abs(num);
let e2 = Math.abs(denom);
while (true) {
if (e1 < e2) {
const t = e1;
e1 = e2;
e2 = t;
}
const r = e1 % e2;
if (r) {
e1 = r;
}
else {
return [num / e2, denom / e2];
}
const simplifyRatio = (num, denom) => {
let e1 = Math.abs(num);
let e2 = Math.abs(denom);
while (true) {
if (e1 < e2) {
const t = e1;
e1 = e2;
e2 = t;
}
const r = e1 % e2;
if (r) {
e1 = r;
} else {
return [num / e2, denom / e2];
}
}
};
export {
simplifyRatio
};

@@ -70,3 +70,3 @@ <!-- This file is generated - DO NOT EDIT! -->

Package sizes (brotli'd, pre-treeshake): ESM: 4.08 KB
Package sizes (brotli'd, pre-treeshake): ESM: 4.07 KB

@@ -73,0 +73,0 @@ ## Dependencies

@@ -1,7 +0,4 @@

/**
* Returns `a` divided by `b` or zero if `b = 0`.
*
* @param a -
* @param b -
*/
export const safeDiv = (a, b) => (b !== 0 ? a / b : 0);
const safeDiv = (a, b) => b !== 0 ? a / b : 0;
export {
safeDiv
};
import { EPS } from "./api.js";
import { safeDiv } from "./safe-div.js";
/**
* Produces a new function which computes derivative of the given single-arg
* function. The extra optional arg `eps` is used to define the step width for
* computing derived values:
*
* `f'(x) = (f(x + eps) - f(x)) / eps`
*
* The original function is assumed to be fully differentiable in the interval
* the returned function is going to be used. No validity checks of any form are
* done.
*
* https://en.wikipedia.org/wiki/Derivative#Continuity_and_differentiability
*
* @param fn -
* @param eps -
*/
export const derivative = (f, eps = EPS) => (x) => (f(x + eps) - f(x)) / eps;
/**
* Computes solution for linear equation: `ax + b = 0`.
*
* Note: Returns 0 iff `a == 0`
*
* @param a - slope
* @param b - constant offset
*/
export const solveLinear = (a, b) => safeDiv(-b, a);
/**
* Computes solutions for quadratic equation: `ax^2 + bx + c = 0`. Returns array
* of real solutions. Note: `a` MUST NOT be zero. If the quadratic term is
* missing, use {@link solveLinear} instead.
*
* - https://en.wikipedia.org/wiki/Quadratic_function
* - https://en.wikipedia.org/wiki/Quadratic_equation
*
* @param a - quadratic coefficient
* @param b - linear coefficient
* @param c - constant offset
* @param eps - tolerance to determine multiple roots
*/
export const solveQuadratic = (a, b, c, eps = 1e-9) => {
const d = 2 * a;
let r = b * b - 4 * a * c;
return r < 0
? []
: r < eps
? [-b / d]
: ((r = Math.sqrt(r)), [(-b - r) / d, (-b + r) / d]);
const derivative = (f, eps = EPS) => (x) => (f(x + eps) - f(x)) / eps;
const solveLinear = (a, b) => safeDiv(-b, a);
const solveQuadratic = (a, b, c, eps = 1e-9) => {
const d = 2 * a;
let r = b * b - 4 * a * c;
return r < 0 ? [] : r < eps ? [-b / d] : (r = Math.sqrt(r), [(-b - r) / d, (-b + r) / d]);
};
/**
* Computes solutions for quadratic equation: `ax^3 + bx^2 + c*x + d = 0`.
* Returns array of solutions, both real & imaginary. Note: `a` MUST NOT be
* zero. If the cubic term is missing (i.e. zero), use {@link solveQuadratic} or
* {@link solveLinear} instead.
*
* https://en.wikipedia.org/wiki/Cubic_function
*
* @param a - cubic coefficient
* @param b - quadratic coefficient
* @param c - linear coefficient
* @param d - constant offset
* @param eps - tolerance to determine multiple roots
*/
export const solveCubic = (a, b, c, d, eps = 1e-9) => {
const aa = a * a;
const bb = b * b;
const ba3 = b / (3 * a);
const p = (3 * a * c - bb) / (3 * aa);
const q = (2 * bb * b - 9 * a * b * c + 27 * aa * d) / (27 * aa * a);
if (Math.abs(p) < eps) {
return [Math.cbrt(-q) - ba3];
const solveCubic = (a, b, c, d, eps = 1e-9) => {
const aa = a * a;
const bb = b * b;
const ba3 = b / (3 * a);
const p = (3 * a * c - bb) / (3 * aa);
const q = (2 * bb * b - 9 * a * b * c + 27 * aa * d) / (27 * aa * a);
if (Math.abs(p) < eps) {
return [Math.cbrt(-q) - ba3];
} else if (Math.abs(q) < eps) {
return p < 0 ? [-Math.sqrt(-p) - ba3, -ba3, Math.sqrt(-p) - ba3] : [-ba3];
} else {
const denom = q * q / 4 + p * p * p / 27;
if (Math.abs(denom) < eps) {
return [-1.5 * q / p - ba3, 3 * q / p - ba3];
} else if (denom > 0) {
const u = Math.cbrt(-q / 2 - Math.sqrt(denom));
return [u - p / (3 * u) - ba3];
} else {
const u = 2 * Math.sqrt(-p / 3), t = Math.acos(3 * q / p / u) / 3, k = 2 * Math.PI / 3;
return [
u * Math.cos(t) - ba3,
u * Math.cos(t - k) - ba3,
u * Math.cos(t - 2 * k) - ba3
];
}
else if (Math.abs(q) < eps) {
return p < 0
? [-Math.sqrt(-p) - ba3, -ba3, Math.sqrt(-p) - ba3]
: [-ba3];
}
else {
const denom = (q * q) / 4 + (p * p * p) / 27;
if (Math.abs(denom) < eps) {
return [(-1.5 * q) / p - ba3, (3 * q) / p - ba3];
}
else if (denom > 0) {
const u = Math.cbrt(-q / 2 - Math.sqrt(denom));
return [u - p / (3 * u) - ba3];
}
else {
const u = 2 * Math.sqrt(-p / 3), t = Math.acos((3 * q) / p / u) / 3, k = (2 * Math.PI) / 3;
return [
u * Math.cos(t) - ba3,
u * Math.cos(t - k) - ba3,
u * Math.cos(t - 2 * k) - ba3,
];
}
}
}
};
export {
derivative,
solveCubic,
solveLinear,
solveQuadratic
};
import { clamp01 } from "./interval.js";
/**
* Step/threshold function.
*
* @param edge - threshold
* @param x - test value
* @returns 0, if `x < e`, else 1
*/
export const step = (edge, x) => (x < edge ? 0 : 1);
/**
* GLSL-style smoothStep threshold function.
*
* @remarks
* Also see {@link smoothStep01}, {@link smootherStep}.
*
* @param edge - lower threshold
* @param edge2 - upper threshold
* @param x - test value
* @returns 0, if `x < edge1`, 1 if `x > edge2`, else S-curve polynomial interpolation
*/
export const smoothStep = (edge, edge2, x) => smoothStep01(clamp01((x - edge) / (edge2 - edge)));
/**
* Specialized version of {@link smoothStep}, assuming edges are 0/1
* respectively and `x` is in [0..1]. No clamping performed.
*
* @param x
*/
export const smoothStep01 = (x) => x * x * (3 - 2 * x);
/**
* Similar to {@link smoothStep} but using different, higher degree polynomial.
*
* @remarks
* Also see {@link smootherStep01}.
*
* @param edge -
* @param edge2 -
* @param x -
*/
export const smootherStep = (edge, edge2, x) => smootherStep01(clamp01((x - edge) / (edge2 - edge)));
/**
* Specialized version of {@link smootherStep}, assuming edges are 0/1
* respectively and `x` is in [0..1]. No clamping performed.
*
* @param x
*/
export const smootherStep01 = (x) => x * x * x * (x * (x * 6 - 15) + 10);
/**
* Exponential ramp with variable shape
*
* @remarks
* Example configurations:
*
* - S-curve: k=8, n=4
* - Step near 1.0: k=8, n=20
* - Pulse: k=0.005, n=-10
* - Ease-in: k=0.5, n=0.25
*
* Interactive graph: https://www.desmos.com/calculator/gcnuyppycz
*
* @param k -
* @param n -
* @param x -
*/
export const expStep = (k, n, x) => 1 - Math.exp(-k * Math.pow(x, n));
const step = (edge, x) => x < edge ? 0 : 1;
const smoothStep = (edge, edge2, x) => smoothStep01(clamp01((x - edge) / (edge2 - edge)));
const smoothStep01 = (x) => x * x * (3 - 2 * x);
const smootherStep = (edge, edge2, x) => smootherStep01(clamp01((x - edge) / (edge2 - edge)));
const smootherStep01 = (x) => x * x * x * (x * (x * 6 - 15) + 10);
const expStep = (k, n, x) => 1 - Math.exp(-k * Math.pow(x, n));
export {
expStep,
smoothStep,
smoothStep01,
smootherStep,
smootherStep01,
step
};
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc