Skip to content

⬅️ Back to Table of Contents

📄 Box3.js

📊 Analysis Summary

Metric Count
🔧 Functions 34
🧱 Classes 1
📦 Imports 1
📊 Variables & Constants 19

📚 Table of Contents

🛠️ File Location:

📂 src/math/Box3.js

📦 Imports

Name Source
Vector3 ./Vector3.js

Variables & Constants

Name Type Kind Value Exported
geometry any let/var object.geometry
children any let/var object.children
min any let/var *not shown*
max any let/var *not shown*
axes number[] let/var [ 0, - _f0.z, _f0.y, 0, - _f1.z, _f1.y, 0, - _f2.z, _f2.y, _f0.z, 0, - _f0.x,...
_points Vector3[] let/var [ /*@__PURE__*/ new Vector3(), /*@__PURE__*/ new Vector3(), /*@__PURE__*/ new...
_vector Vector3 let/var new Vector3()
_box Box3 let/var new Box3()
_v0 Vector3 let/var new Vector3()
_v1 Vector3 let/var new Vector3()
_v2 Vector3 let/var new Vector3()
_f0 Vector3 let/var new Vector3()
_f1 Vector3 let/var new Vector3()
_f2 Vector3 let/var new Vector3()
_center Vector3 let/var new Vector3()
_extents Vector3 let/var new Vector3()
_triangleNormal Vector3 let/var new Vector3()
_testAxis Vector3 let/var new Vector3()
r number let/var extents.x * Math.abs( _testAxis.x ) + extents.y * Math.abs( _testAxis.y ) + e...

Functions

Box3.set(min: Vector3, max: Vector3): Box3

JSDoc:

/**
     * Sets the lower and upper boundaries of this box.
     * Please note that this method only copies the values from the given objects.
     *
     * @param {Vector3} min - The lower boundary of the box.
     * @param {Vector3} max - The upper boundary of the box.
     * @return {Box3} A reference to this bounding box.
     */

Parameters:

  • min Vector3
  • max Vector3

Returns: Box3

Calls:

  • this.min.copy
  • this.max.copy
Code
set( min, max ) {

        this.min.copy( min );
        this.max.copy( max );

        return this;

    }

Box3.setFromArray(array: number[]): Box3

JSDoc:

/**
     * Sets the upper and lower bounds of this box so it encloses the position data
     * in the given array.
     *
     * @param {Array<number>} array - An array holding 3D position data.
     * @return {Box3} A reference to this bounding box.
     */

Parameters:

  • array number[]

Returns: Box3

Calls:

  • this.makeEmpty
  • this.expandByPoint
  • _vector.fromArray
Code
setFromArray( array ) {

        this.makeEmpty();

        for ( let i = 0, il = array.length; i < il; i += 3 ) {

            this.expandByPoint( _vector.fromArray( array, i ) );

        }

        return this;

    }

Box3.setFromBufferAttribute(attribute: BufferAttribute): Box3

JSDoc:

/**
     * Sets the upper and lower bounds of this box so it encloses the position data
     * in the given buffer attribute.
     *
     * @param {BufferAttribute} attribute - A buffer attribute holding 3D position data.
     * @return {Box3} A reference to this bounding box.
     */

Parameters:

  • attribute BufferAttribute

Returns: Box3

Calls:

  • this.makeEmpty
  • this.expandByPoint
  • _vector.fromBufferAttribute
Code
setFromBufferAttribute( attribute ) {

        this.makeEmpty();

        for ( let i = 0, il = attribute.count; i < il; i ++ ) {

            this.expandByPoint( _vector.fromBufferAttribute( attribute, i ) );

        }

        return this;

    }

Box3.setFromPoints(points: Vector3[]): Box3

JSDoc:

/**
     * Sets the upper and lower bounds of this box so it encloses the position data
     * in the given array.
     *
     * @param {Array<Vector3>} points - An array holding 3D position data as instances of {@link Vector3}.
     * @return {Box3} A reference to this bounding box.
     */

Parameters:

  • points Vector3[]

Returns: Box3

Calls:

  • this.makeEmpty
  • this.expandByPoint
Code
setFromPoints( points ) {

        this.makeEmpty();

        for ( let i = 0, il = points.length; i < il; i ++ ) {

            this.expandByPoint( points[ i ] );

        }

        return this;

    }

Box3.setFromCenterAndSize(center: Vector3, size: Vector3): Box3

JSDoc:

/**
     * Centers this box on the given center vector and sets this box's width, height and
     * depth to the given size values.
     *
     * @param {Vector3} center - The center of the box.
     * @param {Vector3} size - The x, y and z dimensions of the box.
     * @return {Box3} A reference to this bounding box.
     */

Parameters:

  • center Vector3
  • size Vector3

Returns: Box3

Calls:

  • _vector.copy( size ).multiplyScalar
  • this.min.copy( center ).sub
  • this.max.copy( center ).add
Code
setFromCenterAndSize( center, size ) {

        const halfSize = _vector.copy( size ).multiplyScalar( 0.5 );

        this.min.copy( center ).sub( halfSize );
        this.max.copy( center ).add( halfSize );

        return this;

    }

Box3.setFromObject(object: Object3D, precise: boolean): Box3

JSDoc:

/**
     * Computes the world-axis-aligned bounding box for the given 3D object
     * (including its children), accounting for the object's, and children's,
     * world transforms. The function may result in a larger box than strictly necessary.
     *
     * @param {Object3D} object - The 3D object to compute the bounding box for.
     * @param {boolean} [precise=false] - If set to `true`, the method computes the smallest
     * world-axis-aligned bounding box at the expense of more computation.
     * @return {Box3} A reference to this bounding box.
     */

Parameters:

  • object Object3D
  • precise boolean

Returns: Box3

Calls:

  • this.makeEmpty
  • this.expandByObject
Code
setFromObject( object, precise = false ) {

        this.makeEmpty();

        return this.expandByObject( object, precise );

    }

Box3.clone(): Box3

JSDoc:

/**
     * Returns a new box with copied values from this instance.
     *
     * @return {Box3} A clone of this instance.
     */

Returns: Box3

Calls:

  • new this.constructor().copy
Code
clone() {

        return new this.constructor().copy( this );

    }

Box3.copy(box: Box3): Box3

JSDoc:

/**
     * Copies the values of the given box to this instance.
     *
     * @param {Box3} box - The box to copy.
     * @return {Box3} A reference to this bounding box.
     */

Parameters:

  • box Box3

Returns: Box3

Calls:

  • this.min.copy
  • this.max.copy
Code
copy( box ) {

        this.min.copy( box.min );
        this.max.copy( box.max );

        return this;

    }

Box3.makeEmpty(): Box3

JSDoc:

/**
     * Makes this box empty which means in encloses a zero space in 3D.
     *
     * @return {Box3} A reference to this bounding box.
     */

Returns: Box3

Code
makeEmpty() {

        this.min.x = this.min.y = this.min.z = + Infinity;
        this.max.x = this.max.y = this.max.z = - Infinity;

        return this;

    }

Box3.isEmpty(): boolean

JSDoc:

/**
     * Returns true if this box includes zero points within its bounds.
     * Note that a box with equal lower and upper bounds still includes one
     * point, the one both bounds share.
     *
     * @return {boolean} Whether this box is empty or not.
     */

Returns: boolean

Internal Comments:

// this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes

Code
isEmpty() {

        // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes

        return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z );

    }

Box3.getCenter(target: Vector3): Vector3

JSDoc:

/**
     * Returns the center point of this box.
     *
     * @param {Vector3} target - The target vector that is used to store the method's result.
     * @return {Vector3} The center point.
     */

Parameters:

  • target Vector3

Returns: Vector3

Calls:

  • this.isEmpty
  • target.set
  • target.addVectors( this.min, this.max ).multiplyScalar
Code
getCenter( target ) {

        return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 );

    }

