import { create as v2Create, distSquare as v2DistSquare } from './vector.js'; 
 | 
var mathPow = Math.pow; 
 | 
var mathSqrt = Math.sqrt; 
 | 
var EPSILON = 1e-8; 
 | 
var EPSILON_NUMERIC = 1e-4; 
 | 
var THREE_SQRT = mathSqrt(3); 
 | 
var ONE_THIRD = 1 / 3; 
 | 
var _v0 = v2Create(); 
 | 
var _v1 = v2Create(); 
 | 
var _v2 = v2Create(); 
 | 
function isAroundZero(val) { 
 | 
    return val > -EPSILON && val < EPSILON; 
 | 
} 
 | 
function isNotAroundZero(val) { 
 | 
    return val > EPSILON || val < -EPSILON; 
 | 
} 
 | 
export function cubicAt(p0, p1, p2, p3, t) { 
 | 
    var onet = 1 - t; 
 | 
    return onet * onet * (onet * p0 + 3 * t * p1) 
 | 
        + t * t * (t * p3 + 3 * onet * p2); 
 | 
} 
 | 
export function cubicDerivativeAt(p0, p1, p2, p3, t) { 
 | 
    var onet = 1 - t; 
 | 
    return 3 * (((p1 - p0) * onet + 2 * (p2 - p1) * t) * onet 
 | 
        + (p3 - p2) * t * t); 
 | 
} 
 | 
