import { AABB } from './AABB.js';
import { Vector3 } from './Vector3.js';
const aabb = new AABB();
/**
* Class representing a bounding sphere.
*
* @author {@link https://github.com/Mugen87|Mugen87}
*/
class BoundingSphere {
/**
* Constructs a new bounding sphere with the given values.
*
* @param {Vector3} center - The center position of the bounding sphere.
* @param {Number} radius - The radius of the bounding sphere.
*/
constructor( center = new Vector3(), radius = 0 ) {
/**
* The center position of the bounding sphere.
* @type {Vector3}
*/
this.center = center;
/**
* The radius of the bounding sphere.
* @type {Number}
*/
this.radius = radius;
}
/**
* Sets the given values to this bounding sphere.
*
* @param {Vector3} center - The center position of the bounding sphere.
* @param {Number} radius - The radius of the bounding sphere.
* @return {BoundingSphere} A reference to this bounding sphere.
*/
set( center, radius ) {
this.center = center;
this.radius = radius;
return this;
}
/**
* Copies all values from the given bounding sphere to this bounding sphere.
*
* @param {BoundingSphere} sphere - The bounding sphere to copy.
* @return {BoundingSphere} A reference to this bounding sphere.
*/
copy( sphere ) {
this.center.copy( sphere.center );
this.radius = sphere.radius;
return this;
}
/**
* Creates a new bounding sphere and copies all values from this bounding sphere.
*
* @return {BoundingSphere} A new bounding sphere.
*/
clone() {
return new this.constructor().copy( this );
}
/**
* Ensures the given point is inside this bounding sphere and stores
* the result in the given vector.
*
* @param {Vector3} point - A point in 3D space.
* @param {Vector3} result - The result vector.
* @return {Vector3} The result vector.
*/
clampPoint( point, result ) {
result.copy( point );
const squaredDistance = this.center.squaredDistanceTo( point );
if ( squaredDistance > ( this.radius * this.radius ) ) {
result.sub( this.center ).normalize();
result.multiplyScalar( this.radius ).add( this.center );
}
return result;
}
/**
* Returns true if the given point is inside this bounding sphere.
*
* @param {Vector3} point - A point in 3D space.
* @return {Boolean} The result of the containments test.
*/
containsPoint( point ) {
return ( point.squaredDistanceTo( this.center ) <= ( this.radius * this.radius ) );
}
/**
* Returns true if the given bounding sphere intersects this bounding sphere.
*
* @param {BoundingSphere} sphere - The bounding sphere to test.
* @return {Boolean} The result of the intersection test.
*/
intersectsBoundingSphere( sphere ) {
const radius = this.radius + sphere.radius;
return ( sphere.center.squaredDistanceTo( this.center ) <= ( radius * radius ) );
}
/**
* Returns true if the given plane intersects this bounding sphere.
*
* Reference: Testing Sphere Against Plane in Real-Time Collision Detection
* by Christer Ericson (chapter 5.2.2)
*
* @param {Plane} plane - The plane to test.
* @return {Boolean} The result of the intersection test.
*/
intersectsPlane( plane ) {
return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius;
}
/**
* Returns the normal for a given point on this bounding sphere's surface.
*
* @param {Vector3} point - The point on the surface
* @param {Vector3} result - The result vector.
* @return {Vector3} The result vector.
*/
getNormalFromSurfacePoint( point, result ) {
return result.subVectors( point, this.center ).normalize();
}
/**
* Computes a bounding sphere that encloses the given set of points.
*
* @param {Array<Vector3>} points - An array of 3D vectors representing points in 3D space.
* @return {BoundingSphere} A reference to this bounding sphere.
*/
fromPoints( points ) {
// Using an AABB is a simple way to compute a bounding sphere for a given set
// of points. However, there are other more complex algorithms that produce a
// more tight bounding sphere. For now, this approach is a good start.
aabb.fromPoints( points );
aabb.getCenter( this.center );
this.radius = this.center.distanceTo( aabb.max );
return this;
}
/**
* Transforms this bounding sphere with the given 4x4 transformation matrix.
*
* @param {Matrix4} matrix - The 4x4 transformation matrix.
* @return {BoundingSphere} A reference to this bounding sphere.
*/
applyMatrix4( matrix ) {
this.center.applyMatrix4( matrix );
this.radius = this.radius * matrix.getMaxScale();
return this;
}
/**
* Returns true if the given bounding sphere is deep equal with this bounding sphere.
*
* @param {BoundingSphere} sphere - The bounding sphere to test.
* @return {Boolean} The result of the equality test.
*/
equals( sphere ) {
return ( sphere.center.equals( this.center ) ) && ( sphere.radius === this.radius );
}
/**
* Transforms this instance into a JSON object.
*
* @return {Object} The JSON object.
*/
toJSON() {
return {
type: this.constructor.name,
center: this.center.toArray( new Array() ),
radius: this.radius
};
}
/**
* Restores this instance from the given JSON object.
*
* @param {Object} json - The JSON object.
* @return {BoundingSphere} A reference to this bounding sphere.
*/
fromJSON( json ) {
this.center.fromArray( json.center );
this.radius = json.radius;
return this;
}
}
export { BoundingSphere };