Box3.getSize(target: Vector3): Vector3

JSDoc:

/**
     * Returns the dimensions of this box.
     *
     * @param {Vector3} target - The target vector that is used to store the method's result.
     * @return {Vector3} The size.
     */

Parameters:

  • target Vector3

Returns: Vector3

Calls:

  • this.isEmpty
  • target.set
  • target.subVectors
Code
getSize( target ) {

        return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min );

    }

Box3.expandByPoint(point: Vector3): Box3

JSDoc:

/**
     * Expands the boundaries of this box to include the given point.
     *
     * @param {Vector3} point - The point that should be included by the bounding box.
     * @return {Box3} A reference to this bounding box.
     */

Parameters:

  • point Vector3

Returns: Box3

Calls:

  • this.min.min
  • this.max.max
Code
expandByPoint( point ) {

        this.min.min( point );
        this.max.max( point );

        return this;

    }

Box3.expandByVector(vector: Vector3): Box3

JSDoc:

/**
     * Expands this box equilaterally by the given vector. The width of this
     * box will be expanded by the x component of the vector in both
     * directions. The height of this box will be expanded by the y component of
     * the vector in both directions. The depth of this box will be
     * expanded by the z component of the vector in both directions.
     *
     * @param {Vector3} vector - The vector that should expand the bounding box.
     * @return {Box3} A reference to this bounding box.
     */

Parameters:

  • vector Vector3

Returns: Box3

Calls:

  • this.min.sub
  • this.max.add
Code
expandByVector( vector ) {

        this.min.sub( vector );
        this.max.add( vector );

        return this;

    }

Box3.expandByScalar(scalar: number): Box3

JSDoc:

/**
     * Expands each dimension of the box by the given scalar. If negative, the
     * dimensions of the box will be contracted.
     *
     * @param {number} scalar - The scalar value that should expand the bounding box.
     * @return {Box3} A reference to this bounding box.
     */

Parameters:

  • scalar number

Returns: Box3

Calls:

  • this.min.addScalar
  • this.max.addScalar
Code
expandByScalar( scalar ) {

        this.min.addScalar( - scalar );
        this.max.addScalar( scalar );

        return this;

    }

Box3.expandByObject(object: Object3D, precise: boolean): Box3

JSDoc:

/**
     * Expands the boundaries of this box to include the given 3D object and
     * its children, accounting for the object's, and children's, world
     * transforms. The function may result in a larger box than strictly
     * necessary (unless the precise parameter is set to true).
     *
     * @param {Object3D} object - The 3D object that should expand the bounding box.
     * @param {boolean} precise - If set to `true`, the method expands the bounding box
     * as little as necessary at the expense of more computation.
     * @return {Box3} A reference to this bounding box.
     */

Parameters:

  • object Object3D
  • precise boolean

Returns: Box3

Calls:

  • object.updateWorldMatrix
  • geometry.getAttribute
  • object.getVertexPosition
  • _vector.fromBufferAttribute
  • _vector.applyMatrix4
  • this.expandByPoint
  • object.computeBoundingBox
  • _box.copy
  • geometry.computeBoundingBox
  • _box.applyMatrix4
  • this.union
  • this.expandByObject

Internal Comments:

// Computes the world-axis-aligned bounding box of an object (including its children), (x4)
// accounting for both the object's, and children's, world transforms (x4)
// precise AABB computation based on vertex data requires at least a position attribute.
// instancing isn't supported so far and uses the normal (conservative) code path.
// object-level bounding box
// geometry-level bounding box

Code
expandByObject( object, precise = false ) {

        // Computes the world-axis-aligned bounding box of an object (including its children),
        // accounting for both the object's, and children's, world transforms

        object.updateWorldMatrix( false, false );

        const geometry = object.geometry;

        if ( geometry !== undefined ) {

            const positionAttribute = geometry.getAttribute( 'position' );

            // precise AABB computation based on vertex data requires at least a position attribute.
            // instancing isn't supported so far and uses the normal (conservative) code path.

            if ( precise === true && positionAttribute !== undefined && object.isInstancedMesh !== true ) {

                for ( let i = 0, l = positionAttribute.count; i < l; i ++ ) {

                    if ( object.isMesh === true ) {

                        object.getVertexPosition( i, _vector );

                    } else {

                        _vector.fromBufferAttribute( positionAttribute, i );

                    }

                    _vector.applyMatrix4( object.matrixWorld );
                    this.expandByPoint( _vector );

                }

            } else {

                if ( object.boundingBox !== undefined ) {

                    // object-level bounding box

                    if ( object.boundingBox === null ) {

                        object.computeBoundingBox();

                    }

                    _box.copy( object.boundingBox );


                } else {

                    // geometry-level bounding box

                    if ( geometry.boundingBox === null ) {

                        geometry.computeBoundingBox();

                    }

                    _box.copy( geometry.boundingBox );

                }

                _box.applyMatrix4( object.matrixWorld );

                this.union( _box );

            }

        }

        const children = object.children;

        for ( let i = 0, l = children.length; i < l; i ++ ) {

            this.expandByObject( children[ i ], precise );

        }

        return this;

    }

Box3.containsPoint(point: Vector3): boolean

JSDoc:

/**
     * Returns `true` if the given point lies within or on the boundaries of this box.
     *
     * @param {Vector3} point - The point to test.
     * @return {boolean} Whether the bounding box contains the given point or not.
     */

Parameters:

  • point Vector3

Returns: boolean

Code
containsPoint( point ) {

        return point.x >= this.min.x && point.x <= this.max.x &&
            point.y >= this.min.y && point.y <= this.max.y &&
            point.z >= this.min.z && point.z <= this.max.z;

    }

Box3.containsBox(box: Box3): boolean

JSDoc:

/**
     * Returns `true` if this bounding box includes the entirety of the given bounding box.
     * If this box and the given one are identical, this function also returns `true`.
     *
     * @param {Box3} box - The bounding box to test.
     * @return {boolean} Whether the bounding box contains the given bounding box or not.
     */

Parameters:

  • box Box3

Returns: boolean

Code
containsBox( box ) {

        return this.min.x <= box.min.x && box.max.x <= this.max.x &&
            this.min.y <= box.min.y && box.max.y <= this.max.y &&
            this.min.z <= box.min.z && box.max.z <= this.max.z;

    }

Box3.getParameter(point: Vector3, target: Vector3): Vector3

JSDoc:

/**
     * Returns a point as a proportion of this box's width, height and depth.
     *
     * @param {Vector3} point - A point in 3D space.
     * @param {Vector3} target - The target vector that is used to store the method's result.
     * @return {Vector3} A point as a proportion of this box's width, height and depth.
     */