export function cubicRootAt(p0, p1, p2, p3, val, roots) { 
 | 
    var a = p3 + 3 * (p1 - p2) - p0; 
 | 
    var b = 3 * (p2 - p1 * 2 + p0); 
 | 
    var c = 3 * (p1 - p0); 
 | 
    var d = p0 - val; 
 | 
    var A = b * b - 3 * a * c; 
 | 
    var B = b * c - 9 * a * d; 
 | 
    var C = c * c - 3 * b * d; 
 | 
    var n = 0; 
 | 
    if (isAroundZero(A) && isAroundZero(B)) { 
 | 
        if (isAroundZero(b)) { 
 | 
            roots[0] = 0; 
 | 
        } 
 | 
        else { 
 | 
            var t1 = -c / b; 
 | 
            if (t1 >= 0 && t1 <= 1) { 
 | 
                roots[n++] = t1; 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
    else { 
 | 
        var disc = B * B - 4 * A * C; 
 | 
        if (isAroundZero(disc)) { 
 | 
            var K = B / A; 
 | 
            var t1 = -b / a + K; 
 | 
            var t2 = -K / 2; 
 | 
            if (t1 >= 0 && t1 <= 1) { 
 | 
                roots[n++] = t1; 
 | 
            } 
 | 
            if (t2 >= 0 && t2 <= 1) { 
 | 
                roots[n++] = t2; 
 | 
            } 
 | 
        } 
 | 
        else if (disc > 0) { 
 | 
            var discSqrt = mathSqrt(disc); 
 | 
            var Y1 = A * b + 1.5 * a * (-B + discSqrt); 
 | 
            var Y2 = A * b + 1.5 * a * (-B - discSqrt); 
 | 
            if (Y1 < 0) { 
 | 
                Y1 = -mathPow(-Y1, ONE_THIRD); 
 | 
            } 
 | 
            else { 
 | 
                Y1 = mathPow(Y1, ONE_THIRD); 
 | 
            } 
 | 
            if (Y2 < 0) { 
 | 
                Y2 = -mathPow(-Y2, ONE_THIRD); 
 | 
            } 
 | 
            else { 
 | 
                Y2 = mathPow(Y2, ONE_THIRD); 
 | 
            } 
 | 
            var t1 = (-b - (Y1 + Y2)) / (3 * a); 
 | 
            if (t1 >= 0 && t1 <= 1) { 
 | 
                roots[n++] = t1; 
 | 
            } 
 | 
        } 
 | 
        else { 
 | 
            var T = (2 * A * b - 3 * a * B) / (2 * mathSqrt(A * A * A)); 
 | 
            var theta = Math.acos(T) / 3; 
 | 
            var ASqrt = mathSqrt(A); 
 | 
            var tmp = Math.cos(theta); 
 | 
            var t1 = (-b - 2 * ASqrt * tmp) / (3 * a); 
 | 
            var t2 = (-b + ASqrt * (tmp + THREE_SQRT * Math.sin(theta))) / (3 * a); 
 | 
            var t3 = (-b + ASqrt * (tmp - THREE_SQRT * Math.sin(theta))) / (3 * a); 
 | 
            if (t1 >= 0 && t1 <= 1) { 
 | 
                roots[n++] = t1; 
 | 
            } 
 | 
            if (t2 >= 0 && t2 <= 1) { 
 | 
                roots[n++] = t2; 
 | 
            } 
 | 
            if (t3 >= 0 && t3 <= 1) { 
 | 
                roots[n++] = t3; 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
    return n; 
 | 
} 
 | 
export function cubicExtrema(p0, p1, p2, p3, extrema) { 
 | 
    var b = 6 * p2 - 12 * p1 + 6 * p0; 
 | 
    var a = 9 * p1 + 3 * p3 - 3 * p0 - 9 * p2; 
 | 
    var c = 3 * p1 - 3 * p0; 
 | 
    var n = 0; 
 | 
    if (isAroundZero(a)) { 
 | 
        if (isNotAroundZero(b)) { 
 | 
            var t1 = -c / b; 
 | 
            if (t1 >= 0 && t1 <= 1) { 
 | 
                extrema[n++] = t1; 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
    else { 
 | 
        var disc = b * b - 4 * a * c; 
 | 
        if (isAroundZero(disc)) { 
 | 
            extrema[0] = -b / (2 * a); 
 | 
        } 
 | 
        else if (disc > 0) { 
 | 
            var discSqrt = mathSqrt(disc); 
 | 
            var t1 = (-b + discSqrt) / (2 * a); 
 | 
            var t2 = (-b - discSqrt) / (2 * a); 
 | 
            if (t1 >= 0 && t1 <= 1) { 
 | 
                extrema[n++] = t1; 
 | 
            } 
 | 
            if (t2 >= 0 && t2 <= 1) { 
 | 
                extrema[n++] = t2; 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
    return n; 
 | 
} 
 | 
export function cubicSubdivide(p0, p1, p2, p3, t, out) { 
 | 
    var p01 = (p1 - p0) * t + p0; 
 | 
    var p12 = (p2 - p1) * t + p1; 
 | 
    var p23 = (p3 - p2) * t + p2; 
 | 
    var p012 = (p12 - p01) * t + p01; 
 | 
    var p123 = (p23 - p12) * t + p12; 
 | 
    var p0123 = (p123 - p012) * t + p012; 
 | 
    out[0] = p0; 
 | 
    out[1] = p01; 
 | 
    out[2] = p012; 
 | 
    out[3] = p0123; 
 | 
    out[4] = p0123; 
 | 
    out[5] = p123; 
 | 
    out[6] = p23; 
 | 
    out[7] = p3; 
 | 
} 
 | 
export function cubicProjectPoint(x0, y0, x1, y1, x2, y2, x3, y3, x, y, out) { 
 | 
    var t; 
 | 
    var interval = 0.005; 
 | 
    var d = Infinity; 
 | 
    var prev; 
 | 
    var next; 
 | 
    var d1; 
 | 
    var d2; 
 | 
    _v0[0] = x; 
 | 
    _v0[1] = y; 
 | 
    for (var _t = 0; _t < 1; _t += 0.05) { 
 | 
        _v1[0] = cubicAt(x0, x1, x2, x3, _t); 
 | 
        _v1[1] = cubicAt(y0, y1, y2, y3, _t); 
 | 
        d1 = v2DistSquare(_v0, _v1); 
 | 
        if (d1 < d) { 
 | 
            t = _t; 
 | 
            d = d1; 
 | 
        } 
 | 
    } 
 | 
    d = Infinity; 
 | 
    for (var i = 0; i < 32; i++) { 
 | 
        if (interval < EPSILON_NUMERIC) { 
 | 
            break; 
 | 
        } 
 | 
        prev = t - interval; 
 | 
        next = t + interval; 
 | 
        _v1[0] = cubicAt(x0, x1, x2, x3, prev); 
 | 
        _v1[1] = cubicAt(y0, y1, y2, y3, prev); 
 | 
        d1 = v2DistSquare(_v1, _v0); 
 | 
        if (prev >= 0 && d1 < d) { 
 | 
            t = prev; 
 | 
            d = d1; 
 | 
        } 
 | 
        else { 
 | 
            _v2[0] = cubicAt(x0, x1, x2, x3, next); 
 | 
            _v2[1] = cubicAt(y0, y1, y2, y3, next); 
 | 
            d2 = v2DistSquare(_v2, _v0); 
 | 
            if (next <= 1 && d2 < d) { 
 | 
                t = next; 
 | 
                d = d2; 
 | 
            } 
 | 
            else { 
 | 
                interval *= 0.5; 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
    if (out) { 
 | 
        out[0] = cubicAt(x0, x1, x2, x3, t); 
 | 
        out[1] = cubicAt(y0, y1, y2, y3, t); 
 | 
    } 
 | 
    return mathSqrt(d); 
 | 
} 
 | 
export function cubicLength(x0, y0, x1, y1, x2, y2, x3, y3, iteration) { 
 | 
    var px = x0; 
 | 
    var py = y0; 
 | 
    var d = 0; 
 | 
    var step = 1 / iteration; 
 | 
    for (var i = 1; i <= iteration; i++) { 
 | 
        var t = i * step; 
 | 
        var x = cubicAt(x0, x1, x2, x3, t); 
 | 
        var y = cubicAt(y0, y1, y2, y3, t); 
 | 
        var dx = x - px; 
 | 
        var dy = y - py; 
 | 
        d += Math.sqrt(dx * dx + dy * dy); 
 | 
        px = x; 
 | 
        py = y; 
 | 
    } 
 | 
    return d; 
 | 
} 
 | 
export function quadraticAt(p0, p1, p2, t) { 
 | 
    var onet = 1 - t; 
 | 
    return onet * (onet * p0 + 2 * t * p1) + t * t * p2; 
 | 
} 
 | 
export function quadraticDerivativeAt(p0, p1, p2, t) { 
 | 
    return 2 * ((1 - t) * (p1 - p0) + t * (p2 - p1)); 
 | 
} 
 | 
export function quadraticRootAt(p0, p1, p2, val, roots) { 
 | 
    var a = p0 - 2 * p1 + p2; 
 | 
    var b = 2 * (p1 - p0); 
 | 
    var c = p0 - val; 
 | 
    var n = 0; 
 | 
    if (isAroundZero(a)) { 
 | 
        if (isNotAroundZero(b)) { 
 | 
            var t1 = -c / b; 
 | 
            if (t1 >= 0 && t1 <= 1) { 
 | 
                roots[n++] = t1; 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
    else { 
 | 
        var disc = b * b - 4 * a * c; 
 | 
        if (isAroundZero(disc)) { 
 | 
            var t1 = -b / (2 * a); 
 | 
            if (t1 >= 0 && t1 <= 1) { 
 | 
                roots[n++] = t1; 
 | 
            } 
 | 
        } 
 | 
        else if (disc > 0) { 
 | 
            var discSqrt = mathSqrt(disc); 
 | 
            var t1 = (-b + discSqrt) / (2 * a); 
 | 
            var t2 = (-b - discSqrt) / (2 * a); 
 | 
            if (t1 >= 0 && t1 <= 1) { 
 | 
                roots[n++] = t1; 
 | 
            } 
 | 
            if (t2 >= 0 && t2 <= 1) { 
 | 
                roots[n++] = t2; 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
    return n; 
 | 
} 
 | 
export function quadraticExtremum(p0, p1, p2) { 
 | 
    var divider = p0 + p2 - 2 * p1; 
 | 
    if (divider === 0) { 
 | 
        return 0.5; 
 | 
    } 
 | 
    else { 
 | 
        return (p0 - p1) / divider; 
 | 
    } 
 | 
} 
 | 
export function quadraticSubdivide(p0, p1, p2, t, out) { 
 | 
    var p01 = (p1 - p0) * t + p0; 
 | 
    var p12 = (p2 - p1) * t + p1; 
 | 
    var p012 = (p12 - p01) * t + p01; 
 | 
    out[0] = p0; 
 | 
    out[1] = p01; 
 | 
    out[2] = p012; 
 | 
    out[3] = p012; 
 | 
    out[4] = p12; 
 | 
    out[5] = p2; 
 | 
} 
 | 
export function quadraticProjectPoint(x0, y0, x1, y1, x2, y2, x, y, out) { 
 | 
    var t; 
 | 
    var interval = 0.005; 
 | 
    var d = Infinity; 
 | 
    _v0[0] = x; 
 | 
    _v0[1] = y; 
 | 
    for (var _t = 0; _t < 1; _t += 0.05) { 
 | 
        _v1[0] = quadraticAt(x0, x1, x2, _t); 
 | 
        _v1[1] = quadraticAt(y0, y1, y2, _t); 
 | 
        var d1 = v2DistSquare(_v0, _v1); 
 | 
        if (d1 < d) { 
 | 
            t = _t; 
 | 
            d = d1; 
 | 
        } 
 | 
    } 
 | 
    d = Infinity; 
 | 
    for (var i = 0; i < 32; i++) { 
 | 
        if (interval < EPSILON_NUMERIC) { 
 | 
            break; 
 | 
        } 
 | 
        var prev = t - interval; 
 | 
        var next = t + interval; 
 | 
        _v1[0] = quadraticAt(x0, x1, x2, prev); 
 | 
        _v1[1] = quadraticAt(y0, y1, y2, prev); 
 | 
        var d1 = v2DistSquare(_v1, _v0); 
 | 
        if (prev >= 0 && d1 < d) { 
 | 
            t = prev; 
 | 
            d = d1; 
 | 
        } 
 | 
        else { 
 | 
            _v2[0] = quadraticAt(x0, x1, x2, next); 
 | 
            _v2[1] = quadraticAt(y0, y1, y2, next); 
 | 
            var d2 = v2DistSquare(_v2, _v0); 
 | 
            if (next <= 1 && d2 < d) { 
 | 
                t = next; 
 | 
                d = d2; 
 | 
            } 
 | 
            else { 
 | 
                interval *= 0.5; 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
    if (out) { 
 | 
        out[0] = quadraticAt(x0, x1, x2, t); 
 | 
        out[1] = quadraticAt(y0, y1, y2, t); 
 | 
    } 
 | 
    return mathSqrt(d); 
 | 
} 
 | 
export function quadraticLength(x0, y0, x1, y1, x2, y2, iteration) { 
 | 
    var px = x0; 
 | 
    var py = y0; 
 | 
    var d = 0; 
 | 
    var step = 1 / iteration; 
 | 
    for (var i = 1; i <= iteration; i++) { 
 | 
        var t = i * step; 
 | 
        var x = quadraticAt(x0, x1, x2, t); 
 | 
        var y = quadraticAt(y0, y1, y2, t); 
 | 
        var dx = x - px; 
 | 
        var dy = y - py; 
 | 
        d += Math.sqrt(dx * dx + dy * dy); 
 | 
        px = x; 
 | 
        py = y; 
 | 
    } 
 | 
    return d; 
 | 
} 
 |