#

API Docs for: 0.6.1
Show: Inherited Protected Private Deprecated

# File: src/collision/AABB.js

    var Vec3 = require('../math/Vec3');
    var Utils = require('../utils/Utils');

    module.exports = AABB;

    /**
     * Axis aligned bounding box class.
     * @class AABB
     * @constructor
     * @param {Object} [options]
     * @param {Vec3}   [options.upperBound]
     * @param {Vec3}   [options.lowerBound]
     */
    function AABB(options){
        options = options || {};

        /**
         * The lower bound of the bounding box.
         * @property lowerBound
         * @type {Vec3}
         */
        this.lowerBound = new Vec3();
        if(options.lowerBound){
            this.lowerBound.copy(options.lowerBound);
        }

        /**
         * The upper bound of the bounding box.
         * @property upperBound
         * @type {Vec3}
         */
        this.upperBound = new Vec3();
        if(options.upperBound){
            this.upperBound.copy(options.upperBound);
        }
    }

    var tmp = new Vec3();

    /**
     * Set the AABB bounds from a set of points.
     * @method setFromPoints
     * @param {Array} points An array of Vec3's.
     * @param {Vec3} position
     * @param {Quaternion} quaternion
     * @param {number} skinSize
     * @return {AABB} The self object
     */
    AABB.prototype.setFromPoints = function(points, position, quaternion, skinSize){
        var l = this.lowerBound,
            u = this.upperBound,
            q = quaternion;

        // Set to the first point
        l.copy(points[0]);
        if(q){
            q.vmult(l, l);
        }
        u.copy(l);

        for(var i = 1; i<points.length; i++){
            var p = points[i];

            if(q){
                q.vmult(p, tmp);
                p = tmp;
            }

            if(p.x > u.x){ u.x = p.x; }
            if(p.x < l.x){ l.x = p.x; }
            if(p.y > u.y){ u.y = p.y; }
            if(p.y < l.y){ l.y = p.y; }
            if(p.z > u.z){ u.z = p.z; }
            if(p.z < l.z){ l.z = p.z; }
        }

        // Add offset
        if (position) {
            position.vadd(l, l);
            position.vadd(u, u);
        }

        if(skinSize){
            l.x -= skinSize;
            l.y -= skinSize;
            l.z -= skinSize;
            u.x += skinSize;
            u.y += skinSize;
            u.z += skinSize;
        }

        return this;
    };

    /**
     * Copy bounds from an AABB to this AABB
     * @method copy
     * @param  {AABB} aabb Source to copy from
     * @return {AABB} The this object, for chainability
     */
    AABB.prototype.copy = function(aabb){
        this.lowerBound.copy(aabb.lowerBound);
        this.upperBound.copy(aabb.upperBound);
        return this;
    };

    /**
     * Clone an AABB
     * @method clone
     */
    AABB.prototype.clone = function(){
        return new AABB().copy(this);
    };

    /**
     * Extend this AABB so that it covers the given AABB too.
     * @method extend
     * @param  {AABB} aabb
     */
    AABB.prototype.extend = function(aabb){
        // Extend lower bound
        var l = aabb.lowerBound.x;
        if(this.lowerBound.x > l){
            this.lowerBound.x = l;
        }

        // Upper
        var u = aabb.upperBound.x;
        if(this.upperBound.x < u){
            this.upperBound.x = u;
        }

        // Extend lower bound
        var l = aabb.lowerBound.y;
        if(this.lowerBound.y > l){
            this.lowerBound.y = l;
        }

        // Upper
        var u = aabb.upperBound.y;
        if(this.upperBound.y < u){
            this.upperBound.y = u;
        }

        // Extend lower bound
        var l = aabb.lowerBound.z;
        if(this.lowerBound.z > l){
            this.lowerBound.z = l;
        }

        // Upper
        var u = aabb.upperBound.z;
        if(this.upperBound.z < u){
            this.upperBound.z = u;
        }
    };

    /**
     * Returns true if the given AABB overlaps this AABB.
     * @method overlaps
     * @param  {AABB} aabb
     * @return {Boolean}
     */
    AABB.prototype.overlaps = function(aabb){
        var l1 = this.lowerBound,
            u1 = this.upperBound,
            l2 = aabb.lowerBound,
            u2 = aabb.upperBound;

        //      l2        u2
        //      |---------|
        // |--------|
        // l1       u1

        return ((l2.x <= u1.x && u1.x <= u2.x) || (l1.x <= u2.x && u2.x <= u1.x)) &&
               ((l2.y <= u1.y && u1.y <= u2.y) || (l1.y <= u2.y && u2.y <= u1.y)) &&
               ((l2.z <= u1.z && u1.z <= u2.z) || (l1.z <= u2.z && u2.z <= u1.z));
    };

    /**
     * Returns true if the given AABB is fully contained in this AABB.
     * @method contains
     * @param {AABB} aabb
     * @return {Boolean}
     */
    AABB.prototype.contains = function(aabb){
        var l1 = this.lowerBound,
            u1 = this.upperBound,
            l2 = aabb.lowerBound,
            u2 = aabb.upperBound;

        //      l2        u2
        //      |---------|
        // |---------------|
        // l1              u1

        return (
            (l1.x <= l2.x && u1.x >= u2.x) &&
            (l1.y <= l2.y && u1.y >= u2.y) &&
            (l1.z <= l2.z && u1.z >= u2.z)
        );
    };

    /**
     * @method getCorners
     * @param {Vec3} a
     * @param {Vec3} b
     * @param {Vec3} c
     * @param {Vec3} d
     * @param {Vec3} e
     * @param {Vec3} f
     * @param {Vec3} g
     * @param {Vec3} h
     */
    AABB.prototype.getCorners = function(a, b, c, d, e, f, g, h){
        var l = this.lowerBound,
            u = this.upperBound;

        a.copy(l);
        b.set( u.x, l.y, l.z );
        c.set( u.x, u.y, l.z );
        d.set( l.x, u.y, u.z );
        e.set( u.x, l.y, l.z );
        f.set( l.x, u.y, l.z );
        g.set( l.x, l.y, u.z );
        h.copy(u);
    };

    var transformIntoFrame_corners = [
        new Vec3(),
        new Vec3(),
        new Vec3(),
        new Vec3(),
        new Vec3(),
        new Vec3(),
        new Vec3(),
        new Vec3()
    ];

    /**
     * Get the representation of an AABB in another frame.
     * @method toLocalFrame
     * @param  {Transform} frame
     * @param  {AABB} target
     * @return {AABB} The "target" AABB object.
     */
    AABB.prototype.toLocalFrame = function(frame, target){

        var corners = transformIntoFrame_corners;
        var a = corners[0];
        var b = corners[1];
        var c = corners[2];
        var d = corners[3];
        var e = corners[4];
        var f = corners[5];
        var g = corners[6];
        var h = corners[7];

        // Get corners in current frame
        this.getCorners(a, b, c, d, e, f, g, h);

        // Transform them to new local frame
        for(var i=0; i !== 8; i++){
            var corner = corners[i];
            frame.pointToLocal(corner, corner);
        }

        return target.setFromPoints(corners);
    };

    /**
     * Get the representation of an AABB in the global frame.
     * @method toWorldFrame
     * @param  {Transform} frame
     * @param  {AABB} target
     * @return {AABB} The "target" AABB object.
     */
    AABB.prototype.toWorldFrame = function(frame, target){

        var corners = transformIntoFrame_corners;
        var a = corners[0];
        var b = corners[1];
        var c = corners[2];
        var d = corners[3];
        var e = corners[4];
        var f = corners[5];
        var g = corners[6];
        var h = corners[7];

        // Get corners in current frame
        this.getCorners(a, b, c, d, e, f, g, h);

        // Transform them to new local frame
        for(var i=0; i !== 8; i++){
            var corner = corners[i];
            frame.pointToWorld(corner, corner);
        }

        return target.setFromPoints(corners);
    };