Parameters:

  • point Vector3
  • target Vector3

Returns: Vector3

Calls:

  • target.set

Internal Comments:

// This can potentially have a divide by zero if the box
// has a size dimension of 0.

Code
getParameter( point, target ) {

        // This can potentially have a divide by zero if the box
        // has a size dimension of 0.

        return target.set(
            ( point.x - this.min.x ) / ( this.max.x - this.min.x ),
            ( point.y - this.min.y ) / ( this.max.y - this.min.y ),
            ( point.z - this.min.z ) / ( this.max.z - this.min.z )
        );

    }

Box3.intersectsBox(box: Box3): boolean

JSDoc:

/**
     * Returns `true` if the given bounding box intersects with this bounding box.
     *
     * @param {Box3} box - The bounding box to test.
     * @return {boolean} Whether the given bounding box intersects with this bounding box.
     */

Parameters:

  • box Box3

Returns: boolean

Internal Comments:

// using 6 splitting planes to rule out intersections.

Code
intersectsBox( box ) {

        // using 6 splitting planes to rule out intersections.
        return box.max.x >= this.min.x && box.min.x <= this.max.x &&
            box.max.y >= this.min.y && box.min.y <= this.max.y &&
            box.max.z >= this.min.z && box.min.z <= this.max.z;

    }

Box3.intersectsSphere(sphere: Sphere): boolean

JSDoc:

/**
     * Returns `true` if the given bounding sphere intersects with this bounding box.
     *
     * @param {Sphere} sphere - The bounding sphere to test.
     * @return {boolean} Whether the given bounding sphere intersects with this bounding box.
     */

Parameters:

  • sphere Sphere

Returns: boolean

Calls:

  • this.clampPoint
  • _vector.distanceToSquared

Internal Comments:

// Find the point on the AABB closest to the sphere center. (x4)
// If that point is inside the sphere, the AABB and sphere intersect.

Code
intersectsSphere( sphere ) {

        // Find the point on the AABB closest to the sphere center.
        this.clampPoint( sphere.center, _vector );

        // If that point is inside the sphere, the AABB and sphere intersect.
        return _vector.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius );

    }

Box3.intersectsPlane(plane: Plane): boolean

JSDoc:

/**
     * Returns `true` if the given plane intersects with this bounding box.
     *
     * @param {Plane} plane - The plane to test.
     * @return {boolean} Whether the given plane intersects with this bounding box.
     */

Parameters:

  • plane Plane

Returns: boolean

Internal Comments:

// We compute the minimum and maximum dot product values. If those values (x2)
// are on the same side (back or front) of the plane, then there is no intersection. (x2)

Code
intersectsPlane( plane ) {

        // We compute the minimum and maximum dot product values. If those values
        // are on the same side (back or front) of the plane, then there is no intersection.

        let min, max;

        if ( plane.normal.x > 0 ) {

            min = plane.normal.x * this.min.x;
            max = plane.normal.x * this.max.x;

        } else {

            min = plane.normal.x * this.max.x;
            max = plane.normal.x * this.min.x;

        }

        if ( plane.normal.y > 0 ) {

            min += plane.normal.y * this.min.y;
            max += plane.normal.y * this.max.y;

        } else {

            min += plane.normal.y * this.max.y;
            max += plane.normal.y * this.min.y;

        }

        if ( plane.normal.z > 0 ) {

            min += plane.normal.z * this.min.z;
            max += plane.normal.z * this.max.z;

        } else {

            min += plane.normal.z * this.max.z;
            max += plane.normal.z * this.min.z;

        }

        return ( min <= - plane.constant && max >= - plane.constant );

    }

Box3.intersectsTriangle(triangle: Triangle): boolean

JSDoc:

/**
     * Returns `true` if the given triangle intersects with this bounding box.
     *
     * @param {Triangle} triangle - The triangle to test.
     * @return {boolean} Whether the given triangle intersects with this bounding box.
     */

Parameters:

  • triangle Triangle

Returns: boolean

Calls:

  • this.isEmpty
  • this.getCenter
  • _extents.subVectors
  • _v0.subVectors
  • _v1.subVectors
  • _v2.subVectors
  • _f0.subVectors
  • _f1.subVectors
  • _f2.subVectors
  • satForAxes
  • _triangleNormal.crossVectors

Internal Comments:

// compute box center and extents (x4)
// translate triangle to aabb origin (x4)
// compute edge vectors for triangle (x4)
// test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb (x2)
// make an axis testing of each of the 3 sides of the aabb against each of the 3 sides of the triangle = 9 axis of separation (x2)
// axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned) (x2)
// test 3 face normals from the aabb (x3)
// finally testing the face normal of the triangle (x4)
// use already existing triangle edge vectors here (x4)

Code
intersectsTriangle( triangle ) {

        if ( this.isEmpty() ) {

            return false;

        }

        // compute box center and extents
        this.getCenter( _center );
        _extents.subVectors( this.max, _center );

        // translate triangle to aabb origin
        _v0.subVectors( triangle.a, _center );
        _v1.subVectors( triangle.b, _center );
        _v2.subVectors( triangle.c, _center );

        // compute edge vectors for triangle
        _f0.subVectors( _v1, _v0 );
        _f1.subVectors( _v2, _v1 );
        _f2.subVectors( _v0, _v2 );

        // test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb
        // make an axis testing of each of the 3 sides of the aabb against each of the 3 sides of the triangle = 9 axis of separation
        // axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned)
        let axes = [
            0, - _f0.z, _f0.y, 0, - _f1.z, _f1.y, 0, - _f2.z, _f2.y,
            _f0.z, 0, - _f0.x, _f1.z, 0, - _f1.x, _f2.z, 0, - _f2.x,
            - _f0.y, _f0.x, 0, - _f1.y, _f1.x, 0, - _f2.y, _f2.x, 0
        ];
        if ( ! satForAxes( axes, _v0, _v1, _v2, _extents ) ) {

            return false;

        }

        // test 3 face normals from the aabb
        axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ];
        if ( ! satForAxes( axes, _v0, _v1, _v2, _extents ) ) {

            return false;

        }

        // finally testing the face normal of the triangle
        // use already existing triangle edge vectors here
        _triangleNormal.crossVectors( _f0, _f1 );
        axes = [ _triangleNormal.x, _triangleNormal.y, _triangleNormal.z ];

        return satForAxes( axes, _v0, _v1, _v2, _extents );

    }

Box3.clampPoint(point: Vector3, target: Vector3): Vector3

JSDoc:

/**
     * Clamps the given point within the bounds of this box.
     *
     * @param {Vector3} point - The point to clamp.
     * @param {Vector3} target - The target vector that is used to store the method's result.
     * @return {Vector3} The clamped point.
     */

Parameters:

  • point Vector3
  • target Vector3

Returns: Vector3

Calls:

  • target.copy( point ).clamp
Code
clampPoint( point, target ) {

        return target.copy( point ).clamp( this.min, this.max );

    }

Box3.distanceToPoint(point: Vector3): number

JSDoc:

