/**
 * CIE 1931 2° XYZ color matching functions (analytic approximation)
 *
 * Implementation based on:
 * Wyman, Sloan, Shirley (2013), "Simple Analytic Approximations to the CIE 1931 XYZ Color Matching Functions"
 * JCGT 2(2), 2013. http://jcgt.org/published/0002/02/01/
 *
 * Valid primarily over 380–780 nm. Outside this range, the functions return 0.
 * Returns unweighted CMFs (no illuminant). Weighting by illuminant SPD (e.g., D65)
 * should be applied by the caller during spectral integration when needed.
 */

// Helper for asymmetric Gaussian term from Wyman et al.
function gaussAsym(w, w0, sigmaL, sigmaR) {
    const t = (w - w0) * (w < w0 ? sigmaL : sigmaR);
    return Math.exp(-0.5 * t * t);
}

/**
 * Color-Matching Function in CIE XYZ space.
 *
 * Compute CIE 1931 2° x̄(λ), ȳ(λ), z̄(λ) using Wyman et al. analytic fits.
 *
 * This is the "multi-lobe" fit. The absolute error magnitude is under 0.05 across the spectrum according to the paper.
 *
 * @param {number[]} out length>=3
 * @param {number} wavelength_nm wavelength in nanometers
 * @returns {number[]} out
 */
export function xyz_cmf_wyman(out, wavelength_nm) {
    const w = wavelength_nm;

    // Return zeros outside the modeled range
    if (w < 380 || w > 780) {

        out[0] = 0;
        out[1] = 0;
        out[2] = 0;

        return out;

    }

    // x̄(λ)
    const x =
        + 0.362 * gaussAsym(w, 442.0, 0.0624, 0.0374)
        + 1.056 * gaussAsym(w, 599.8, 0.0264, 0.0323)
        - 0.065 * gaussAsym(w, 501.1, 0.0490, 0.0382);

    // ȳ(λ)
    const y =
        + 0.821 * gaussAsym(w, 568.8, 0.0213, 0.0247)
        + 0.286 * gaussAsym(w, 530.9, 0.0613, 0.0322);

    // z̄(λ)
    const z =
        + 1.217 * gaussAsym(w, 437.0, 0.0845, 0.0278)
        + 0.681 * gaussAsym(w, 459.0, 0.0385, 0.0725);

    out[0] = x;
    out[1] = y;
    out[2] = z;

    return out;
}
