/**
 * pacem v0.51.10-faraday (https://js.pacem.it)
 * Copyright 2025 Pacem (https://pacem.it)
 * Licensed under Apache-2.0
 */
var Pacem;
(function (Pacem) {
    var Geometry;
    (function (Geometry) {
        var LinearAlgebra;
        (function (LinearAlgebra) {
            class Vector {
                static unit(v) {
                    const clone = { x: v.x, y: v.y };
                    this.normalize(clone);
                    return clone;
                }
                static magSqr(v) {
                    return v.x * v.x + v.y * v.y;
                }
                static mag(v) {
                    return Math.sqrt(Vector.magSqr(v));
                }
                static normalize(v) {
                    const l = Vector.mag(v);
                    if (l <= 0) {
                        throw 'Cannot normalize a vector of length 0.';
                    }
                    const inv = 1 / l;
                    v.x *= inv;
                    v.y *= inv;
                }
                static from(p1, p2) {
                    return Pacem.Point.subtract(p1, p2);
                }
                static dot(v1, v2) {
                    return v1.x * v2.x + v1.y * v2.y;
                }
                static cross(v1, v2) {
                    return v1.x * v2.y - v1.y * v2.x;
                }
            }
            LinearAlgebra.Vector = Vector;
        })(LinearAlgebra = Geometry.LinearAlgebra || (Geometry.LinearAlgebra = {}));
    })(Geometry = Pacem.Geometry || (Pacem.Geometry = {}));
})(Pacem || (Pacem = {}));
var Pacem;
(function (Pacem) {
    var Geometry;
    (function (Geometry) {
        const RAD2DEG = 180.0 / Math.PI;
        const RAD_ROUND = 2 * Math.PI;
        const Vector = Geometry.LinearAlgebra.Vector;
        function isPoint(p) {
            return Pacem.Point.isPoint(p);
        }
        function isSegment(s) {
            return s != null && Array.isArray(s) && s.length === 2
                && isPoint(s[0]) && isPoint(s[1]);
        }
        class Utils {
            static slopeRad(p1, p2) {
                return Math.atan2(p2.y - p1.y, p2.x - p1.x);
            }
            static slopeRad2(p1, p2) {
                return (RAD_ROUND + this.slopeRad(p1, p2)) % RAD_ROUND;
            }
            static slopeDeg(p1, p2) {
                return this.slopeRad(p1, p2) * RAD2DEG;
            }
            static slopeDeg2(p1, p2) {
                return (360 + this.slopeDeg(p1, p2)) % 360;
            }
            static intersect(arg1, arg2, ...args) {
                if (Array.isArray(arg1) && Array.isArray(arg2)) {
                    return this._intersectSegments(arg1, arg2, true);
                }
                else {
                    return this._intersectRects.apply(this, arguments);
                }
            }
            static intersectLines(segment1, segment2, m2, q2) {
                let s1, s2;
                if (Array.isArray(segment1) && Array.isArray(segment2)
                    && segment1.length === 2 && segment2.length === 2
                    && typeof segment1[0] === 'number' && typeof segment2[0] === 'number' && typeof segment1[1] === 'number' && typeof segment2[1] === 'number') {
                    m2 = segment2[0];
                    q2 = segment2[1];
                    segment2 = segment1[1];
                    segment1 = segment1[0];
                }
                if (typeof segment1 === 'number' && typeof segment2 === 'number') {
                    const m1 = segment1, q1 = segment2;
                    s1 = [
                        { x: 0, y: q1 },
                        { x: 1, y: m1 + q1 }
                    ];
                    s2 = [
                        { x: 0, y: q2 },
                        { x: 1, y: m2 + q2 }
                    ];
                }
                else {
                    s1 = segment1;
                    s2 = segment2;
                }
                return this._intersectSegments(s1, s2, false);
            }
            static cramer(l1, l2) {
                if (Array.isArray(l1)) {
                    l1 = { a: l1[0], b: l1[1], c: l1[2] };
                }
                if (Array.isArray(l2)) {
                    l2 = { a: l2[0], b: l2[1], c: l2[2] };
                }
                let xP = (l1.b * l2.c - l1.c * l2.b) / (l1.b * l2.a - l1.a * l2.b), yP = (l1.c * l2.a - l1.a * l2.c) / (l1.b * l2.a - l1.a * l2.b);
                return { x: -xP.roundoff(), y: -yP.roundoff() };
            }
            static mq(arg0, p2) {
                let p1;
                if (isPoint(arg0)) {
                    p1 = arg0;
                }
                else {
                    p1 = arg0[0];
                    p2 = arg0[1];
                }
                if (p1.x === p2.x) {
                    return [Number.NaN, Number.NaN];
                }
                const m = (p2.y - p1.y) / (p2.x - p1.x);
                const q = p1.y - m * p1.x;
                return [m, q];
            }
            static _intersectSegments(segment1, segment2, excludeProjection) {
                const A = segment1[0], B = segment1[1], C = segment2[0], D = segment2[1], xAB = Math.min(A.x, B.x), yAB = Math.min(A.y, B.y), XAB = Math.max(A.x, B.x), wAB = XAB - xAB, YAB = Math.max(A.y, B.y), hAB = YAB - yAB, xCD = Math.min(C.x, D.x), yCD = Math.min(C.y, D.y), XCD = Math.max(C.x, D.x), wCD = XCD - xCD, YCD = Math.max(C.y, D.y), hCD = YCD - yCD;
                if (wAB === 0 && wCD === 0) {
                    return null;
                }
                if (hAB === 0 && hCD === 0) {
                    return null;
                }
                const outOfXBounds = (p) => {
                    return p.x < xCD || p.x > XCD || p.x < xAB || p.x > XAB;
                };
                const outOfYBounds = (p) => {
                    return p.y < yCD || p.y > YCD || p.y < yAB || p.y > YAB;
                };
                var retval = null;
                if (wAB === 0) {
                    if (excludeProjection && (xCD > xAB || XCD < XAB)) {
                        return null;
                    }
                    const mqCD = this.mq(C, D);
                    retval = this.cramer([1, 0, -xAB], [mqCD[0], -1, mqCD[1]]);
                    if (excludeProjection && outOfYBounds(retval)) {
                        retval = null;
                    }
                }
                else if (wCD === 0) {
                    if (excludeProjection && (xAB > xCD || XAB < XCD)) {
                        return null;
                    }
                    const mqAB = this.mq(A, B);
                    retval = this.cramer([mqAB[0], -1, mqAB[1]], [1, 0, -xCD]);
                    if (excludeProjection && outOfYBounds(retval)) {
                        retval = null;
                    }
                }
                else if (hAB === 0) {
                    if (excludeProjection && (yCD > yAB || YCD < YAB)) {
                        return null;
                    }
                    const mqCD = this.mq(C, D);
                    retval = this.cramer([0, 1, -yAB], [mqCD[0], -1, mqCD[1]]);
                    if (excludeProjection && outOfXBounds(retval)) {
                        retval = null;
                    }
                }
                else if (hCD === 0) {
                    if (excludeProjection && (yAB > yCD || YAB < YCD)) {
                        return null;
                    }
                    const mqAB = this.mq(A, B);
                    retval = this.cramer([mqAB[0], -1, mqAB[1]], [0, 1, -yCD]);
                    if (excludeProjection && outOfXBounds(retval)) {
                        retval = null;
                    }
                }
                else {
                    let intersection;
                    if (!excludeProjection ||
                        ((intersection = this._intersectRects({ x: xAB, y: yAB, width: wAB, height: hAB }, { x: xCD, y: yCD, width: wCD, height: hCD }))
                            && intersection.width > 0
                            && intersection.height > 0)) {
                        const mqAB = this.mq(A, B), mqCD = this.mq(C, D);
                        const mAB = mqAB[0], mCD = mqCD[0], qAB = mqAB[1], qCD = mqCD[1];
                        if (mAB !== mCD) {
                            retval = this.cramer([mAB, -1, qAB], [mCD, -1, qCD]);
                            let xR = retval.x, yR = retval.y;
                            if (excludeProjection
                                && (xR < intersection.x || xR > (intersection.x + intersection.width)
                                    || yR < intersection.y || yR > (intersection.y + intersection.height))) {
                                retval = null;
                            }
                        }
                    }
                }
                if (retval === null) {
                    return null;
                }
                return { x: retval.x, y: retval.y };
            }
            static _intersectRects(...args) {
                return Pacem.Rect.intersect.apply(this, args);
            }
            static dot(v1, v2) {
                return Vector.dot(v1, v2);
            }
            static cross(v1, v2) {
                return Vector.cross(v1, v2);
            }
            static distance(p1, arg2) {
                if (isSegment(p1)) {
                    return Pacem.Point.distance(p1[0], p1[1]);
                }
                else if (isPoint(arg2)) {
                    return Pacem.Point.distance(p1, arg2);
                }
                else {
                    const m = arg2[0], q = arg2[1];
                    return Math.abs(m * p1.x - p1.y + q) / Math.sqrt(Math.pow(m, 2) + 1);
                }
            }
            static inLine(p, segment) {
                const v1 = Vector.from(segment[0], p), v2 = Vector.from(p, segment[1]);
                const prod = this.cross(v1, v2);
                return prod.isCloseTo(0);
            }
            static inSegment(p, segment) {
                const minx = Math.min(segment[0].x, segment[1].x), maxx = Math.max(segment[0].x, segment[1].x), miny = Math.min(segment[0].y, segment[1].y), maxy = Math.max(segment[0].y, segment[1].y);
                return p.x >= minx && p.x <= maxx && p.y >= miny && p.y <= maxy && this.inLine(p, segment);
            }
            static inTriangle(p, triangle) {
                let last;
                for (let j = 0; j < 3; j++) {
                    const p1 = triangle[j], p2 = triangle[(j + 1) % 3], v1 = Pacem.Point.subtract(p2, p), v2 = Pacem.Point.subtract(p1, p), current = this.cross(v1, v2);
                    if (j > 0 && (current * last) <= 0) {
                        return false;
                    }
                    last = current;
                }
                return true;
            }
            static inPolygon(p, vertices, precision) {
                if (!(vertices?.length >= 3)) {
                    throw `Not enough vertices`;
                }
                const length = vertices.length;
                if (length === 3) {
                    return this.inTriangle(p, [vertices[0], vertices[1], vertices[2]]);
                }
                if (precision > 0) {
                    vertices = vertices.map(v => { return { x: v.x.roundoff(precision), y: v.y.roundoff(precision) }; });
                    p = { x: p.x.roundoff(precision), y: p.y.roundoff(precision) };
                }
                let minx = Number.MAX_VALUE, miny = Number.MAX_VALUE, maxx = Number.MIN_VALUE, maxy = Number.MIN_VALUE;
                for (let j = 0; j < length; j++) {
                    const v = vertices[j];
                    minx = Math.min(minx, v.x);
                    miny = Math.min(miny, v.y);
                    maxx = Math.max(maxx, v.x);
                    maxy = Math.max(maxy, v.y);
                }
                if (p.x < minx || p.x > maxx || p.y < miny || p.y > maxy) {
                    return false;
                }
                const outerPoint = { x: minx - 1, y: p.y }, test = [outerPoint, p];
                let intersections = 0;
                for (let j = 0; j < length; j++) {
                    const p1 = vertices[j], p2 = vertices[(j + 1) % length], side = [p1, p2];
                    if (p1.y === p.y) {
                        const p0 = vertices[(j - 1 + length) % length];
                        if (p.x > p1.x && (p0.y - p.y) * (p2.y - p.y) < 0) {
                            intersections++;
                        }
                    }
                    else if (p2.y === p.y) {
                        continue;
                    }
                    else {
                        if (this.intersect(side, test) != null) {
                            intersections++;
                        }
                    }
                }
                return intersections % 2 === 1;
            }
            static area(point, ...points) {
                const pts = [].concat(point).concat(points);
                let retval = 0;
                const length = pts.length;
                if (length >= 3) {
                    for (let j = 0; j < pts.length; j++) {
                        const { x: xj, y: yj } = pts[j], next = j === (length - 1) ? 0 : j + 1, { x: xnext, y: ynext } = pts[next];
                        retval += (xj * ynext - yj * xnext);
                    }
                    retval *= .5;
                }
                return Math.abs(retval.roundoff());
            }
        }
        Geometry.Utils = Utils;
    })(Geometry = Pacem.Geometry || (Pacem.Geometry = {}));
})(Pacem || (Pacem = {}));
var Pacem;
(function (Pacem) {
    var Geometry;
    (function (Geometry) {
        var LinearAlgebra;
        (function (LinearAlgebra) {
            const RAD2DEG = 180.0 / Math.PI;
            const DEG2RAD = 1.0 / RAD2DEG;
            class Vector3D {
                static from(...args) {
                    const l = 3;
                    if (args.length !== l) {
                        throw new RangeError(`Must provide exactly ${l} numbers`);
                    }
                    return { x: args[0], y: args[1], z: args[2] };
                }
                static parse(input) {
                    const arr = Pacem.parseAsNumericalArray(input);
                    if (arr && arr.length === 3) {
                        return Vector3D.from.apply(null, arr);
                    }
                    throw new Error(`Cannot parse "${input}" as a valid Vector3D.`);
                }
                static i() {
                    return { x: 1, y: 0, z: 0 };
                }
                static j() {
                    return { x: 0, y: 1, z: 0 };
                }
                static k() {
                    return { x: 0, y: 0, z: 1 };
                }
                static zero() {
                    return { x: 0, y: 0, z: 0 };
                }
                static subtract(p, from) {
                    return { x: from.x - p.x, y: from.y - p.y, z: from.z - p.z };
                }
                static add(...points) {
                    var point = { x: 0, y: 0, z: 0 };
                    for (var p of points) {
                        point.x += p.x;
                        point.y += p.y;
                        point.z += p.z;
                    }
                    return point;
                }
                static dot(v1, v2) {
                    return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
                }
                static cross(v1, v2) {
                    return {
                        x: (v1.y * v2.z) - (v1.z * v2.y),
                        y: (v1.z * v2.x) - (v1.x * v2.z),
                        z: (v1.x * v2.y) - (v1.y * v2.x)
                    };
                }
                static scale(v, fx, fy = fx, fz = fx) {
                    return { x: v.x * fx, y: v.y * fy, z: v.z * fz };
                }
                static magSqr(v) {
                    return v.x * v.x + v.y * v.y + v.z * v.z;
                }
                static mag(v) {
                    return Math.sqrt(Vector3D.magSqr(v));
                }
                static negate(v) {
                    return { x: -v.x, y: -v.y, z: -v.z };
                }
                static unit(v) {
                    const clone = { x: v.x, y: v.y, z: v.z };
                    this.normalize(clone);
                    return clone;
                }
                static normalize(v) {
                    const l = Vector3D.mag(v);
                    if (l <= 0) {
                        throw 'Cannot normalize a vector of length 0.';
                    }
                    const inv = 1 / l;
                    v.x *= inv;
                    v.y *= inv;
                    v.z *= inv;
                }
                static angleBetween(vector1, vector2) {
                    let num;
                    const v1 = Vector3D.unit(vector1);
                    const v2 = Vector3D.unit(vector2);
                    const dot = Vector3D.dot(v1, v2);
                    if (dot < 0.0) {
                        const vectord = { x: -v1.x - v2.x, y: -v1.y - v2.y, z: -v1.z - v2.z };
                        const length = Vector3D.mag(vectord);
                        num = Math.PI - (2.0 * Math.asin(length / 2.0));
                    }
                    else {
                        const vectord = { x: v1.x - v2.x, y: v1.y - v2.y, z: v1.z - v2.z };
                        const length = Vector3D.mag(vectord);
                        num = 2.0 * Math.asin(length / 2.0);
                    }
                    return RAD2DEG * num;
                }
            }
            LinearAlgebra.Vector3D = Vector3D;
            class Spherical {
                static from(rho, theta, phi) {
                    return { rho: rho.clamp(0, Infinity), theta: theta.clamp(-180, 180), phi: phi.clamp(0, 360) };
                }
                static fromVector(v, y, z) {
                    if (typeof v === 'number') {
                        v = Vector3D.from(v, y, z);
                    }
                    const rho = Vector3D.mag(v);
                    if (rho.isCloseTo(0)) {
                        return Spherical.from(0, 0, 0);
                    }
                    const theta = Math.atan2(v.x, v.z), phi = Math.acos((v.y / rho).clamp(-1, 1));
                    return Spherical.from(rho, theta * RAD2DEG, phi * RAD2DEG);
                }
                static toVector(coords) {
                    const { rho, theta: thetaDeg, phi: phiDeg } = coords;
                    const phi = phiDeg * DEG2RAD;
                    const theta = thetaDeg * DEG2RAD;
                    const sinPhiRho = Math.sin(phi) * rho;
                    return {
                        x: sinPhiRho * Math.sin(theta),
                        y: Math.cos(phi) * rho,
                        z: sinPhiRho * Math.cos(theta)
                    };
                }
                static toRotationMatrix(coords) {
                    const { theta, phi } = coords;
                    const t = DEG2RAD * theta, sinTheta = Math.sin(t), cosTheta = Math.cos(t), p = DEG2RAD * phi, sinPhi = Math.sin(p), cosPhi = Math.cos(p);
                    return Matrix3D.from(sinTheta * cosPhi, sinTheta * sinPhi, cosTheta, 0, cosTheta * cosPhi, cosTheta * sinPhi, -sinTheta, 0, -sinPhi, cosPhi, 0, 0, 0, 0, 0, 1);
                }
            }
            LinearAlgebra.Spherical = Spherical;
            class Matrix3DUtils {
                static modify(m, action) {
                    const { m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, offsetX, offsetY, offsetZ, m44 } = m;
                    const retval = {
                        m11, m12, m13, m14,
                        m21, m22, m23, m24,
                        m31, m32, m33, m34,
                        offsetX, offsetY, offsetZ, m44
                    };
                    action(retval);
                    return retval;
                }
                static clone(m) {
                    return Matrix3DUtils.modify(m, _ => { });
                }
                static multiply(m1, m2) {
                    if (Matrix3D.isIdentity(m1))
                        return m2;
                    if (Matrix3D.isIdentity(m2))
                        return m1;
                    return Matrix3D.from((((m1.m11 * m2.m11) + (m1.m12 * m2.m21)) + (m1.m13 * m2.m31)) + (m1.m14 * m2.offsetX), (((m1.m11 * m2.m12) + (m1.m12 * m2.m22)) + (m1.m13 * m2.m32)) + (m1.m14 * m2.offsetY), (((m1.m11 * m2.m13) + (m1.m12 * m2.m23)) + (m1.m13 * m2.m33)) + (m1.m14 * m2.offsetZ), (((m1.m11 * m2.m14) + (m1.m12 * m2.m24)) + (m1.m13 * m2.m34)) + (m1.m14 * m2.m44), (((m1.m21 * m2.m11) + (m1.m22 * m2.m21)) + (m1.m23 * m2.m31)) + (m1.m24 * m2.offsetX), (((m1.m21 * m2.m12) + (m1.m22 * m2.m22)) + (m1.m23 * m2.m32)) + (m1.m24 * m2.offsetY), (((m1.m21 * m2.m13) + (m1.m22 * m2.m23)) + (m1.m23 * m2.m33)) + (m1.m24 * m2.offsetZ), (((m1.m21 * m2.m14) + (m1.m22 * m2.m24)) + (m1.m23 * m2.m34)) + (m1.m24 * m2.m44), (((m1.m31 * m2.m11) + (m1.m32 * m2.m21)) + (m1.m33 * m2.m31)) + (m1.m34 * m2.offsetX), (((m1.m31 * m2.m12) + (m1.m32 * m2.m22)) + (m1.m33 * m2.m32)) + (m1.m34 * m2.offsetY), (((m1.m31 * m2.m13) + (m1.m32 * m2.m23)) + (m1.m33 * m2.m33)) + (m1.m34 * m2.offsetZ), (((m1.m31 * m2.m14) + (m1.m32 * m2.m24)) + (m1.m33 * m2.m34)) + (m1.m34 * m2.m44), (((m1.offsetX * m2.m11) + (m1.offsetY * m2.m21)) + (m1.offsetZ * m2.m31)) + (m1.m44 * m2.offsetX), (((m1.offsetX * m2.m12) + (m1.offsetY * m2.m22)) + (m1.offsetZ * m2.m32)) + (m1.m44 * m2.offsetY), (((m1.offsetX * m2.m13) + (m1.offsetY * m2.m23)) + (m1.offsetZ * m2.m33)) + (m1.m44 * m2.offsetZ), (((m1.offsetX * m2.m14) + (m1.offsetY * m2.m24)) + (m1.offsetZ * m2.m34)) + (m1.m44 * m2.m44));
                }
            }
            class Matrix3D {
                static identity() {
                    return {
                        m11: 1, m12: 0, m13: 0, m14: 0,
                        m21: 0, m22: 1, m23: 0, m24: 0,
                        m31: 0, m32: 0, m33: 1, m34: 0,
                        offsetX: 0, offsetY: 0, offsetZ: 0, m44: 1
                    };
                }
                static from(...args) {
                    const l = 16;
                    if (args.length !== l) {
                        throw new RangeError(`Must provide exactly ${l} numbers`);
                    }
                    return {
                        m11: args[0],
                        m12: args[1],
                        m13: args[2],
                        m14: args[3],
                        m21: args[4],
                        m22: args[5],
                        m23: args[6],
                        m24: args[7],
                        m31: args[8],
                        m32: args[9],
                        m33: args[10],
                        m34: args[11],
                        offsetX: args[12],
                        offsetY: args[13],
                        offsetZ: args[14],
                        m44: args[15]
                    };
                }
                static transpose(m) {
                    return Matrix3D.from(m.m11, m.m21, m.m31, m.offsetX, m.m12, m.m22, m.m32, m.offsetY, m.m13, m.m23, m.m33, m.offsetZ, m.m14, m.m24, m.m34, m.m44);
                }
                static toArray(m) {
                    return [m.m11, m.m12, m.m13, m.m14,
                        m.m21, m.m22, m.m23, m.m24,
                        m.m31, m.m32, m.m33, m.m34,
                        m.offsetX, m.offsetY, m.offsetZ, m.m44];
                }
                static clone(m, modifier) {
                    return typeof modifier === 'function' ? Matrix3DUtils.modify(m, modifier) : Matrix3DUtils.clone(m);
                }
                static scale(m, x, y, z) {
                    if (typeof x === 'number') {
                        y ??= x;
                        z ??= x;
                    }
                    else {
                        z = x.z;
                        y = x.y;
                        x = x.x;
                    }
                    return Matrix3DUtils.modify(m, s => {
                        s.m11 *= x;
                        s.m22 *= y;
                        s.m33 *= z;
                    });
                }
                static translate(m, offset) {
                    return Matrix3DUtils.modify(m, s => {
                        s.offsetX += offset.x;
                        s.offsetY += offset.y;
                        s.offsetZ += offset.z;
                    });
                }
                static parse(input) {
                    const arr = Pacem.parseAsNumericalArray(input);
                    if (arr && arr.length === 16) {
                        return Matrix3D.from.apply(null, arr);
                    }
                    throw new Error(`Cannot parse "${input}" as a valid Matrix3D.`);
                }
                static isIdentity(m) {
                    return m.m11 == 1.0 && m.m12 == .0 && m.m13 == .0 && m.m14 == .0
                        && m.m21 == .0 && m.m22 == 1.0 && m.m23 == .0 && m.m24 == .0
                        && m.m31 == .0 && m.m32 == .0 && m.m33 == 1.0 && m.m34 == .0
                        && m.offsetX == .0 && m.offsetY == .0 && m.offsetZ == .0 && m.m44 == 1.0;
                }
                static isAffine(m) {
                    return m.m14 == .0 && m.m24 == .0 && m.m34 == .0 && m.m44 == 1.0;
                }
                static determinant(m) {
                    if (Matrix3D.isIdentity(m)) {
                        return 1.0;
                    }
                    else if (Matrix3D.isAffine(m)) {
                        return m.m11 * (m.m22 * m.m33 - m.m32 * m.m23)
                            - m.m12 * (m.m21 * m.m33 - m.m31 * m.m23)
                            + m.m13 * (m.m21 * m.m32 - m.m31 * m.m22);
                    }
                    else {
                        const num6 = (m.m13 * m.m24) - (m.m23 * m.m14);
                        const num5 = (m.m13 * m.m34) - (m.m33 * m.m14);
                        const num4 = (m.m13 * m.m44) - (m.offsetZ * m.m14);
                        const num3 = (m.m23 * m.m34) - (m.m33 * m.m24);
                        const num2 = (m.m23 * m.m44) - (m.offsetZ * m.m24);
                        const num = (m.m33 * m.m44) - (m.offsetZ * m.m34);
                        const num10 = ((m.m22 * num5) - (m.m32 * num6)) - (m.m12 * num3);
                        const num9 = ((m.m12 * num2) - (m.m22 * num4)) + (m.offsetY * num6);
                        const num8 = ((m.m32 * num4) - (m.offsetY * num5)) - (m.m12 * num);
                        const num7 = ((m.m22 * num) - (m.m32 * num2)) + (m.offsetY * num3);
                        const det = ((((m.offsetX * num10) + (m.m31 * num9)) + (m.m21 * num8)) + (m.m11 * num7));
                        return det;
                    }
                }
                static multiply(...matrices) {
                    if (matrices.length === 0) {
                        throw new ReferenceError('Matrix not provided.');
                    }
                    const arr = Array.from(matrices);
                    let m = arr[0];
                    for (let i = 1; i < arr.length; i++) {
                        m = Matrix3DUtils.multiply(m, arr[i]);
                    }
                    return m;
                }
                static invert(m) {
                    if (Matrix3D.isAffine(m)) {
                        const determinant = Matrix3D.determinant(m);
                        if (determinant == 0.0) {
                            return null;
                        }
                        const cofactor31 = (m.m12 * m.m23) - (m.m22 * m.m13);
                        const cofactor21 = (m.m32 * m.m13) - (m.m12 * m.m33);
                        const cofactor11 = (m.m22 * m.m33) - (m.m32 * m.m23);
                        const num20 = (m.m21 * m.m13) - (m.m11 * m.m23);
                        const num19 = (m.m11 * m.m33) - (m.m31 * m.m13);
                        const num18 = (m.m31 * m.m23) - (m.m21 * m.m33);
                        const num7 = (m.m11 * m.m22) - (m.m21 * m.m12);
                        const num6 = (m.m11 * m.m32) - (m.m31 * m.m12);
                        const num5 = (m.m11 * m.offsetY) - (m.offsetX * m.m12);
                        const num4 = (m.m21 * m.m32) - (m.m31 * m.m22);
                        const num3 = (m.m21 * m.offsetY) - (m.offsetX * m.m22);
                        const num2 = (m.m31 * m.offsetY) - (m.offsetX * m.m32);
                        const num17 = ((m.m23 * num5) - (m.offsetZ * num7)) - (m.m13 * num3);
                        const num16 = ((m.m13 * num2) - (m.m33 * num5)) + (m.offsetZ * num6);
                        const num15 = ((m.m33 * num3) - (m.offsetZ * num4)) - (m.m23 * num2);
                        const num14 = num7;
                        const num13 = -num6;
                        const num12 = num4;
                        const invdet = 1.0 / determinant;
                        return Matrix3D.from(cofactor11 * invdet, cofactor21 * invdet, cofactor31 * invdet, .0, num18 * invdet, num19 * invdet, num20 * invdet, .0, num12 * invdet, num13 * invdet, num14 * invdet, .0, num15 * invdet, num16 * invdet, num17 * invdet, 1.0);
                    }
                    else {
                        const determinant = Matrix3D.determinant(m);
                        if (determinant == 0.0) {
                            return null;
                        }
                        const num1 = m.m33 * m.m44 - m.m34 * m.offsetZ;
                        const num2 = m.m32 * m.m44 - m.m34 * m.offsetY;
                        const num3 = m.m31 * m.m44 - m.m34 * m.offsetX;
                        const num4 = m.m32 * m.offsetZ - m.m33 * m.offsetY;
                        const num5 = m.m31 * m.offsetZ - m.m33 * m.offsetX;
                        const num6 = m.m31 * m.offsetY - m.m32 * m.offsetX;
                        const num7 = m.m33 * m.m44 - m.m34 * m.offsetZ;
                        const num8 = m.m32 * m.m44 - m.m34 * m.offsetY;
                        const num9 = m.m31 * m.m44 - m.m34 * m.offsetX;
                        const num10 = m.m32 * m.offsetZ - m.m33 * m.offsetY;
                        const num11 = m.m31 * m.offsetZ - m.m33 * m.offsetX;
                        const num12 = m.m31 * m.offsetY - m.m32 * m.offsetX;
                        const num13 = m.m23 * m.m44 - m.m24 * m.offsetZ;
                        const num14 = m.m22 * m.m44 - m.m24 * m.offsetY;
                        const num15 = m.m21 * m.m44 - m.m24 * m.offsetX;
                        const num16 = m.m22 * m.offsetZ - m.m23 * m.offsetY;
                        const num17 = m.m21 * m.offsetZ - m.m23 * m.offsetX;
                        const num18 = m.m21 * m.offsetY - m.m22 * m.offsetX;
                        const num19 = m.m23 * m.m34 - m.m24 * m.m33;
                        const num20 = m.m22 * m.m34 - m.m24 * m.m32;
                        const num21 = m.m21 * m.m34 - m.m24 * m.m31;
                        const num22 = m.m22 * m.m33 - m.m23 * m.m32;
                        const num23 = m.m21 * m.m33 - m.m23 * m.m31;
                        const num24 = m.m21 * m.m32 - m.m22 * m.m31;
                        const cofactor11 = (m.m22 * num1 - m.m23 * num2 + m.m24 * num4);
                        const cofactor12 = -(m.m21 * num1 - m.m23 * num3 + m.m24 * num5);
                        const cofactor13 = (m.m21 * num2 - m.m22 * num3 + m.m24 * num6);
                        const cofactor14 = -(m.m21 * num4 - m.m22 * num5 + m.m23 * num6);
                        const cofactor21 = -(m.m12 * num7 - m.m13 * num8 + m.m14 * num10);
                        const cofactor22 = (m.m11 * num7 - m.m13 * num9 + m.m14 * num11);
                        const cofactor23 = -(m.m11 * num8 - m.m12 * num9 + m.m14 * num12);
                        const cofactor24 = (m.m11 * num10 - m.m12 * num11 + m.m13 * num12);
                        const cofactor31 = (m.m12 * num13 - m.m13 * num14 + m.m14 * num16);
                        const cofactor32 = -(m.m11 * num13 - m.m13 * num15 + m.m14 * num17);
                        const cofactor33 = (m.m11 * num14 - m.m12 * num15 + m.m14 * num18);
                        const cofactor34 = -(m.m11 * num16 - m.m12 * num17 + m.m13 * num18);
                        const cofactor41 = -(m.m12 * num19 - m.m13 * num20 + m.m14 * num22);
                        const cofactor42 = (m.m11 * num19 - m.m13 * num21 + m.m14 * num23);
                        const cofactor43 = -(m.m11 * num20 - m.m12 * num21 + m.m14 * num24);
                        const cofactor44 = (m.m11 * num22 - m.m12 * num23 + m.m13 * num24);
                        const inverseDet = 1.0 / determinant;
                        return Matrix3D.from(cofactor11 * inverseDet, cofactor21 * inverseDet, cofactor31 * inverseDet, cofactor41 * inverseDet, cofactor12 * inverseDet, cofactor22 * inverseDet, cofactor32 * inverseDet, cofactor42 * inverseDet, cofactor13 * inverseDet, cofactor23 * inverseDet, cofactor33 * inverseDet, cofactor43 * inverseDet, cofactor14 * inverseDet, cofactor24 * inverseDet, cofactor34 * inverseDet, cofactor44 * inverseDet);
                    }
                }
                static transform(point, matrix) {
                    var pt = { x: point.x, y: point.y, z: point.z };
                    if (!Matrix3D.isIdentity(matrix)) {
                        var x = pt.x;
                        var y = pt.y;
                        var z = pt.z;
                        pt.x = (((x * matrix.m11) + (y * matrix.m21)) + (z * matrix.m31)) + matrix.offsetX;
                        pt.y = (((x * matrix.m12) + (y * matrix.m22)) + (z * matrix.m32)) + matrix.offsetY;
                        pt.z = (((x * matrix.m13) + (y * matrix.m23)) + (z * matrix.m33)) + matrix.offsetZ;
                        if (!Matrix3D.isAffine(matrix)) {
                            var num4 = (((x * matrix.m14) + (y * matrix.m24)) + (z * matrix.m34)) + matrix.m44;
                            if (num4 != .0) {
                                pt.x /= num4;
                                pt.y /= num4;
                                pt.z /= num4;
                            }
                        }
                    }
                    return pt;
                }
            }
            LinearAlgebra.Matrix3D = Matrix3D;
            class Quaternion {
                static identity() {
                    return Quaternion.from(0, 0, 0, 1);
                }
                static from(...args) {
                    const l = 4;
                    if (args.length !== l) {
                        throw new RangeError(`Must provide exactly ${l} numbers`);
                    }
                    return {
                        x: args[0],
                        y: args[1],
                        z: args[2],
                        w: args[3],
                    };
                }
                static parse(input) {
                    const arr = Pacem.parseAsNumericalArray(input);
                    if (arr && arr.length === 4) {
                        return Quaternion.from.apply(null, arr);
                    }
                    throw new Error(`Cannot parse "${input}" as a valid Quaternion.`);
                }
                static fromVectors(from, to) {
                    Vector3D.normalize(from);
                    Vector3D.normalize(to);
                    const yieldQ = (x, y, z, w) => {
                        const retval = Quaternion.from(x, y, z, w);
                        Quaternion.normalize(retval);
                        return retval;
                    };
                    let r = Vector3D.dot(from, to) + 1;
                    if (r.isCloseTo(0)) {
                        if (Math.abs(from.x) > Math.abs(from.z)) {
                            return yieldQ(-from.y, from.x, 0, 0);
                        }
                        return yieldQ(0, -from.z, from.y, 0);
                    }
                    else {
                        return yieldQ(from.y * to.z - from.z * to.y, from.z * to.x - from.x * to.z, from.x * to.y - from.y * to.x, r);
                    }
                }
                static normalize(q) {
                    const l = Quaternion.mag(q);
                    if (l.isCloseTo(0)) {
                        q.x = q.y = q.z = 0;
                        q.w = 1;
                    }
                    else {
                        const f = 1 / l;
                        q.x *= f;
                        q.y *= f;
                        q.z *= f;
                        q.w *= f;
                    }
                }
                static unit(q) {
                    const clone = Quaternion.from(q.x, q.y, q.z, q.w);
                    Quaternion.normalize(clone);
                    return clone;
                }
                static fromAxisAngle(axis, angleDeg) {
                    angleDeg %= 360.0;
                    var angleInRadians = DEG2RAD * angleDeg;
                    var length = Vector3D.mag(axis);
                    if (length == 0.0) {
                        throw new RangeError('Invalid argument');
                    }
                    var factor = Math.sin(0.5 * angleInRadians) / length;
                    var x = axis.x * factor;
                    var y = axis.y * factor;
                    var z = axis.z * factor;
                    return Quaternion.from(x, y, z, Math.cos(.5 * angleInRadians));
                }
                static fromRotationMatrix(rotationMatrix) {
                    const trace = rotationMatrix.m11 + rotationMatrix.m22 + rotationMatrix.m33 + rotationMatrix.m44;
                    if (trace > 0) {
                        const sq = 0.5 / Math.sqrt(trace);
                        const w = 0.25 / sq;
                        const x = (rotationMatrix.m23 - rotationMatrix.m32) * sq;
                        const y = (rotationMatrix.m31 - rotationMatrix.m13) * sq;
                        const z = (rotationMatrix.m12 - rotationMatrix.m21) * sq;
                        return Quaternion.from(x, y, z, w);
                    }
                    else {
                        if (rotationMatrix.m11 > rotationMatrix.m22 && rotationMatrix.m11 > rotationMatrix.m22) {
                            const sq = 0.5 / Math.sqrt(rotationMatrix.m44 + rotationMatrix.m11 - rotationMatrix.m22 - rotationMatrix.m33);
                            const w = (rotationMatrix.m23 - rotationMatrix.m32) * sq;
                            const x = 0.25 / sq;
                            const y = (rotationMatrix.m12 + rotationMatrix.m21) * sq;
                            const z = (rotationMatrix.m31 + rotationMatrix.m13) * sq;
                            return Quaternion.from(x, y, z, w);
                        }
                        else if (rotationMatrix.m22 > rotationMatrix.m33) {
                            const sq = .5 / Math.sqrt(rotationMatrix.m44 + rotationMatrix.m22 - rotationMatrix.m11 - rotationMatrix.m33);
                            const z = (rotationMatrix.m23 + rotationMatrix.m32) * sq;
                            const y = 0.25 / sq;
                            const x = (rotationMatrix.m12 + rotationMatrix.m21) * sq;
                            const w = (rotationMatrix.m31 - rotationMatrix.m13) * sq;
                            return Quaternion.from(x, y, z, w);
                        }
                        else {
                            const sq = .5 / Math.sqrt(rotationMatrix.m44 + rotationMatrix.m33 - rotationMatrix.m11 - rotationMatrix.m22);
                            const y = (rotationMatrix.m23 + rotationMatrix.m32) * sq;
                            const z = 0.25 / sq;
                            const w = (rotationMatrix.m12 - rotationMatrix.m21) * sq;
                            const x = (rotationMatrix.m31 - rotationMatrix.m13) * sq;
                            return Quaternion.from(x, y, z, w);
                        }
                    }
                }
                static conjugate(q) {
                    return Quaternion.from(-q.x, -q.y, -q.z, q.w);
                }
                static mag(q) {
                    return Math.sqrt(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w);
                }
                static norm(q) {
                    return (q.x * q.x + q.y * q.y + q.z * q.z);
                }
                static axis(q) {
                    if (q.x == .0 && q.y == .0 && q.z == .0) {
                        return Vector3D.j();
                    }
                    return Vector3D.unit(q);
                }
                static transform(v, q) {
                    Quaternion.normalize(q);
                    const cross = Vector3D.cross(q, v);
                    const t = Vector3D.scale(cross, 2);
                    const tCross = Vector3D.cross(q, t);
                    return {
                        x: v.x + q.w * t.x + tCross.x,
                        y: v.y + q.w * t.y + tCross.y,
                        z: v.z + q.w * t.z + tCross.z,
                    };
                }
                static angle(q) {
                    let y = Math.sqrt(q.x * q.x + q.y * q.y + q.z * q.z);
                    let x = q.w;
                    if (y > Number.MAX_VALUE) {
                        const num = Math.max(Math.abs(q.x), Math.max(Math.abs(q.y), Math.abs(q.z)));
                        const num5 = q.x / num;
                        const num4 = q.y / num;
                        const num3 = q.z / num;
                        y = Math.sqrt(((num5 * num5) + (num4 * num4)) + (num3 * num3));
                        x /= num;
                    }
                    return (Math.atan2(y, x) * 114.59155902616465);
                }
                static toRotationMatrix(q) {
                    var m = Matrix3D.identity();
                    var X = q.x;
                    var Y = q.y;
                    var Z = q.z;
                    var W = q.w;
                    m.m11 = 1.0 - 2.0 * Y * Y - 2.0 * Z * Z;
                    m.m12 = 2.0 * X * Y + 2.0 * W * Z;
                    m.m13 = 2.0 * X * Z - 2.0 * W * Y;
                    m.m21 = 2.0 * X * Y - 2.0 * W * Z;
                    m.m22 = 1.0 - 2.0 * X * X - 2.0 * Z * Z;
                    m.m23 = 2.0 * Y * Z + 2.0 * W * X;
                    m.m31 = 2.0 * W * Y + 2.0 * X * Z;
                    m.m32 = 2.0 * Y * Z - 2.0 * W * X;
                    m.m33 = 1.0 - 2.0 * X * X - 2.0 * Y * Y;
                    return m;
                }
                static invert(q) {
                    const n = Quaternion.unit(q);
                    return Quaternion.conjugate(n);
                }
                static multiply(q1, q2) {
                    return Quaternion.from(q1.w * q2.x + q1.x + q2.w + q1.y * q2.z - q1.z * q2.y, q1.w * q2.y - q1.x * q2.z + q1.y * q2.w + q1.z * q2.x, q1.w * q2.z + q1.x * q2.y - q1.y * q2.x + q1.z * q2.w, q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z);
                }
                static dot(q1, q2) {
                    var q = Quaternion.multiply(q1, Quaternion.conjugate(q2));
                    return q.w;
                }
            }
            LinearAlgebra.Quaternion = Quaternion;
        })(LinearAlgebra = Geometry.LinearAlgebra || (Geometry.LinearAlgebra = {}));
    })(Geometry = Pacem.Geometry || (Pacem.Geometry = {}));
})(Pacem || (Pacem = {}));
(function (Pacem) {
    var Geometry;
    (function (Geometry) {
        const Vector3D = Pacem.Geometry.LinearAlgebra.Vector3D;
        const Matrix3D = Pacem.Geometry.LinearAlgebra.Matrix3D;
        class Utils3D {
            static intersect(ray, triangle) {
                const [start, end] = ray;
                const vector = Vector3D.subtract(start, end);
                const [a, b, c] = triangle;
                const ab = Vector3D.subtract(a, b);
                const ac = Vector3D.subtract(a, c);
                const cross = Vector3D.cross(vector, ac);
                const det = Vector3D.dot(ab, cross);
                if (det.isCloseTo(0)) {
                    return null;
                }
                const invDet = 1 / det;
                const s = Vector3D.subtract(start, a);
                const u = invDet * Vector3D.dot(s, cross);
                if (u < 0 || u > 1) {
                    return null;
                }
                const scross = Vector3D.cross(s, ab);
                const v = invDet * Vector3D.dot(vector, scross);
                if (v < 0 || (u + v) > 1) {
                    return null;
                }
                const t = invDet * Vector3D.dot(ac, scross);
                if (t < 0 || t.isCloseTo(0)) {
                    return null;
                }
                return Vector3D.add(start, Vector3D.scale(vector, t));
            }
        }
        Geometry.Utils3D = Utils3D;
    })(Geometry = Pacem.Geometry || (Pacem.Geometry = {}));
})(Pacem || (Pacem = {}));
var Pacem;
(function (Pacem) {
    var Geometry;
    (function (Geometry) {
        function isPolygon(obj) {
            let vertices;
            return 'vertices' in obj && Array.isArray(obj.vertices)
                && (vertices = obj.vertices).length >= 3
                && vertices.every(i => Pacem.Point.isPoint(i));
        }
        class Polygon {
            static isPolygon(obj) {
                return isPolygon(obj);
            }
            static from(...points) {
                return { vertices: Array.from(points) };
            }
            static contains(polygon, p) {
                return Geometry.Utils.inPolygon(p, polygon.vertices, 12);
            }
            static centroid(polygon) {
                const bbox = Polygon.boundingBox(polygon);
                return { x: bbox.x + bbox.width / 2, y: bbox.y + bbox.height / 2 };
            }
            static boundingBox(polygon) {
                let xmin = Number.MAX_VALUE, ymin = Number.MAX_VALUE, xmax = Number.MIN_VALUE, ymax = Number.MIN_VALUE;
                const { vertices } = polygon, l = vertices.length;
                for (let v of vertices) {
                    xmin = Math.min(xmin, v.x);
                    ymin = Math.min(ymin, v.y);
                    xmax = Math.max(xmax, v.x);
                    ymax = Math.max(ymax, v.y);
                }
                return { x: xmin, y: ymin, width: xmax - xmin, height: ymax - ymin };
            }
            static sides(polygon) {
                const { vertices } = polygon;
                const retval = [];
                for (let j = 1; j <= vertices.length; j++) {
                    const v = vertices[j % vertices.length], v0 = vertices[j - 1];
                    retval.push([v0, v]);
                }
                return retval;
            }
            static isConvex(polygon) {
                const { vertices } = polygon, l = vertices.length;
                if (l <= 3) {
                    return true;
                }
                let sign = 0;
                for (let j = 0; j < vertices.length; j++) {
                    const p0 = vertices[(j - 1 + l) % l], p = vertices[j], p1 = vertices[(j + 1) % l];
                    const theta = Pacem.Angle.angleBetween(p, p0, p1);
                    if (sign === 0) {
                        sign = Math.sign(theta);
                        continue;
                    }
                    if (sign != Math.sign(theta)) {
                        return false;
                    }
                }
                return true;
            }
            static isSelfIntersecting(polygon) {
                const { vertices } = polygon;
                if (vertices.length <= 3) {
                    return false;
                }
                const sides = Polygon.sides(polygon);
                for (let side of sides) {
                    for (let check of sides) {
                        if (check === side || check[0] === side[1] || side[0] === check[1]) {
                            continue;
                        }
                        const intersection = Geometry.Utils.intersect(check, side);
                        if (!Pacem.NullChecker.isNull(intersection)) {
                            return true;
                        }
                    }
                }
                return false;
            }
            static isCounterClockwise(polygon) {
                const { vertices: [p0, p1, p2] } = polygon;
                return Pacem.Angle.angleBetween(p1, p0, p2) > 0;
            }
            static expand(polygon, offset) {
                const { vertices } = polygon, l = vertices.length, retval = [];
                for (let j = 0; j < vertices.length; j++) {
                    const p0 = vertices[(j - 1 + l) % l], p = vertices[j], p1 = vertices[(j + 1) % l];
                    const theta = Pacem.Angle.angleBetween(p, p0, p1), scale = -offset / Math.sin(Math.abs(theta) / 2);
                    const matrix = Pacem.Matrix2D.scale(Pacem.Matrix2D.identity, scale);
                    const v0 = Pacem.Point.subtract(p, p0);
                    Geometry.LinearAlgebra.Vector.normalize(v0);
                    const v1 = Pacem.Point.subtract(p, p1);
                    Geometry.LinearAlgebra.Vector.normalize(v1);
                    const vector = Pacem.Point.add(v0, v1);
                    Geometry.LinearAlgebra.Vector.normalize(vector);
                    const pOffset = Pacem.Matrix2D.multiply(vector, matrix);
                    retval.push(Pacem.Point.add(p, { x: pOffset.x.roundoff(), y: pOffset.y.roundoff() }));
                }
                return { vertices: retval };
            }
            static area(polygon) {
                return Geometry.Utils.area(polygon.vertices);
            }
        }
        Geometry.Polygon = Polygon;
    })(Geometry = Pacem.Geometry || (Pacem.Geometry = {}));
})(Pacem || (Pacem = {}));
var Pacem;
(function (Pacem) {
    var Mathematics;
    (function (Mathematics) {
        function complex(c) {
            if (typeof c === 'number') {
                c = { real: c, img: 0 };
            }
            return c;
        }
        var NOT_A_COMPLEX;
        function buildComplex(real, img) {
            const c = {};
            Object.defineProperty(c, 'real', { value: real, writable: false });
            Object.defineProperty(c, 'img', { value: img, writable: false });
            return c;
        }
        function nac() {
            return NOT_A_COMPLEX || (NOT_A_COMPLEX = buildComplex(Number.NaN, Number.NaN));
        }
        class Complex {
            static build(real, img) {
                if (this.isComplex(real)) {
                    return real;
                }
                img ??= 0;
                if (typeof real != 'number' || typeof img != 'number') {
                    return nac();
                }
                return buildComplex(real, img || 0);
            }
            static add(a, b) {
                const ac = complex(a), bc = complex(b);
                return buildComplex(ac.real + bc.real, ac.img + bc.img);
            }
            static subtract(from, what) {
                const ac = complex(from), bc = complex(what);
                return buildComplex(ac.real - bc.real, ac.img - bc.img);
            }
            static multiply(a, b) {
                const ac = complex(a), bc = complex(b);
                return buildComplex(ac.real * bc.real - ac.img * bc.img, ac.real * bc.img + ac.img * bc.real);
            }
            static divide(a, b) {
                const ac = complex(a), bc = complex(b);
                const div = this.absSquare(bc).roundoff();
                if (div === 0) {
                    return nac();
                }
                const inv_div = 1 / div;
                return buildComplex(inv_div * (ac.real * bc.real + ac.img * bc.img), inv_div * (ac.img * bc.real - ac.real * bc.img));
            }
            static absSquare(c) {
                const ac = complex(c);
                return Math.pow(ac.real, 2) + Math.pow(ac.img, 2);
            }
            static modulus(c) {
                return Math.sqrt(this.absSquare(c));
            }
            static isComplex(c) {
                return c != null && typeof c === 'object' && 'real' in c && 'img' in c && typeof c.real === 'number' && typeof c.img === 'number';
            }
            static conjugate(a) {
                a = complex(a);
                return buildComplex(a.real, Math.abs(a.img) == 0 ? 0 : -a.img);
            }
            static equals(c1, c2) {
                const c_1 = this.build(c1), c_2 = this.build(c2);
                if (!this.isComplex(c1) || !this.isComplex(c2)) {
                    return false;
                }
                return c_1.real === c_2.real && c_1.img === c_2.img;
            }
            static get NaC() { return nac(); }
        }
        Mathematics.Complex = Complex;
    })(Mathematics = Pacem.Mathematics || (Pacem.Mathematics = {}));
})(Pacem || (Pacem = {}));
var Pacem;
(function (Pacem) {
    var Mathematics;
    (function (Mathematics) {
        var DataAnalysis;
        (function (DataAnalysis) {
            function euler(k, N) {
                const x = 2 * Math.PI * k / N;
                return Mathematics.Complex.build(Math.cos(x), Math.sin(x));
            }
            const unitCircle = {};
            function exp(k, N) {
                const memN = unitCircle[N] = unitCircle[N] || {};
                return memN[k] = memN[k] || euler(k, N);
            }
            function isPowerOfTwo(length) {
                return length > 0 && (length & (length - 1)) === 0;
            }
            function fftRec(data) {
                const retval = [], N = data.length;
                if (N === 1) {
                    return [Mathematics.Complex.build(data[0])];
                }
                const retval_2n = fftRec(data.filter((_, i) => i % 2 === 0)), retval_2n1 = fftRec(data.filter((_, i) => i % 2 === 1));
                for (var k = 0; k < N / 2; k++) {
                    const t = retval_2n[k], e = Mathematics.Complex.multiply(exp(k, N), retval_2n1[k]);
                    retval[k] = Mathematics.Complex.add(t, e);
                    retval[k + (N / 2)] = Mathematics.Complex.subtract(t, e);
                }
                return retval;
            }
            class Fourier {
                static transform(data, normalize = true) {
                    data = data || [];
                    if (isPowerOfTwo(data.length)) {
                        return this.fft(data, normalize);
                    }
                    return this.dft(data, normalize);
                }
                static invert(data, normalize = true) {
                    return this.idft(data || [], normalize);
                }
                static dft(data, normalize = true) {
                    const N = (data || [])?.length, DEN = normalize ? 1 / Math.sqrt(N) : 1, retval = [];
                    for (let k = 0; k < N; k++) {
                        retval.push({ real: 0, img: 0 });
                        for (let j = 0; j < N; j++) {
                            const e = exp(k * j, N), item = Mathematics.Complex.multiply(data[j], e), itemN = Mathematics.Complex.multiply(item, DEN);
                            retval[k] = Mathematics.Complex.add(retval[k], itemN);
                        }
                    }
                    return retval;
                }
                static idft(data, normalize = true) {
                    const reversed = data.map(i => Mathematics.Complex.build(i.img, i.real)), temp = this.transform(reversed, normalize);
                    return temp.map(c => Mathematics.Complex.build(c.img, c.real));
                }
                static fft(data, normalize = true) {
                    const retval = fftRec(data);
                    if (!normalize) {
                        return retval;
                    }
                    const DEN = 1 / Math.sqrt(data.length);
                    return retval.map(i => Mathematics.Complex.multiply(i, DEN));
                }
            }
            DataAnalysis.Fourier = Fourier;
        })(DataAnalysis = Mathematics.DataAnalysis || (Mathematics.DataAnalysis = {}));
    })(Mathematics = Pacem.Mathematics || (Pacem.Mathematics = {}));
})(Pacem || (Pacem = {}));
var Pacem;
(function (Pacem) {
    var Mathematics;
    (function (Mathematics) {
        var DataAnalysis;
        (function (DataAnalysis) {
            const SQRT_PI = Math.sqrt(Math.PI);
            function erfc(x) {
                const z = Math.abs(x);
                const t = 1.0 / (1.0 + 0.5 * z);
                const ans = t * Math.exp(-z * z - 1.26551223 + t * (1.00002368 + t * (0.37409196 + t * (0.09678418 +
                    t * (-0.18628806 + t * (0.27886807 + t * (-1.13520398 + t * (1.48851587 +
                        t * (-0.82215223 + t * 0.17087277)))))))));
                return x >= 0.0 ? ans : 2.0 - ans;
            }
            function erf(x) {
                return 1 - erfc(x);
            }
            class Gaussian {
                constructor(mean, stdev) {
                    this.mean = mean;
                    this.stdev = Math.abs(stdev);
                    this.variance = Math.pow(stdev, 2);
                }
                mean;
                stdev;
                variance;
                static get normal() {
                    return _normal;
                }
                weight(x) {
                    return Math.exp(-0.5 * Math.pow(this._z(x), 2));
                }
                probabilityDensity(x) {
                    const inv_coeff = this.stdev * Math.SQRT2 * SQRT_PI, exp_part = this.weight(x);
                    return exp_part / inv_coeff;
                }
                _z(x) {
                    return (x - this.mean) / this.stdev;
                }
                probability(x) {
                    return 0.5 * erfc(-this._z(x) / Math.SQRT2);
                }
            }
            DataAnalysis.Gaussian = Gaussian;
            const _normal = new Gaussian(0, 1);
        })(DataAnalysis = Mathematics.DataAnalysis || (Mathematics.DataAnalysis = {}));
    })(Mathematics = Pacem.Mathematics || (Pacem.Mathematics = {}));
})(Pacem || (Pacem = {}));
var Pacem;
(function (Pacem) {
    var Mathematics;
    (function (Mathematics) {
        var DataAnalysis;
        (function (DataAnalysis) {
            class Lagrangian {
                constructor(...args) {
                    this.#set = Array.from(args) || [];
                }
                #set;
                #lagrangian;
                _unsafeCreate() {
                    const points = this.#set || [];
                    const x = 'x';
                    let fnBody = 'var ljs = [];\n';
                    let lastx;
                    for (let j = 0; j < points.length; j++) {
                        const pj = points[j], xj = pj.x;
                        if (lastx != null && lastx >= xj) {
                            throw new Error('Invalid function provided.');
                        }
                        lastx = xj;
                        fnBody += `ljs.push( ${pj.y}`;
                        for (let m = 0; m < points.length; m++) {
                            if (m !== j) {
                                const pm = points[m];
                                fnBody += ` * ((${x} - ${pm.x})/${xj - pm.x})`;
                            }
                        }
                        fnBody += ');\n';
                    }
                    fnBody += `return ljs.reduce((prev, next) => prev + next, 0);`;
                    this.#lagrangian = new Function(x, fnBody);
                }
                _compute(x) {
                    const points = this.#set || [];
                    let lastx;
                    const ljs = [];
                    for (let j = 0; j < points.length; j++) {
                        const xj = points[j].x;
                        if (lastx != null && lastx >= xj) {
                            throw new Error('Invalid function provided.');
                        }
                        lastx = xj;
                        let lj = points[j].y;
                        for (let m = 0; m < points.length; m++) {
                            if (m !== j) {
                                const pm = points[m];
                                lj *= (x - pm.x) / (xj - pm.x);
                            }
                        }
                        ljs.push(lj);
                    }
                    return ljs.reduce((prev, next) => prev + next, 0);
                }
                interpolate(x) {
                    const lagrangian = this.#lagrangian;
                    if (typeof lagrangian === 'function') {
                        return this.#lagrangian.apply(null, [x]);
                    }
                    return this._compute(x);
                }
                static create(...values) {
                    var array = [];
                    if (arguments.length > 0 && Array.isArray(arguments[0])) {
                        array = arguments[0];
                    }
                    else {
                        array = Array.from(values);
                    }
                    const points = array.map((y, x) => { return typeof y === 'number' ? { x, y } : y; });
                    const activator = Function.prototype.bind;
                    const l = new (activator.apply(Lagrangian, [null].concat(points)));
                    try {
                        l._unsafeCreate();
                    }
                    catch (_) {
                    }
                    return l;
                }
            }
            DataAnalysis.Lagrangian = Lagrangian;
        })(DataAnalysis = Mathematics.DataAnalysis || (Mathematics.DataAnalysis = {}));
    })(Mathematics = Pacem.Mathematics || (Pacem.Mathematics = {}));
})(Pacem || (Pacem = {}));
var Pacem;
(function (Pacem) {
    var Mathematics;
    (function (Mathematics) {
        var NumberTheory;
        (function (NumberTheory) {
            const ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyz';
            const OUT_OF_RANGE = `Radix out of range: possible values go between positive 1 exclusive and ${ALPHABET.length} inclusive`;
            class Utils {
                static lcd(...args) {
                    if (Pacem.NullChecker.isNullOrEmpty(args) || args.length <= 1) {
                        throw 'Insufficient set of numbers.';
                    }
                    function ex9(x, y) {
                        if (!y)
                            return y === 0 ? x : NaN;
                        return ex9(y, x % y);
                    }
                    function ex10(x, y) {
                        return x * y / ex9(x, y);
                    }
                    let result = Math.round(args[0]);
                    for (let j = 1; j < args.length; j++) {
                        result = ex10(result, Math.round(args[j]));
                    }
                    return result;
                }
                static gcd(a, b) {
                    a = Math.round(a),
                        b = Math.round(b);
                    if (a === 0) {
                        return b;
                    }
                    return Utils.gcd(b % a, a);
                }
                static rebaseInt(v, from, to) {
                    return Pacem.Numbers.rebase(v, from, to);
                }
                static rebaseFloat(v, fromRadix, toRadix, precision = 12) {
                    const from10 = Utils.rebaseFloat10ToN, to10 = Utils.rebaseFloatNTo10;
                    if (fromRadix === 10) {
                        const vFloat = parseFloat(v.toString());
                        if (toRadix % 1 === 0) {
                            return Utils.rebaseFloat10ToNIntBase(vFloat, toRadix, precision);
                        }
                        return from10(vFloat, toRadix, precision);
                    }
                    if (toRadix === 10) {
                        return to10(v.toString(), fromRadix, precision);
                    }
                    const _10 = to10(v.toString(), fromRadix, precision + 1);
                    return from10(_10, toRadix, precision);
                }
                static rebaseFloatNTo10(v, radix, precision = 12) {
                    const alphabet = ALPHABET;
                    if (radix <= 1 || radix > alphabet.length) {
                        throw new Error(OUT_OF_RANGE);
                    }
                    const vs = (v ?? '0').toString().toLowerCase(), nan = Number.NaN;
                    if (vs === '0') {
                        return 0;
                    }
                    const arr = /^([-+]?) *([\da-z]+)?(.[\da-z]+)?$/.exec(vs);
                    if (arr.length < 2) {
                        return nan;
                    }
                    const sign = arr[1] === '-' ? -1 : 1, int = arr[2] || '0', frac = arr[3] || '.0';
                    let retval = 0, cursor = 0;
                    for (let digit of (int + frac.substr(1))) {
                        const num = alphabet.indexOf(digit);
                        if (num === -1 || num >= radix) {
                            return nan;
                        }
                        retval += num * Math.pow(radix, int.length - cursor - 1);
                        cursor++;
                    }
                    return sign * retval;
                }
                static rebaseFloat10ToNIntBase(v, radix, precision = 12) {
                    const alphabet = ALPHABET;
                    if (radix <= 1 || radix > alphabet.length) {
                        throw new Error(OUT_OF_RANGE);
                    }
                    const to = radix;
                    let value = Math.abs(v ?? 0);
                    if (value === 0 || Number.isNaN(value)) {
                        return v.toString();
                    }
                    let decimals = (value % 1).roundoff();
                    let output = '';
                    do {
                        let div = value / to;
                        let divFloor = Math.floor(div);
                        let mod = (value - divFloor * to).roundoff();
                        let intPart = Math.floor(mod);
                        if (intPart >= alphabet.length) {
                            output = `[${intPart}]` + output;
                        }
                        else {
                            output = alphabet[intPart] + output;
                        }
                        if (divFloor <= 0) {
                            break;
                        }
                        value = divFloor;
                    } while (true);
                    output = output.replace(/^0+/, '');
                    output ||= '0';
                    if (decimals === 0) {
                        return output;
                    }
                    let rebasedFrac = '';
                    do {
                        value = (decimals * to).roundoff();
                        const intPart = Math.floor(value), remainder = (value - intPart).roundoff();
                        if (intPart >= alphabet.length) {
                            rebasedFrac = `[${intPart}]`;
                        }
                        else {
                            rebasedFrac += alphabet[intPart];
                        }
                        decimals = remainder;
                    } while (!decimals.isCloseTo(0) && rebasedFrac.length < precision);
                    if (/^0*$/.test(rebasedFrac)) {
                        return output;
                    }
                    return (Math.sign(v) < 0 ? '-' : '') + output + '.' + rebasedFrac.replace(/0+$/, '');
                }
                static rebaseFloat10ToN(v, radix, precision = 12) {
                    const alphabet = ALPHABET;
                    if (radix <= 1 || radix > alphabet.length) {
                        throw new Error(OUT_OF_RANGE);
                    }
                    const to = radix;
                    let value = Math.abs(v ?? 0);
                    if (value === 0 || Number.isNaN(value)) {
                        return v.toString();
                    }
                    let sign = Math.sign(v) < 0 ? '-' : '';
                    let int = [];
                    let dec = [];
                    for (let j = 0; j < 20; j++) {
                        int.push('0');
                        dec.push('0');
                    }
                    const maxIndex = to % 1 === 0 ? to : Math.ceil(to);
                    function add(integers, j, digitIndex) {
                        const output = integers ? int : dec;
                        const current = output[j] = output[j] || '0';
                        const index = alphabet.indexOf(current) + digitIndex, tgetIndex = index % maxIndex, carryIndex = Math.floor(index / maxIndex);
                        output[j] = alphabet[tgetIndex];
                        if (carryIndex > 0) {
                            if (integers) {
                                add(integers, j + 1, carryIndex);
                            }
                            else {
                                if (j === 0) {
                                    add(true, 0, carryIndex);
                                }
                                else {
                                    add(false, j - 1, carryIndex);
                                }
                            }
                        }
                        return carryIndex;
                    }
                    let step = 0;
                    do {
                        const magnitude = Math.floor(Pacem.Numbers.log(value, to));
                        const isInteger = magnitude >= 0;
                        const absMagnitude = isInteger ? magnitude : Math.abs(1 + magnitude);
                        add(isInteger, absMagnitude, 1);
                        value = (value - Math.pow(to, magnitude).roundoff()).roundoff();
                        if (!isInteger) {
                            step++;
                        }
                        if (value === 0 || step >= 100) {
                            const integer = sign + (int.reverse().map(i => i || '0').join('').replace(/^0+/, '') || '0'), fractional = dec.map(i => i || '0').join('').substr(0, precision).replace(/0+$/, '');
                            if (/^0*$/.test(fractional)) {
                                return integer;
                            }
                            return integer + '.' + fractional;
                        }
                    } while (true);
                }
            }
            NumberTheory.Utils = Utils;
        })(NumberTheory = Mathematics.NumberTheory || (Mathematics.NumberTheory = {}));
    })(Mathematics = Pacem.Mathematics || (Pacem.Mathematics = {}));
})(Pacem || (Pacem = {}));
var Pacem;
(function (Pacem) {
    var Mathematics;
    (function (Mathematics) {
        var DataAnalysis;
        (function (DataAnalysis) {
            const selfSelector = (i, _) => i;
            function mode(set, selector = selfSelector) {
                const groups = Object.groupBy(set, selector);
                let key, max = 0;
                for (let group in groups) {
                    const l = groups[group].length;
                    if (l > max) {
                        key = parseInt(group);
                        max = l;
                    }
                }
                return key;
            }
            function median(set, selector = selfSelector) {
                const setCopy = set.slice(0), length = setCopy.length;
                setCopy.sort((a, b) => {
                    const i = selector(a), j = selector(b);
                    return i - j;
                });
                const index = Math.ceil(setCopy.length / 2) - 1;
                if (length % 2 == 1) {
                    return setCopy[index];
                }
                return .5 * (setCopy[index + 1] + setCopy[index]);
            }
            function sum(set, selector = selfSelector) {
                return set.reduce((p, c, i) => p + selector(c, i), 0);
            }
            function mean(set, selector = selfSelector) {
                return sum(set, selector) / set.length;
            }
            function variance(set, selector = selfSelector, bessel = false) {
                const avg = mean(set, selector);
                return set.reduce((p, c) => Math.pow(c - avg, 2) + p, 0) / (set.length - (bessel ? 1 : 0));
            }
            function stdev(set, selector = selfSelector, bessel = false) {
                const v = variance(set, selector, bessel);
                return Math.sqrt(v);
            }
            function correlation(set, arg2, selector1 = selfSelector, selector2 = selfSelector) {
                const twoArrays = Array.isArray(arg2);
                if (twoArrays && arg2.length !== set.length) {
                    throw new Error('Sets must be of the same length.');
                }
                const length = set.length;
                const setX = set, setY = twoArrays ? arg2 : set;
                const selectorX = twoArrays ? selector1 : arg2;
                const selectorY = twoArrays ? selector2 : selector1;
                const meanX = mean(setX, selectorX);
                const meanY = mean(setY, selectorY);
                let accNum = 0;
                let accDenXSq = 0;
                let accDenYSq = 0;
                for (let i = 0; i < length; i++) {
                    const itemX = setX[i], itemY = setY[i];
                    const a = selectorX(itemX, i) - meanX;
                    const b = selectorY(itemY, i) - meanY;
                    accNum += (a * b);
                    accDenXSq += (a * a);
                    accDenYSq += (b * b);
                }
                return accNum / Math.sqrt(accDenXSq * accDenYSq);
            }
            function linearRegression(set, arg2, selector1 = selfSelector, selector2 = selfSelector) {
                const twoArrays = Array.isArray(arg2);
                if (twoArrays && arg2.length !== set.length) {
                    throw new Error('Sets must be of the same length.');
                }
                const setX = set, setY = twoArrays ? arg2 : set;
                const selectorX0 = twoArrays ? selector1 : arg2;
                const selectorY0 = twoArrays ? selector2 : selectorX0;
                const selectorX = selectorX0 ?? (p => p.x);
                const selectorY = selectorY0 ?? (p => p.y);
                const length = set.length;
                let xyAcc = 0, xAcc = 0, yAcc = 0, x2Acc = 0, y2Acc = 0;
                for (let i = 0; i < length; i++) {
                    const itemX = setX[i], itemY = setY[i];
                    const x = selectorX(itemX, i);
                    const y = selectorY(itemY, i);
                    xyAcc += x * y;
                    xAcc += x;
                    yAcc += y;
                    x2Acc += x * x;
                    y2Acc += y * y;
                }
                const m = (length * xyAcc - xAcc * yAcc) / (length * x2Acc - Math.pow(xAcc, 2));
                const q = (yAcc - m * xAcc) / length;
                return [m, q];
            }
            class Utils {
                static sum(set, selector) {
                    return sum(set, selector);
                }
                static mean(set, selector) {
                    return mean(set, selector);
                }
                static median(set, selector) {
                    return median(set, selector);
                }
                static mode(set, selector) {
                    return mode(set, selector);
                }
                static var(set, selector) {
                    return variance(set, selector, true);
                }
                static varp(set, selector) {
                    return variance(set, selector, false);
                }
                static stdevp(set, selector) {
                    return stdev(set, selector, false);
                }
                static stdev(set, selector) {
                    return stdev(set, selector, true);
                }
                static correlation(set, arg2, selector1, selector2) {
                    return correlation(set, arg2, selector1, selector2);
                }
                static linearRegression(set, arg2, selector1, selector2) {
                    return linearRegression(set, arg2, selector1, selector2);
                }
                static gaussian(mean, stdev) {
                    return new DataAnalysis.Gaussian(mean, stdev);
                }
            }
            DataAnalysis.Utils = Utils;
            function searchFnFactory(minAssigner, maxAssigner) {
                const fn = (left, right, f, tolerance) => {
                    let min = left;
                    let max = right;
                    let x1 = minAssigner(min, max);
                    let x2 = maxAssigner(min, max);
                    let f1 = f(x1);
                    let f2 = f(x2);
                    while ((max - min) > tolerance) {
                        if (f1 < f2) {
                            max = x2;
                            x2 = x1;
                            f2 = f1;
                            x1 = minAssigner(min, max);
                            f1 = f(x1);
                        }
                        else {
                            min = x1;
                            x1 = x2;
                            f1 = f2;
                            x2 = maxAssigner(min, max);
                            f2 = f(x2);
                        }
                    }
                    return .5 * (x1 + x2);
                };
                return fn;
            }
            const DEFAULT_TOLERANCE = 1e-3;
            const goldenRatioSearch = (left, right, weight, tolerance = DEFAULT_TOLERANCE) => {
                const phi = 1.618;
                const minAssigner = (min, max) => max - (max - min) / phi;
                const maxAssigner = (min, max) => min + (max - min) / phi;
                const fn = searchFnFactory(minAssigner, maxAssigner);
                return fn(left, right, weight, tolerance);
            };
            function linearSearch(segments) {
                if (segments <= 1) {
                    throw new RangeError("segments must be a number grater than 1.");
                }
                return (left, right, weight, tolerance = DEFAULT_TOLERANCE) => {
                    const minAssigner = (min, max) => min + (max - min) / segments;
                    const maxAssigner = (min, max) => max - (max - min) / segments;
                    const fn = searchFnFactory(minAssigner, maxAssigner);
                    return fn(left, right, weight, tolerance);
                };
            }
            const gaussianSearch = (left, right, weight, tolerance = DEFAULT_TOLERANCE) => {
                var sigma0 = null;
                var length0 = null;
                const computeSigma = (min, max) => {
                    length0 ??= (max - min);
                    sigma0 ??= length0 / Math.sqrt(12);
                    return sigma0 * (max - min) / length0;
                };
                const minAssigner = (min, max) => Math.max(min, (max + min) / 2 - computeSigma(min, max));
                const maxAssigner = (min, max) => Math.min(max, (max + min) / 2 + computeSigma(min, max));
                const fn = searchFnFactory(minAssigner, maxAssigner);
                return fn(left, right, weight, tolerance);
            };
            DataAnalysis.SearchFunctions = {
                linear: (segments = 2) => linearSearch(segments),
                goldenRatio: goldenRatioSearch,
                gaussian: gaussianSearch,
            };
        })(DataAnalysis = Mathematics.DataAnalysis || (Mathematics.DataAnalysis = {}));
    })(Mathematics = Pacem.Mathematics || (Pacem.Mathematics = {}));
})(Pacem || (Pacem = {}));
