UNPKG

cannon

Version:

A lightweight 3D physics engine written in JavaScript.

301 lines (260 loc) 6.66 kB
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); };