/**
     * Returns the euclidean distance from any edge of this box to the specified point. If
     * the given point lies inside of this box, the distance will be `0`.
     *
     * @param {Vector3} point - The point to compute the distance to.
     * @return {number} The euclidean distance.
     */

Parameters:

  • point Vector3

Returns: number

Calls:

  • this.clampPoint( point, _vector ).distanceTo
Code
distanceToPoint( point ) {

        return this.clampPoint( point, _vector ).distanceTo( point );

    }

Box3.getBoundingSphere(target: Sphere): Sphere

JSDoc:

/**
     * Returns a bounding sphere that encloses this bounding box.
     *
     * @param {Sphere} target - The target sphere that is used to store the method's result.
     * @return {Sphere} The bounding sphere that encloses this bounding box.
     */

Parameters:

  • target Sphere

Returns: Sphere

Calls:

  • this.isEmpty
  • target.makeEmpty
  • this.getCenter
  • this.getSize( _vector ).length
Code
getBoundingSphere( target ) {

        if ( this.isEmpty() ) {

            target.makeEmpty();

        } else {

            this.getCenter( target.center );

            target.radius = this.getSize( _vector ).length() * 0.5;

        }

        return target;

    }

Box3.intersect(box: Box3): Box3

JSDoc:

/**
     * Computes the intersection of this bounding box and the given one, setting the upper
     * bound of this box to the lesser of the two boxes' upper bounds and the
     * lower bound of this box to the greater of the two boxes' lower bounds. If
     * there's no overlap, makes this box empty.
     *
     * @param {Box3} box - The bounding box to intersect with.
     * @return {Box3} A reference to this bounding box.
     */

Parameters:

  • box Box3

Returns: Box3

Calls:

  • this.min.max
  • this.max.min
  • this.isEmpty
  • this.makeEmpty

Internal Comments:

// ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values.

Code
intersect( box ) {

        this.min.max( box.min );
        this.max.min( box.max );

        // ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values.
        if ( this.isEmpty() ) this.makeEmpty();

        return this;

    }

Box3.union(box: Box3): Box3

JSDoc:

/**
     * Computes the union of this box and another and the given one, setting the upper
     * bound of this box to the greater of the two boxes' upper bounds and the
     * lower bound of this box to the lesser of the two boxes' lower bounds.
     *
     * @param {Box3} box - The bounding box that will be unioned with this instance.
     * @return {Box3} A reference to this bounding box.
     */

Parameters:

  • box Box3

Returns: Box3

Calls:

  • this.min.min
  • this.max.max
Code
union( box ) {

        this.min.min( box.min );
        this.max.max( box.max );

        return this;

    }

Box3.applyMatrix4(matrix: Matrix4): Box3

JSDoc:

/**
     * Transforms this bounding box by the given 4x4 transformation matrix.
     *
     * @param {Matrix4} matrix - The transformation matrix.
     * @return {Box3} A reference to this bounding box.
     */

Parameters:

  • matrix Matrix4

Returns: Box3

Calls:

  • this.isEmpty
  • _points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4
  • _points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4
  • _points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4
  • _points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4
  • _points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4
  • _points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4
  • _points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4
  • _points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4
  • this.setFromPoints

Internal Comments:

// transform of empty box is an empty box.
// NOTE: I am using a binary pattern to specify all 2^3 combinations below (x7)

Code
applyMatrix4( matrix ) {

        // transform of empty box is an empty box.
        if ( this.isEmpty() ) return this;

        // NOTE: I am using a binary pattern to specify all 2^3 combinations below
        _points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000
        _points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001
        _points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010
        _points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011
        _points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100
        _points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101
        _points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110
        _points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111

        this.setFromPoints( _points );

        return this;

    }

Box3.translate(offset: Vector3): Box3

JSDoc:

/**
     * Adds the given offset to both the upper and lower bounds of this bounding box,
     * effectively moving it in 3D space.
     *
     * @param {Vector3} offset - The offset that should be used to translate the bounding box.
     * @return {Box3} A reference to this bounding box.
     */

Parameters:

  • offset Vector3

Returns: Box3

Calls:

  • this.min.add
  • this.max.add
Code
translate( offset ) {

        this.min.add( offset );
        this.max.add( offset );

        return this;

    }

Box3.equals(box: Box3): boolean

JSDoc:

/**
     * Returns `true` if this bounding box is equal with the given one.
     *
     * @param {Box3} box - The box to test for equality.
     * @return {boolean} Whether this bounding box is equal with the given one.
     */

Parameters:

  • box Box3

Returns: boolean

Calls:

  • box.min.equals
  • box.max.equals
Code
equals( box ) {

        return box.min.equals( this.min ) && box.max.equals( this.max );

    }

Box3.toJSON(): any

JSDoc:

/**
     * Returns a serialized structure of the bounding box.
     *
     * @return {Object} Serialized structure with fields representing the object state.
     */

Returns: any

Calls:

  • this.min.toArray
  • this.max.toArray
Code
toJSON() {

        return {
            min: this.min.toArray(),
            max: this.max.toArray()
        };

    }

Box3.fromJSON(json: any): Box3

JSDoc:

/**
     * Returns a serialized structure of the bounding box.
     *
     * @param {Object} json - The serialized json to set the box from.
     * @return {Box3} A reference to this bounding box.
     */

Parameters:

  • json any

Returns: Box3

Calls:

  • this.min.fromArray
  • this.max.fromArray
Code
fromJSON( json ) {

        this.min.fromArray( json.min );
        this.max.fromArray( json.max );
        return this;

    }

satForAxes(axes: any, v0: any, v1: any, v2: any, extents: any): boolean

Parameters:

  • axes any
  • v0 any
  • v1 any
  • v2 any
  • extents any

Returns: boolean

Calls:

  • _testAxis.fromArray
  • Math.abs
  • v0.dot
  • v1.dot
  • v2.dot
  • Math.max
  • Math.min

Internal Comments:

// project the aabb onto the separating axis (x2)
// project all 3 vertices of the triangle onto the separating axis (x2)
// actual test, basically see if either of the most extreme of the triangle points intersects r
// points of the projected triangle are outside the projected half-length of the aabb
// the axis is separating and we can exit

Code
function satForAxes( axes, v0, v1, v2, extents ) {

    for ( let i = 0, j = axes.length - 3; i <= j; i += 3 ) {

        _testAxis.fromArray( axes, i );
        // project the aabb onto the separating axis
        const r = extents.x * Math.abs( _testAxis.x ) + extents.y * Math.abs( _testAxis.y ) + extents.z * Math.abs( _testAxis.z );
        // project all 3 vertices of the triangle onto the separating axis
        const p0 = v0.dot( _testAxis );
        const p1 = v1.dot( _testAxis );
        const p2 = v2.dot( _testAxis );
        // actual test, basically see if either of the most extreme of the triangle points intersects r
        if ( Math.max( - Math.max( p0, p1, p2 ), Math.min( p0, p1, p2 ) ) > r ) {

            // points of the projected triangle are outside the projected half-length of the aabb
            // the axis is separating and we can exit
            return false;

        }

    }

    return true;

}

Classes

Box3

Class Code
class Box3 {

