/** @internal NOTE: Internal APIs. Subject to change. Use of these APIs in production applications is not supported. */
import { Epsilon, Scalar } from '../loader/babylonjs-import';
/**
 * Perform `ceil(base^v)` calcuation.
 * @param v Number to perform `base^v` on
 * @param base Power of base. Ie `base^v`. Defaults to `2`
 * @returns `ceil(base^v)`
 */
export function pow2ceil(v, base = 2) {
    return Math.pow(base, Math.ceil(Math.log(v) / Math.log(base)));
}
/**
 * Calculate next power of two greater than or equal to `n`.
 * @param n number to calculate next power of two for.
 * @returns next power of two greater than or equal to `n`
 */
export function nextPow2(n) {
    if (n <= 1)
        return 1;
    return 2 ** Math.ceil(Math.log2(n));
}
/**
 * Assign `Number.MAX_VALUE` to `x, y ,z` properties of `dst`.
 * @param dst {@link Vertex3}.
 * @returns Referece to `m`.
 */
export function setMax(dst) {
    return setValue(dst, Number.MAX_VALUE);
}
/**
 * Assign `-Number.MAX_VALUE` to `x, y ,z` properties of `dst`.
 * @param dst {@link Vertex3}.
 * @returns Referece to `m`.
 */
export function setMin(dst) {
    return setValue(dst, -Number.MAX_VALUE);
}
/**
 * Assign `n` to `dst.x, y, z`.
 * @param dst Instance to assign `n` to.
 * @param n Value to assign to `dst.x, y, z`.
 * @returns Reference to `dst`-
 */
export function setValue(dst, n) {
    dst.x = n;
    dst.y = dst.x;
    dst.z = dst.x;
    return dst;
}
/**
 * Copy x, y, z properties from one instance to another
 * @param src Object to copy from-
 * @param dst Object to copy to.
 * @returns Reference to `dst`
 */
export function copyVertex3ToRef(src, dst) {
    dst.x = src.x;
    dst.y = src.y;
    dst.z = src.z;
    return dst;
}
/**
 * Get sum of all numbers in `arr`.
 * @param arr Array of numbers.
 * @returns sum.
 */
export function sum(arr) {
    return arr.reduce((acc, curr) => acc + curr, 0);
}
/**
 * Get man value of all numbers in `arr`.
 * @param arr Array of numbers.
 * @returns Mean value.
 */
export function mean(arr) {
    return sum(arr) / arr.length;
}
/**
 * Get standard deviation of numbers in `data`
 * @param data Array of numbers.
 * @returns Standard deviation.
 */
export function standardDeviation(data) {
    const dataMean = mean(data);
    const meanDists = data.map((x) => Math.pow(x - dataMean, 2));
    return Math.sqrt(mean(meanDists));
}
export function equalsWithEpsilonVertex3(vertex1, vertex2, epsilon = Epsilon) {
    return (Scalar.WithinEpsilon(vertex1.x, vertex2.x, epsilon) &&
        Scalar.WithinEpsilon(vertex1.y, vertex2.y, epsilon) &&
        Scalar.WithinEpsilon(vertex1.z, vertex2.z, epsilon));
}
/**
 * @internal
 * @hidden
 */
export function findAnomalyIndices(data) {
    const dataStd = standardDeviation(data);
    const dataMean = mean(data);
    const cutOff = dataStd * 3;
    const lowerLimit = dataMean - cutOff;
    const upperLimit = dataMean + cutOff;
    const anomalies = [];
    data.forEach((x, i) => {
        if (x > upperLimit || x < lowerLimit) {
            anomalies.push(i);
        }
    });
    return anomalies;
}
/**
 * Get point of intersection (if any) between a ray and a plane.
 * @param ray Ray to use for intersection calculation.
 * @param plane Plane to performn intersection calculation against
 * @param dst Point of intersection is written to this object (if a intersection could be found)
 * @returns Distance to point of intersection on plane, < 0 if no interrsection.
 */
export function intersectsPlaneAtToRef(ray, plane, dst) {
    const distance = ray.intersectsPlane(plane);
    if (distance !== null && distance !== undefined && distance >= 0) {
        dst.copyFrom(ray.origin);
        ray.direction.scaleAndAddToRef(distance, dst);
        return distance;
    }
    return -1;
}
const props = ['x', 'y', 'z'];
/**
 * Checks if a ray intersets a specified axis aligned bounding box.
 * @param ray Ray to use for intersection calculation.
 * @param aabbMin Min value of axis aligned bounding box
 * @param aabbMax Max value of axis aligned bounding box
 * @returns Undefined of no intersection was found. Otherwise intersection distance
 */
