"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ipsAutoQuadify = exports.ipsErrorFitsIn = exports.vsNumberVec2 = exports.vsNumber = exports.vsQuadifyCurve = void 0;
const point_1 = require("../point/point");
function vsQuadifyCurve(vs, arc, n) {
    if (n < 1)
        throw new RangeError("vsQuadifyCurve: Must have at least 2 inner points");
    let knots = [];
    let zBefore = arc.eval(0), dBefore = arc.derivative(0);
    for (let k = 0; k < n; k++) {
        const tAfter = (k + 1) / n;
        const zAfter = arc.eval(tAfter);
        const dAfter = arc.derivative(tAfter);
        knots.push(vs.addScale(zBefore, 1 / (4 * n), dBefore));
        knots.push(vs.addScale(zAfter, -1 / (4 * n), dAfter));
        zBefore = zAfter;
        dBefore = dAfter;
    }
    return knots;
}
exports.vsQuadifyCurve = vsQuadifyCurve;
exports.vsNumber = {
    neutral: 0,
    addScale: (a, b, c) => a + b * c
};
exports.vsNumberVec2 = {
    neutral: new point_1.Offset2(0, 0),
    addScale: (a, b, c) => new point_1.Offset2(a.x + b * c.x, a.y + b * c.y),
    innerProduct: (a, b) => a.x * b.x + a.y * b.y
};
function ipsErrorFitsIn(ips, c, offPoints, squareError) {
    let zBefore = c.eval(0), dBefore = c.derivative(0);
    const n = offPoints.length;
    for (let j = 0; j < n; j++) {
        const zOffQu = offPoints[j];
        const tAfter = (j + 1) / n;
        const zAfter = c.eval(tAfter);
        const dAfter = c.derivative(tAfter);
        if (j % 2) {
            const zOffQuPrev = offPoints[j - 1];
            const zBeforeQu = vsMix(ips, zOffQu, zOffQuPrev, 1 / 2);
            const dBeforeQu = vsScale(ips, n, vsDifference(ips, zOffQu, zOffQuPrev));
            if (ipsSquareDist(ips, zBefore, zBeforeQu) > squareError)
                return false;
            if (ipsSquareDist(ips, dBefore, dBeforeQu) > 4 * n * n * squareError)
                return false;
        }
        zBefore = zAfter;
        dBefore = dAfter;
    }
    return true;
}
exports.ipsErrorFitsIn = ipsErrorFitsIn;
function ipsAutoQuadify(ips, c, allowError = 0.1, maxSegments = 32) {
    let results = null;
    for (let s = 1; s <= maxSegments; s++) {
        let offPoints = vsQuadifyCurve(ips, c, s);
        if (!offPoints || !offPoints.length)
            continue;
        if (ipsErrorFitsIn(ips, c, offPoints, allowError * allowError))
            return offPoints;
        results = offPoints;
    }
    return results;
}
exports.ipsAutoQuadify = ipsAutoQuadify;
function vsScale(vs, s, x) {
    return vs.addScale(vs.neutral, s, x);
}
function vsDifference(vs, a, b) {
    return vs.addScale(a, -1, b);
}
function vsMix(vs, a, b, p) {
    return vs.addScale(a, p, vsDifference(vs, b, a));
}
function ipsSquareDist(ips, a, b) {
    const d = vsDifference(ips, a, b);
    return ips.innerProduct(d, d);
}