    /**
     * Constructs a new bounding box.
     *
     * @param {Vector3} [min=(Infinity,Infinity,Infinity)] - A vector representing the lower boundary of the box.
     * @param {Vector3} [max=(-Infinity,-Infinity,-Infinity)] - A vector representing the upper boundary of the box.
     */
    constructor( min = new Vector3( + Infinity, + Infinity, + Infinity ), max = new Vector3( - Infinity, - Infinity, - Infinity ) ) {

        /**
         * This flag can be used for type testing.
         *
         * @type {boolean}
         * @readonly
         * @default true
         */
        this.isBox3 = true;

        /**
         * The lower boundary of the box.
         *
         * @type {Vector3}
         */
        this.min = min;

        /**
         * The upper boundary of the box.
         *
         * @type {Vector3}
         */
        this.max = max;

    }

    /**
     * Sets the lower and upper boundaries of this box.
     * Please note that this method only copies the values from the given objects.
     *
     * @param {Vector3} min - The lower boundary of the box.
     * @param {Vector3} max - The upper boundary of the box.
     * @return {Box3} A reference to this bounding box.
     */
    set( min, max ) {

        this.min.copy( min );
        this.max.copy( max );

        return this;

    }

    /**
     * Sets the upper and lower bounds of this box so it encloses the position data
     * in the given array.
     *
     * @param {Array<number>} array - An array holding 3D position data.
     * @return {Box3} A reference to this bounding box.
     */
    setFromArray( array ) {

        this.makeEmpty();

        for ( let i = 0, il = array.length; i < il; i += 3 ) {

            this.expandByPoint( _vector.fromArray( array, i ) );

        }

        return this;

    }

    /**
     * Sets the upper and lower bounds of this box so it encloses the position data
     * in the given buffer attribute.
     *
     * @param {BufferAttribute} attribute - A buffer attribute holding 3D position data.
     * @return {Box3} A reference to this bounding box.
     */
    setFromBufferAttribute( attribute ) {

        this.makeEmpty();

        for ( let i = 0, il = attribute.count; i < il; i ++ ) {

            this.expandByPoint( _vector.fromBufferAttribute( attribute, i ) );

        }

        return this;

    }

    /**
     * Sets the upper and lower bounds of this box so it encloses the position data
     * in the given array.
     *
     * @param {Array<Vector3>} points - An array holding 3D position data as instances of {@link Vector3}.
     * @return {Box3} A reference to this bounding box.
     */
    setFromPoints( points ) {

        this.makeEmpty();

        for ( let i = 0, il = points.length; i < il; i ++ ) {

            this.expandByPoint( points[ i ] );

        }

        return this;

    }

    /**
     * Centers this box on the given center vector and sets this box's width, height and
     * depth to the given size values.
     *
     * @param {Vector3} center - The center of the box.
     * @param {Vector3} size - The x, y and z dimensions of the box.
     * @return {Box3} A reference to this bounding box.
     */
    setFromCenterAndSize( center, size ) {

        const halfSize = _vector.copy( size ).multiplyScalar( 0.5 );

        this.min.copy( center ).sub( halfSize );
        this.max.copy( center ).add( halfSize );

        return this;

    }

    /**
     * Computes the world-axis-aligned bounding box for the given 3D object
     * (including its children), accounting for the object's, and children's,
     * world transforms. The function may result in a larger box than strictly necessary.
     *
     * @param {Object3D} object - The 3D object to compute the bounding box for.
     * @param {boolean} [precise=false] - If set to `true`, the method computes the smallest
     * world-axis-aligned bounding box at the expense of more computation.
     * @return {Box3} A reference to this bounding box.
     */
    setFromObject( object, precise = false ) {

        this.makeEmpty();

        return this.expandByObject( object, precise );

    }

    /**
     * Returns a new box with copied values from this instance.
     *
     * @return {Box3} A clone of this instance.
     */
    clone() {

        return new this.constructor().copy( this );

    }

    /**
     * Copies the values of the given box to this instance.
     *
     * @param {Box3} box - The box to copy.
     * @return {Box3} A reference to this bounding box.
     */
    copy( box ) {

        this.min.copy( box.min );
        this.max.copy( box.max );

        return this;

    }

    /**
     * Makes this box empty which means in encloses a zero space in 3D.
     *
     * @return {Box3} A reference to this bounding box.
     */
    makeEmpty() {

        this.min.x = this.min.y = this.min.z = + Infinity;
        this.max.x = this.max.y = this.max.z = - Infinity;

        return this;

    }