export function rayDistanceToBoundingBox(ray, aabbMin, aabbMax) {
    let lo = -Infinity;
    let hi = +Infinity;
    const ro = ray.origin;
    const rd = ray.direction;
    for (const p of props) {
        let dimLo = (aabbMin[p] - ro[p]) / rd[p];
        let dimHi = (aabbMax[p] - ro[p]) / rd[p];
        if (dimLo > dimHi) {
            const tmp = dimLo;
            dimLo = dimHi;
            dimHi = tmp;
        }
        if (dimHi < lo || dimLo > hi) {
            return undefined;
        }
        if (dimLo > lo)
            lo = dimLo;
        if (dimHi < hi)
            hi = dimHi;
    }
    return lo > hi ? undefined : lo;
}
/**
 * Checks if a ray intersets a specified axis aligned bounding box. If it intersects we get
 * the point of intersection.
 * @param ray Ray to use for intersection calculation.
 * @param aabbMin Min value of axis aligned bounding box
 * @param aabbMax Max value of axis aligned bounding box
 * @param dst Intersection point is written to this object if intersection exists.
 * @returns Undefined of no intersection was found. Otherwise intersection distance
 */
export function intersectRayWithAAABBToRef(ray, aabbMin, aabbMax, dst) {
    const d = rayDistanceToBoundingBox(ray, aabbMin, aabbMax);
    if (d !== undefined) {
        const ro = ray.origin;
        const rd = ray.direction;
        dst.x = ro.x + rd.x * d;
        dst.y = ro.y + rd.y * d;
        dst.z = ro.z + rd.z * d;
    }
    return d;
}
/**
 * Given two points/vectors, calculate a point/vector which lies on the middle of the line that spans
 * the points.
 * @param start Start of line
 * @param end End of line
 * @param dst Results is written to this object.
 * @returns Reference to `dst`.
 */
export function vertexBetweenToRef(start, end, dst) {
    dst.x = (start.x + end.x) * 0.5;
    dst.y = (start.y + end.y) * 0.5;
    if (isVertex3(start) && isVertex3(dst)) {
        dst.z = (start.z + end.z) * 0.5;
    }
    return dst;
}
/**
 * Add a {@link Vertex} to another {@link Vertex}.
 * @param src {@link Vertex} to add to `dst`.
 * @param dst `src` is added to `dst`.
 * @returns Reference to `dst`.
 */
export function addVertexToRef(src, dst) {
    dst.x += src.x;
    dst.y += src.y;
    if (isVertex3(src) && isVertex3(dst)) {
        dst.z += src.z;
    }
    return dst;
}
/**
 * Subtract a {@link Vertex} from another {@link Vertex}.
 * @param vert1 `vert2` is subracted from `vert1`.
 * @param vert2 {@link Vertex} to subtract from `vert1`.
 * @param dst the result of the operation `vert1` - `vert2`.
 * @returns Reference to `dst`.
 */
export function subtractVertexToRef(vert1, vert2, dst) {
    dst.x = vert1.x - vert2.x;
    dst.y = vert1.y - vert2.y;
    if (isVertex3(vert1) && isVertex3(vert2) && isVertex3(dst)) {
        dst.z = vert1.z - vert2.z;
    }
    return dst;
}
/**
 * Type guard to check if `v` is a {@link Vertex3} or not
 * @param v Possibly a {@link Vertex3}
 */
export function isVertex3(v) {
    return 'z' in v;
}
/**
 * Type guard to check if `v` is a {@link Vertex2} or not
 * @param v Possibly a {@link Vertex2}
 */
export function isVertex2(v) {
    return !isVertex3(v);
}
/**
 * Given a collection of points(vertices) , representing corners of outer edges of a polygon. Calculate
 * the centroid.
 * @param points Points
 * @param dst Where centroid value is written
 * @returns Reference to `dst`
 */
export function calculateCentroidVertex3ToRef(points, dst) {
    setValue(dst, 0);
    let len = 0;
    for (const p of points) {
        len++;
        dst.x += p.x;
        dst.y += p.y;
        dst.z += p.z;
    }
    dst.x /= len;
    dst.y /= len;
    dst.z /= len;
    return dst;
}
//# sourceMappingURL=index.js.map