thi-ng/umbrella

View on GitHub
packages/vectors/src/map-vectors.ts

Summary

Maintainability
A
25 mins
Test Coverage
import type {
    ReadonlyVec,
    VecOpVV,
    Vec,
    VecOpVN,
    VecOpVVV,
    VecOpVVN,
} from "./api.js";
import { isNumber } from "@thi.ng/checks/is-number";

/**
 * Takes a vec op `fn`, output array (or null) and a combination of the
 * following inputs:
 *
 * - 2 arrays of vectors
 * - 1 array of vectors & 1 scalar
 * - 3 arrays of vectors
 * - 2 arrays of vectors & 1 scalar
 *
 * Then applies `fn` to each input and writes result into output array,
 * returns `out` (or new array if `out` was given as null).
 *
 * @example
 * ```ts
 * import { addN2, mapVectors, mixN2 } from "@thi.ng/vectors";
 *
 * mapVectors(addN2, [], [[1, 2], [10, 20]], 100)
 * // [ [ 101, 102 ], [ 110, 120 ] ]
 *
 * mapVectors(add2, [], [[1, 2], [10, 20]], [[100, 200], [1000, 2000]])
 * // [ [ 101, 202 ], [ 1010, 2020 ] ]
 *
 * mapVectors(mixN2, null, [[1, 2], [100, 200]], [[10, 20], [1000, 2000]], 0.5)
 * // [ [ 5.5, 11 ], [ 550, 1100 ] ]
 * ```
 *
 * @param fn -
 * @param out -
 * @param a -
 * @param b -
 * @param c -
 */
export function mapVectors(
    fn: VecOpVV,
    out: Vec[] | null,
    a: ReadonlyVec[],
    b: ReadonlyVec[]
): Vec[];
export function mapVectors(
    fn: VecOpVN,
    out: Vec[] | null,
    a: ReadonlyVec[],
    n: number
): Vec[];
export function mapVectors(
    fn: VecOpVVV,
    out: Vec[] | null,
    a: ReadonlyVec[],
    b: ReadonlyVec[],
    c: ReadonlyVec[]
): Vec[];
export function mapVectors(
    fn: VecOpVVN,
    out: Vec[] | null,
    a: ReadonlyVec[],
    b: ReadonlyVec[],
    c: number
): Vec[];
export function mapVectors(
    fn: VecOpVV | VecOpVN | VecOpVVV | VecOpVVN,
    out: Vec[] | null,
    a: ReadonlyVec[],
    b: ReadonlyVec[] | number,
    c?: ReadonlyVec[] | number
): Vec[] {
    const num = a.length;
    !out && (out = new Array(num));
    c !== undefined
        ? isNumber(c)
            ? mapVVN(<VecOpVVN>fn, out, a, <ReadonlyVec[]>b, c)
            : mapVVV(<VecOpVVV>fn, out, a, <ReadonlyVec[]>b, c)
        : isNumber(b)
        ? mapVN(<VecOpVN>fn, out, a, b)
        : mapVV(<VecOpVV>fn, out, a, b);
    return out;
}

const mapVN = (fn: VecOpVN, out: Vec[], a: ReadonlyVec[], b: number) => {
    for (let i = 0, num = a.length; i < num; i++) {
        out[i] = fn(out[i] || [], a[i], b);
    }
};

const mapVV = (fn: VecOpVV, out: Vec[], a: ReadonlyVec[], b: ReadonlyVec[]) => {
    for (let i = 0, num = a.length; i < num; i++) {
        out[i] = fn(out[i] || [], a[i], b[i]);
    }
};

const mapVVN = (
    fn: VecOpVVN,
    out: Vec[],
    a: ReadonlyVec[],
    b: ReadonlyVec[],
    c: number
) => {
    for (let i = 0, num = a.length; i < num; i++) {
        out[i] = fn(out[i] || [], a[i], b[i], c);
    }
};

const mapVVV = (
    fn: VecOpVVV,
    out: Vec[],
    a: ReadonlyVec[],
    b: ReadonlyVec[],
    c: ReadonlyVec[]
) => {
    for (let i = 0, num = a.length; i < num; i++) {
        out[i] = fn(out[i] || [], a[i], b[i], c[i]);
    }
};