    /**
     * Returns true if this box includes zero points within its bounds.
     * Note that a box with equal lower and upper bounds still includes one
     * point, the one both bounds share.
     *
     * @return {boolean} Whether this box is empty or not.
     */
    isEmpty() {

        // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes

        return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z );

    }

    /**
     * Returns the center point of this box.
     *
     * @param {Vector3} target - The target vector that is used to store the method's result.
     * @return {Vector3} The center point.
     */
    getCenter( target ) {

        return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 );

    }

    /**
     * Returns the dimensions of this box.
     *
     * @param {Vector3} target - The target vector that is used to store the method's result.
     * @return {Vector3} The size.
     */
    getSize( target ) {

        return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min );

    }

    /**
     * Expands the boundaries of this box to include the given point.
     *
     * @param {Vector3} point - The point that should be included by the bounding box.
     * @return {Box3} A reference to this bounding box.
     */
    expandByPoint( point ) {

        this.min.min( point );
        this.max.max( point );

        return this;

    }

    /**
     * Expands this box equilaterally by the given vector. The width of this
     * box will be expanded by the x component of the vector in both
     * directions. The height of this box will be expanded by the y component of
     * the vector in both directions. The depth of this box will be
     * expanded by the z component of the vector in both directions.
     *
     * @param {Vector3} vector - The vector that should expand the bounding box.
     * @return {Box3} A reference to this bounding box.
     */
    expandByVector( vector ) {

        this.min.sub( vector );
        this.max.add( vector );

        return this;

    }

    /**
     * Expands each dimension of the box by the given scalar. If negative, the
     * dimensions of the box will be contracted.
     *
     * @param {number} scalar - The scalar value that should expand the bounding box.
     * @return {Box3} A reference to this bounding box.
     */
    expandByScalar( scalar ) {

        this.min.addScalar( - scalar );
        this.max.addScalar( scalar );

        return this;

    }

    /**
     * Expands the boundaries of this box to include the given 3D object and
     * its children, accounting for the object's, and children's, world
     * transforms. The function may result in a larger box than strictly
     * necessary (unless the precise parameter is set to true).
     *
     * @param {Object3D} object - The 3D object that should expand the bounding box.
     * @param {boolean} precise - If set to `true`, the method expands the bounding box
     * as little as necessary at the expense of more computation.
     * @return {Box3} A reference to this bounding box.
     */
    expandByObject( object, precise = false ) {

        // Computes the world-axis-aligned bounding box of an object (including its children),
        // accounting for both the object's, and children's, world transforms

        object.updateWorldMatrix( false, false );

        const geometry = object.geometry;

        if ( geometry !== undefined ) {

            const positionAttribute = geometry.getAttribute( 'position' );

            // precise AABB computation based on vertex data requires at least a position attribute.
            // instancing isn't supported so far and uses the normal (conservative) code path.

            if ( precise === true && positionAttribute !== undefined && object.isInstancedMesh !== true ) {

                for ( let i = 0, l = positionAttribute.count; i < l; i ++ ) {

                    if ( object.isMesh === true ) {

                        object.getVertexPosition( i, _vector );

                    } else {

                        _vector.fromBufferAttribute( positionAttribute, i );

                    }

                    _vector.applyMatrix4( object.matrixWorld );
                    this.expandByPoint( _vector );

                }

            } else {

                if ( object.boundingBox !== undefined ) {

                    // object-level bounding box

                    if ( object.boundingBox === null ) {

                        object.computeBoundingBox();

                    }

                    _box.copy( object.boundingBox );


                } else {

                    // geometry-level bounding box

                    if ( geometry.boundingBox === null ) {

                        geometry.computeBoundingBox();

                    }

                    _box.copy( geometry.boundingBox );

                }

                _box.applyMatrix4( object.matrixWorld );

                this.union( _box );

            }

        }

        const children = object.children;

        for ( let i = 0, l = children.length; i < l; i ++ ) {

            this.expandByObject( children[ i ], precise );

        }

        return this;

    }

    /**
     * Returns `true` if the given point lies within or on the boundaries of this box.
     *
     * @param {Vector3} point - The point to test.
     * @return {boolean} Whether the bounding box contains the given point or not.
     */
    containsPoint( point ) {

        return point.x >= this.min.x && point.x <= this.max.x &&
            point.y >= this.min.y && point.y <= this.max.y &&
            point.z >= this.min.z && point.z <= this.max.z;

    }

    /**
     * Returns `true` if this bounding box includes the entirety of the given bounding box.
     * If this box and the given one are identical, this function also returns `true`.
     *
     * @param {Box3} box - The bounding box to test.
     * @return {boolean} Whether the bounding box contains the given bounding box or not.
     */
    containsBox( box ) {

        return this.min.x <= box.min.x && box.max.x <= this.max.x &&
            this.min.y <= box.min.y && box.max.y <= this.max.y &&
            this.min.z <= box.min.z && box.max.z <= this.max.z;

    }

    /**
     * Returns a point as a proportion of this box's width, height and depth.
     *
     * @param {Vector3} point - A point in 3D space.
     * @param {Vector3} target - The target vector that is used to store the method's result.
     * @return {Vector3} A point as a proportion of this box's width, height and depth.
     */
    getParameter( point, target ) {

        // This can potentially have a divide by zero if the box
        // has a size dimension of 0.

        return target.set(
            ( point.x - this.min.x ) / ( this.max.x - this.min.x ),
            ( point.y - this.min.y ) / ( this.max.y - this.min.y ),
            ( point.z - this.min.z ) / ( this.max.z - this.min.z )
        );

    }

    /**
     * Returns `true` if the given bounding box intersects with this bounding box.
     *
     * @param {Box3} box - The bounding box to test.
     * @return {boolean} Whether the given bounding box intersects with this bounding box.
     */
    intersectsBox( box ) {

        // using 6 splitting planes to rule out intersections.
        return box.max.x >= this.min.x && box.min.x <= this.max.x &&
            box.max.y >= this.min.y && box.min.y <= this.max.y &&
            box.max.z >= this.min.z && box.min.z <= this.max.z;

    }

    /**
     * Returns `true` if the given bounding sphere intersects with this bounding box.
     *
     * @param {Sphere} sphere - The bounding sphere to test.
     * @return {boolean} Whether the given bounding sphere intersects with this bounding box.
     */
    intersectsSphere( sphere ) {

        // Find the point on the AABB closest to the sphere center.
        this.clampPoint( sphere.center, _vector );

        // If that point is inside the sphere, the AABB and sphere intersect.
        return _vector.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius );

    }

    /**
     * Returns `true` if the given plane intersects with this bounding box.
     *
     * @param {Plane} plane - The plane to test.
     * @return {boolean} Whether the given plane intersects with this bounding box.
     */
    intersectsPlane( plane ) {

        // We compute the minimum and maximum dot product values. If those values
        // are on the same side (back or front) of the plane, then there is no intersection.

        let min, max;

        if ( plane.normal.x > 0 ) {

            min = plane.normal.x * this.min.x;
            max = plane.normal.x * this.max.x;

        } else {

            min = plane.normal.x * this.max.x;
            max = plane.normal.x * this.min.x;

        }

        if ( plane.normal.y > 0 ) {

            min += plane.normal.y * this.min.y;
            max += plane.normal.y * this.max.y;

        } else {

            min += plane.normal.y * this.max.y;
            max += plane.normal.y * this.min.y;

        }

        if ( plane.normal.z > 0 ) {

            min += plane.normal.z * this.min.z;
            max += plane.normal.z * this.max.z;

        } else {

            min += plane.normal.z * this.max.z;
            max += plane.normal.z * this.min.z;

        }

        return ( min <= - plane.constant && max >= - plane.constant );

    }

    /**
     * Returns `true` if the given triangle intersects with this bounding box.
     *
     * @param {Triangle} triangle - The triangle to test.
     * @return {boolean} Whether the given triangle intersects with this bounding box.
     */
    intersectsTriangle( triangle ) {

        if ( this.isEmpty() ) {

            return false;

        }

        // compute box center and extents
        this.getCenter( _center );
        _extents.subVectors( this.max, _center );

        // translate triangle to aabb origin
        _v0.subVectors( triangle.a, _center );
        _v1.subVectors( triangle.b, _center );
        _v2.subVectors( triangle.c, _center );

        // compute edge vectors for triangle
        _f0.subVectors( _v1, _v0 );
        _f1.subVectors( _v2, _v1 );
        _f2.subVectors( _v0, _v2 );

        // test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb
        // make an axis testing of each of the 3 sides of the aabb against each of the 3 sides of the triangle = 9 axis of separation
        // axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned)
        let axes = [
            0, - _f0.z, _f0.y, 0, - _f1.z, _f1.y, 0, - _f2.z, _f2.y,
            _f0.z, 0, - _f0.x, _f1.z, 0, - _f1.x, _f2.z, 0, - _f2.x,
            - _f0.y, _f0.x, 0, - _f1.y, _f1.x, 0, - _f2.y, _f2.x, 0
        ];
        if ( ! satForAxes( axes, _v0, _v1, _v2, _extents ) ) {

            return false;

        }

        // test 3 face normals from the aabb
        axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ];
        if ( ! satForAxes( axes, _v0, _v1, _v2, _extents ) ) {

            return false;

        }

        // finally testing the face normal of the triangle
        // use already existing triangle edge vectors here
        _triangleNormal.crossVectors( _f0, _f1 );
        axes = [ _triangleNormal.x, _triangleNormal.y, _triangleNormal.z ];

        return satForAxes( axes, _v0, _v1, _v2, _extents );

    }

    /**
     * Clamps the given point within the bounds of this box.
     *
     * @param {Vector3} point - The point to clamp.
     * @param {Vector3} target - The target vector that is used to store the method's result.
     * @return {Vector3} The clamped point.
     */
    clampPoint( point, target ) {

        return target.copy( point ).clamp( this.min, this.max );

    }

    /**
     * Returns the euclidean distance from any edge of this box to the specified point. If
     * the given point lies inside of this box, the distance will be `0`.
     *
     * @param {Vector3} point - The point to compute the distance to.
     * @return {number} The euclidean distance.
     */
    distanceToPoint( point ) {

        return this.clampPoint( point, _vector ).distanceTo( point );

    }

    /**
     * Returns a bounding sphere that encloses this bounding box.
     *
     * @param {Sphere} target - The target sphere that is used to store the method's result.
     * @return {Sphere} The bounding sphere that encloses this bounding box.
     */
    getBoundingSphere( target ) {

        if ( this.isEmpty() ) {

            target.makeEmpty();

        } else {

            this.getCenter( target.center );

            target.radius = this.getSize( _vector ).length() * 0.5;

        }

        return target;

    }

    /**
     * Computes the intersection of this bounding box and the given one, setting the upper
     * bound of this box to the lesser of the two boxes' upper bounds and the
     * lower bound of this box to the greater of the two boxes' lower bounds. If
     * there's no overlap, makes this box empty.
     *
     * @param {Box3} box - The bounding box to intersect with.
     * @return {Box3} A reference to this bounding box.
     */
    intersect( box ) {

        this.min.max( box.min );
        this.max.min( box.max );

        // ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values.
        if ( this.isEmpty() ) this.makeEmpty();

        return this;

    }

    /**
     * Computes the union of this box and another and the given one, setting the upper
     * bound of this box to the greater of the two boxes' upper bounds and the
     * lower bound of this box to the lesser of the two boxes' lower bounds.
     *
     * @param {Box3} box - The bounding box that will be unioned with this instance.
     * @return {Box3} A reference to this bounding box.
     */
    union( box ) {

        this.min.min( box.min );
        this.max.max( box.max );

        return this;

    }

    /**
     * Transforms this bounding box by the given 4x4 transformation matrix.
     *
     * @param {Matrix4} matrix - The transformation matrix.
     * @return {Box3} A reference to this bounding box.
     */
    applyMatrix4( matrix ) {

        // transform of empty box is an empty box.
        if ( this.isEmpty() ) return this;

        // NOTE: I am using a binary pattern to specify all 2^3 combinations below
        _points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000
        _points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001
        _points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010
        _points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011
        _points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100
        _points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101
        _points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110
        _points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111

        this.setFromPoints( _points );

        return this;

    }

    /**
     * Adds the given offset to both the upper and lower bounds of this bounding box,
     * effectively moving it in 3D space.
     *
     * @param {Vector3} offset - The offset that should be used to translate the bounding box.
     * @return {Box3} A reference to this bounding box.
     */
    translate( offset ) {

        this.min.add( offset );
        this.max.add( offset );

        return this;

    }

    /**
     * Returns `true` if this bounding box is equal with the given one.
     *
     * @param {Box3} box - The box to test for equality.
     * @return {boolean} Whether this bounding box is equal with the given one.
     */
    equals( box ) {

        return box.min.equals( this.min ) && box.max.equals( this.max );

    }

    /**
     * Returns a serialized structure of the bounding box.
     *
     * @return {Object} Serialized structure with fields representing the object state.
     */
    toJSON() {

        return {
            min: this.min.toArray(),
            max: this.max.toArray()
        };

    }

    /**
     * Returns a serialized structure of the bounding box.
     *
     * @param {Object} json - The serialized json to set the box from.
     * @return {Box3} A reference to this bounding box.
     */
    fromJSON( json ) {

        this.min.fromArray( json.min );
        this.max.fromArray( json.max );
        return this;

    }

}

