"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Vector3_1 = require("./Vector3");
/**
 * Representation of bounding boxes.
 */
var Bounds = /** @class */ (function () {
    function Bounds(min, max) {
        this.min = min;
        this.max = max;
    }
    //#region Create / Clone
    /**
     * Convenience function for creating a Bounds object, cloning the parameters.
     * @param min defaults to  inf / inf / inf
     * @param max defaults to -inf /-inf /-inf
     */
    Bounds.create = function (min, max) {
        if (min === void 0) { min = Vector3_1.Vector3.create(Infinity, Infinity, Infinity); }
        if (max === void 0) { max = Vector3_1.Vector3.create(-Infinity, -Infinity, -Infinity); }
        var result = {
            min: Vector3_1.Vector3.clone(min),
            max: Vector3_1.Vector3.clone(max),
        };
        if (Bounds.areValid(result)) {
            Bounds.ensureBoundsAreAssorted(result);
        }
        return result;
    };
    /** Convenience function for cloning a Bounds object */
    Bounds.clone = function (bounds) {
        return Bounds.create(bounds.min, bounds.max);
    };
    //#endregion Create / Clone
    //#region Checks
    /** Convenience function to check if Bounds object is correctly set */
    Bounds.areValid = function (bounds) {
        var dot = Vector3_1.Vector3.innerProduct(bounds.min, bounds.max);
        return isFinite(dot) && !isNaN(dot);
    };
    /**
     * Check intersection of two bounding boxes.
     * @param bb1 First bounding box
     * @param bb2 Second bounding box
     * @return true if the two bounding boxes intersect each other
     */
    Bounds.doIntersect = function (bb1, bb2) {
        if (bb1.max.x <= bb2.min.x ||
            bb1.min.x >= bb2.max.x ||
            bb1.max.y <= bb2.min.y ||
            bb1.min.y >= bb2.max.y ||
            bb1.max.z <= bb2.min.z ||
            bb1.min.z >= bb2.max.z) {
            return false;
        }
        return true;
    };
    /**
     * Check if point is inside a bounding box
     * @param bounds
     * @param point
     * @param deviation positive values extend bounds, negative shrink it
     */
    Bounds.isPointInBounds = function (bounds, point, deviation) {
        if (deviation === void 0) { deviation = 0; }
        if (bounds.max.x + deviation >= point.x &&
            bounds.min.x - deviation <= point.x &&
            bounds.max.y + deviation >= point.y &&
            bounds.min.y - deviation <= point.y &&
            bounds.max.z + deviation >= point.z &&
            bounds.min.z - deviation <= point.z) {
            return true;
        }
        return false;
    };
    /** check if min and max values are assorted and save it in place */
    Bounds.ensureBoundsAreAssorted = function (bounds) {
        var swap;
        if (bounds.min.x > bounds.max.x) {
            swap = bounds.min.x;
            bounds.min.x = bounds.max.x;
            bounds.max.x = swap;
        }
        if (bounds.min.y > bounds.max.y) {
            swap = bounds.min.y;
            bounds.min.y = bounds.max.y;
            bounds.max.y = swap;
        }
        if (bounds.min.z > bounds.max.z) {
            swap = bounds.min.z;
            bounds.min.z = bounds.max.z;
            bounds.max.z = swap;
        }
    };
    //#endregion Checks
    //#region Extend
    /** Function to extend a Bounds object correctly in place */
    Bounds.extendInPlace = function (bounds, point) {
        bounds.min.x = Math.min(bounds.min.x, point.x);
        bounds.min.y = Math.min(bounds.min.y, point.y);
        bounds.min.z = Math.min(bounds.min.z, point.z);
        bounds.max.x = Math.max(bounds.max.x, point.x);
        bounds.max.y = Math.max(bounds.max.y, point.y);
        bounds.max.z = Math.max(bounds.max.z, point.z);
    };
    /** Function to extend a Bounds object with another Bounds object, returning new Bounds */
    Bounds.merge = function (first, second) {
        var merged = Bounds.clone(first);
        Bounds.extendInPlace(merged, second.min);
        Bounds.extendInPlace(merged, second.max);
        return merged;
    };
    //#endregion Extend
    //#region Convert
    /**
     * Create a planar (in the xz-plane) plane segment that is given by the lower part of the cube given by the bounds.
     * @param bounds
     * @returns {PlaneSegment}
     */
    Bounds.convertToXZPlaneSegment = function (bounds) {
        var diameter = Vector3_1.Vector3.sub(bounds.max, bounds.min);
        return {
            point: {
                x: bounds.min.x,
                y: 0,
                z: bounds.min.z,
            },
            borderU: {
                x: diameter.x,
                y: 0,
                z: 0,
            },
            borderV: {
                x: 0,
                y: 0,
                z: diameter.z,
            },
        };
    };
    //#endregion Convert
    //#region Convenience
    /** Convenience function to stringify Bounds */
    Bounds.stringify = function (bounds, precision) {
        if (precision === void 0) { precision = 3; }
        var result = "{min: {x: " + bounds.min.x.toFixed(precision) + ", y: " + bounds.min.y.toFixed(precision) + ", z: " + bounds.min.z.toFixed(precision) + "}, max: {x: " + bounds.max.x.toFixed(precision) + ", y: " + bounds.max.y.toFixed(precision) + ", z: " + bounds.max.z.toFixed(precision) + "}}";
        return result;
    };
    /** convenience function to yield the size of Bounds object */
    Bounds.getSize = function (bounds) {
        var result = Vector3_1.Vector3.create();
        result.x = Math.abs(bounds.max.x - bounds.min.x);
        result.y = Math.abs(bounds.max.y - bounds.min.y);
        result.z = Math.abs(bounds.max.z - bounds.min.z);
        return result;
    };
    /** convenience function to yield the center of Bounds object */
    Bounds.getCenter = function (bounds) {
        var result = Vector3_1.Vector3.scalarMultiply(0.5, Vector3_1.Vector3.add(bounds.max, bounds.min));
        return result;
    };
    return Bounds;
}());
exports.Bounds = Bounds;