Methods

set(min: Vector3, max: Vector3): Box3
Code
set( min, max ) {

        this.min.copy( min );
        this.max.copy( max );

        return this;

    }
setFromArray(array: number[]): Box3
Code
setFromArray( array ) {

        this.makeEmpty();

        for ( let i = 0, il = array.length; i < il; i += 3 ) {

            this.expandByPoint( _vector.fromArray( array, i ) );

        }

        return this;

    }
setFromBufferAttribute(attribute: BufferAttribute): Box3
Code
setFromBufferAttribute( attribute ) {

        this.makeEmpty();

        for ( let i = 0, il = attribute.count; i < il; i ++ ) {

            this.expandByPoint( _vector.fromBufferAttribute( attribute, i ) );

        }

        return this;

    }
setFromPoints(points: Vector3[]): Box3
Code
setFromPoints( points ) {

        this.makeEmpty();

        for ( let i = 0, il = points.length; i < il; i ++ ) {

            this.expandByPoint( points[ i ] );

        }

        return this;

    }
setFromCenterAndSize(center: Vector3, size: Vector3): Box3
Code
setFromCenterAndSize( center, size ) {

        const halfSize = _vector.copy( size ).multiplyScalar( 0.5 );

        this.min.copy( center ).sub( halfSize );
        this.max.copy( center ).add( halfSize );

        return this;

    }
setFromObject(object: Object3D, precise: boolean): Box3
Code
setFromObject( object, precise = false ) {

        this.makeEmpty();

        return this.expandByObject( object, precise );

    }
clone(): Box3
Code
clone() {

        return new this.constructor().copy( this );

    }
copy(box: Box3): Box3
Code
copy( box ) {

        this.min.copy( box.min );
        this.max.copy( box.max );

        return this;

    }
makeEmpty(): Box3
Code
makeEmpty() {

        this.min.x = this.min.y = this.min.z = + Infinity;
        this.max.x = this.max.y = this.max.z = - Infinity;

        return this;

    }
isEmpty(): boolean
Code
isEmpty() {

        // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes

        return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z );

    }
getCenter(target: Vector3): Vector3
Code
getCenter( target ) {

        return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 );

    }
getSize(target: Vector3): Vector3
Code
getSize( target ) {

        return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min );

    }
expandByPoint(point: Vector3): Box3
Code
expandByPoint( point ) {

        this.min.min( point );
        this.max.max( point );

        return this;

    }
expandByVector(vector: Vector3): Box3
Code
expandByVector( vector ) {

        this.min.sub( vector );
        this.max.add( vector );

        return this;

    }
expandByScalar(scalar: number): Box3
Code
expandByScalar( scalar ) {

        this.min.addScalar( - scalar );
        this.max.addScalar( scalar );

        return this;

    }
expandByObject(object: Object3D, precise: boolean): Box3
Code
expandByObject( object, precise = false ) {

        // Computes the world-axis-aligned bounding box of an object (including its children),
        // accounting for both the object's, and children's, world transforms

        object.updateWorldMatrix( false, false );

        const geometry = object.geometry;

        if ( geometry !== undefined ) {

            const positionAttribute = geometry.getAttribute( 'position' );

            // precise AABB computation based on vertex data requires at least a position attribute.
            // instancing isn't supported so far and uses the normal (conservative) code path.

            if ( precise === true && positionAttribute !== undefined && object.isInstancedMesh !== true ) {

                for ( let i = 0, l = positionAttribute.count; i < l; i ++ ) {

                    if ( object.isMesh === true ) {

                        object.getVertexPosition( i, _vector );

                    } else {

                        _vector.fromBufferAttribute( positionAttribute, i );

                    }

                    _vector.applyMatrix4( object.matrixWorld );
                    this.expandByPoint( _vector );

                }

            } else {

                if ( object.boundingBox !== undefined ) {

                    // object-level bounding box

                    if ( object.boundingBox === null ) {

                        object.computeBoundingBox();

                    }

                    _box.copy( object.boundingBox );


                } else {

                    // geometry-level bounding box

                    if ( geometry.boundingBox === null ) {

                        geometry.computeBoundingBox();

                    }

                    _box.copy( geometry.boundingBox );

                }

                _box.applyMatrix4( object.matrixWorld );

                this.union( _box );

            }

        }

        const children = object.children;

        for ( let i = 0, l = children.length; i < l; i ++ ) {

            this.expandByObject( children[ i ], precise );

        }

        return this;

    }
containsPoint(point: Vector3): boolean
Code
containsPoint( point ) {

        return point.x >= this.min.x && point.x <= this.max.x &&
            point.y >= this.min.y && point.y <= this.max.y &&
            point.z >= this.min.z && point.z <= this.max.z;

    }
containsBox(box: Box3): boolean
Code
containsBox( box ) {

        return this.min.x <= box.min.x && box.max.x <= this.max.x &&
            this.min.y <= box.min.y && box.max.y <= this.max.y &&
            this.min.z <= box.min.z && box.max.z <= this.max.z;

    }
getParameter(point: Vector3, target: Vector3): Vector3
Code
getParameter( point, target ) {

        // This can potentially have a divide by zero if the box
        // has a size dimension of 0.

        return target.set(
            ( point.x - this.min.x ) / ( this.max.x - this.min.x ),
            ( point.y - this.min.y ) / ( this.max.y - this.min.y ),
            ( point.z - this.min.z ) / ( this.max.z - this.min.z )
        );

    }
intersectsBox(box: Box3): boolean
Code
intersectsBox( box ) {

        // using 6 splitting planes to rule out intersections.
        return box.max.x >= this.min.x && box.min.x <= this.max.x &&
            box.max.y >= this.min.y && box.min.y <= this.max.y &&
            box.max.z >= this.min.z && box.min.z <= this.max.z;

    }
intersectsSphere(sphere: Sphere): boolean
Code
intersectsSphere( sphere ) {

        // Find the point on the AABB closest to the sphere center.
        this.clampPoint( sphere.center, _vector );

        // If that point is inside the sphere, the AABB and sphere intersect.
        return _vector.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius );

    }
intersectsPlane(plane: Plane): boolean
Code
intersectsPlane( plane ) {

        // We compute the minimum and maximum dot product values. If those values
        // are on the same side (back or front) of the plane, then there is no intersection.

        let min, max;

        if ( plane.normal.x > 0 ) {

            min = plane.normal.x * this.min.x;
            max = plane.normal.x * this.max.x;

        } else {

            min = plane.normal.x * this.max.x;
            max = plane.normal.x * this.min.x;

        }

        if ( plane.normal.y > 0 ) {

            min += plane.normal.y * this.min.y;
            max += plane.normal.y * this.max.y;

        } else {

            min += plane.normal.y * this.max.y;
            max += plane.normal.y * this.min.y;

        }

        if ( plane.normal.z > 0 ) {

            min += plane.normal.z * this.min.z;
            max += plane.normal.z * this.max.z;

        } else {

            min += plane.normal.z * this.max.z;
            max += plane.normal.z * this.min.z;

        }

        return ( min <= - plane.constant && max >= - plane.constant );

    }
intersectsTriangle(triangle: Triangle): boolean
Code
intersectsTriangle( triangle ) {

        if ( this.isEmpty() ) {

            return false;

        }

        // compute box center and extents
        this.getCenter( _center );
        _extents.subVectors( this.max, _center );

        // translate triangle to aabb origin
        _v0.subVectors( triangle.a, _center );
        _v1.subVectors( triangle.b, _center );
        _v2.subVectors( triangle.c, _center );

        // compute edge vectors for triangle
        _f0.subVectors( _v1, _v0 );
        _f1.subVectors( _v2, _v1 );
        _f2.subVectors( _v0, _v2 );

        // test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb
        // make an axis testing of each of the 3 sides of the aabb against each of the 3 sides of the triangle = 9 axis of separation
        // axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned)
        let axes = [
            0, - _f0.z, _f0.y, 0, - _f1.z, _f1.y, 0, - _f2.z, _f2.y,
            _f0.z, 0, - _f0.x, _f1.z, 0, - _f1.x, _f2.z, 0, - _f2.x,
            - _f0.y, _f0.x, 0, - _f1.y, _f1.x, 0, - _f2.y, _f2.x, 0
        ];
        if ( ! satForAxes( axes, _v0, _v1, _v2, _extents ) ) {

            return false;

        }

        // test 3 face normals from the aabb
        axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ];
        if ( ! satForAxes( axes, _v0, _v1, _v2, _extents ) ) {

            return false;

        }

        // finally testing the face normal of the triangle
        // use already existing triangle edge vectors here
        _triangleNormal.crossVectors( _f0, _f1 );
        axes = [ _triangleNormal.x, _triangleNormal.y, _triangleNormal.z ];

        return satForAxes( axes, _v0, _v1, _v2, _extents );

    }
clampPoint(point: Vector3, target: Vector3): Vector3
Code
clampPoint( point, target ) {

        return target.copy( point ).clamp( this.min, this.max );

    }
distanceToPoint(point: Vector3): number
Code
distanceToPoint( point ) {

        return this.clampPoint( point, _vector ).distanceTo( point );

    }
getBoundingSphere(target: Sphere): Sphere
Code
getBoundingSphere( target ) {

        if ( this.isEmpty() ) {

            target.makeEmpty();

        } else {

            this.getCenter( target.center );

            target.radius = this.getSize( _vector ).length() * 0.5;

        }

        return target;

    }
intersect(box: Box3): Box3
Code
intersect( box ) {

        this.min.max( box.min );
        this.max.min( box.max );

        // ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values.
        if ( this.isEmpty() ) this.makeEmpty();

        return this;

    }
union(box: Box3): Box3
Code
union( box ) {

        this.min.min( box.min );
        this.max.max( box.max );

        return this;

    }
applyMatrix4(matrix: Matrix4): Box3
Code
applyMatrix4( matrix ) {

        // transform of empty box is an empty box.
        if ( this.isEmpty() ) return this;

        // NOTE: I am using a binary pattern to specify all 2^3 combinations below
        _points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000
        _points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001
        _points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010
        _points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011
        _points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100
        _points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101
        _points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110
        _points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111

        this.setFromPoints( _points );

        return this;

    }
translate(offset: Vector3): Box3
Code
translate( offset ) {

        this.min.add( offset );
        this.max.add( offset );

        return this;

    }
equals(box: Box3): boolean
Code
equals( box ) {

        return box.min.equals( this.min ) && box.max.equals( this.max );

    }
toJSON(): any
Code
toJSON() {

        return {
            min: this.min.toArray(),
            max: this.max.toArray()
        };

    }
fromJSON(json: any): Box3
Code
fromJSON( json ) {

        this.min.fromArray( json.min );
        this.max.fromArray( json.max );
        return this;

    }