UNPKG

cannon

Version:

A lightweight 3D physics engine written in JavaScript.

452 lines (412 loc) 9.89 kB
module.exports = Vec3; var Mat3 = require('./Mat3'); /** * 3-dimensional vector * @class Vec3 * @constructor * @param {Number} x * @param {Number} y * @param {Number} z * @author schteppe * @example * var v = new Vec3(1, 2, 3); * console.log('x=' + v.x); // x=1 */ function Vec3(x,y,z){ /** * @property x * @type {Number} */ this.x = x||0.0; /** * @property y * @type {Number} */ this.y = y||0.0; /** * @property z * @type {Number} */ this.z = z||0.0; } /** * @static * @property {Vec3} ZERO */ Vec3.ZERO = new Vec3(0, 0, 0); /** * @static * @property {Vec3} UNIT_X */ Vec3.UNIT_X = new Vec3(1, 0, 0); /** * @static * @property {Vec3} UNIT_Y */ Vec3.UNIT_Y = new Vec3(0, 1, 0); /** * @static * @property {Vec3} UNIT_Z */ Vec3.UNIT_Z = new Vec3(0, 0, 1); /** * Vector cross product * @method cross * @param {Vec3} v * @param {Vec3} target Optional. Target to save in. * @return {Vec3} */ Vec3.prototype.cross = function(v,target){ var vx=v.x, vy=v.y, vz=v.z, x=this.x, y=this.y, z=this.z; target = target || new Vec3(); target.x = (y * vz) - (z * vy); target.y = (z * vx) - (x * vz); target.z = (x * vy) - (y * vx); return target; }; /** * Set the vectors' 3 elements * @method set * @param {Number} x * @param {Number} y * @param {Number} z * @return Vec3 */ Vec3.prototype.set = function(x,y,z){ this.x = x; this.y = y; this.z = z; return this; }; /** * Set all components of the vector to zero. * @method setZero */ Vec3.prototype.setZero = function(){ this.x = this.y = this.z = 0; }; /** * Vector addition * @method vadd * @param {Vec3} v * @param {Vec3} target Optional. * @return {Vec3} */ Vec3.prototype.vadd = function(v,target){ if(target){ target.x = v.x + this.x; target.y = v.y + this.y; target.z = v.z + this.z; } else { return new Vec3(this.x + v.x, this.y + v.y, this.z + v.z); } }; /** * Vector subtraction * @method vsub * @param {Vec3} v * @param {Vec3} target Optional. Target to save in. * @return {Vec3} */ Vec3.prototype.vsub = function(v,target){ if(target){ target.x = this.x - v.x; target.y = this.y - v.y; target.z = this.z - v.z; } else { return new Vec3(this.x-v.x, this.y-v.y, this.z-v.z); } }; /** * Get the cross product matrix a_cross from a vector, such that a x b = a_cross * b = c * @method crossmat * @see http://www8.cs.umu.se/kurser/TDBD24/VT06/lectures/Lecture6.pdf * @return {Mat3} */ Vec3.prototype.crossmat = function(){ return new Mat3([ 0, -this.z, this.y, this.z, 0, -this.x, -this.y, this.x, 0]); }; /** * Normalize the vector. Note that this changes the values in the vector. * @method normalize * @return {Number} Returns the norm of the vector */ Vec3.prototype.normalize = function(){ var x=this.x, y=this.y, z=this.z; var n = Math.sqrt(x*x + y*y + z*z); if(n>0.0){ var invN = 1/n; this.x *= invN; this.y *= invN; this.z *= invN; } else { // Make something up this.x = 0; this.y = 0; this.z = 0; } return n; }; /** * Get the version of this vector that is of length 1. * @method unit * @param {Vec3} target Optional target to save in * @return {Vec3} Returns the unit vector */ Vec3.prototype.unit = function(target){ target = target || new Vec3(); var x=this.x, y=this.y, z=this.z; var ninv = Math.sqrt(x*x + y*y + z*z); if(ninv>0.0){ ninv = 1.0/ninv; target.x = x * ninv; target.y = y * ninv; target.z = z * ninv; } else { target.x = 1; target.y = 0; target.z = 0; } return target; }; /** * Get the length of the vector * @method norm * @return {Number} * @deprecated Use .length() instead */ Vec3.prototype.norm = function(){ var x=this.x, y=this.y, z=this.z; return Math.sqrt(x*x + y*y + z*z); }; /** * Get the length of the vector * @method length * @return {Number} */ Vec3.prototype.length = Vec3.prototype.norm; /** * Get the squared length of the vector * @method norm2 * @return {Number} * @deprecated Use .lengthSquared() instead. */ Vec3.prototype.norm2 = function(){ return this.dot(this); }; /** * Get the squared length of the vector. * @method lengthSquared * @return {Number} */ Vec3.prototype.lengthSquared = Vec3.prototype.norm2; /** * Get distance from this point to another point * @method distanceTo * @param {Vec3} p * @return {Number} */ Vec3.prototype.distanceTo = function(p){ var x=this.x, y=this.y, z=this.z; var px=p.x, py=p.y, pz=p.z; return Math.sqrt((px-x)*(px-x)+ (py-y)*(py-y)+ (pz-z)*(pz-z)); }; /** * Get squared distance from this point to another point * @method distanceSquared * @param {Vec3} p * @return {Number} */ Vec3.prototype.distanceSquared = function(p){ var x=this.x, y=this.y, z=this.z; var px=p.x, py=p.y, pz=p.z; return (px-x)*(px-x) + (py-y)*(py-y) + (pz-z)*(pz-z); }; /** * Multiply all the components of the vector with a scalar. * @deprecated Use .scale instead * @method mult * @param {Number} scalar * @param {Vec3} target The vector to save the result in. * @return {Vec3} * @deprecated Use .scale() instead */ Vec3.prototype.mult = function(scalar,target){ target = target || new Vec3(); var x = this.x, y = this.y, z = this.z; target.x = scalar * x; target.y = scalar * y; target.z = scalar * z; return target; }; /** * Multiply the vector with a scalar. * @method scale * @param {Number} scalar * @param {Vec3} target * @return {Vec3} */ Vec3.prototype.scale = Vec3.prototype.mult; /** * Calculate dot product * @method dot * @param {Vec3} v * @return {Number} */ Vec3.prototype.dot = function(v){ return this.x * v.x + this.y * v.y + this.z * v.z; }; /** * @method isZero * @return bool */ Vec3.prototype.isZero = function(){ return this.x===0 && this.y===0 && this.z===0; }; /** * Make the vector point in the opposite direction. * @method negate * @param {Vec3} target Optional target to save in * @return {Vec3} */ Vec3.prototype.negate = function(target){ target = target || new Vec3(); target.x = -this.x; target.y = -this.y; target.z = -this.z; return target; }; /** * Compute two artificial tangents to the vector * @method tangents * @param {Vec3} t1 Vector object to save the first tangent in * @param {Vec3} t2 Vector object to save the second tangent in */ var Vec3_tangents_n = new Vec3(); var Vec3_tangents_randVec = new Vec3(); Vec3.prototype.tangents = function(t1,t2){ var norm = this.norm(); if(norm>0.0){ var n = Vec3_tangents_n; var inorm = 1/norm; n.set(this.x*inorm,this.y*inorm,this.z*inorm); var randVec = Vec3_tangents_randVec; if(Math.abs(n.x) < 0.9){ randVec.set(1,0,0); n.cross(randVec,t1); } else { randVec.set(0,1,0); n.cross(randVec,t1); } n.cross(t1,t2); } else { // The normal length is zero, make something up t1.set(1, 0, 0); t2.set(0, 1, 0); } }; /** * Converts to a more readable format * @method toString * @return string */ Vec3.prototype.toString = function(){ return this.x+","+this.y+","+this.z; }; /** * Converts to an array * @method toArray * @return Array */ Vec3.prototype.toArray = function(){ return [this.x, this.y, this.z]; }; /** * Copies value of source to this vector. * @method copy * @param {Vec3} source * @return {Vec3} this */ Vec3.prototype.copy = function(source){ this.x = source.x; this.y = source.y; this.z = source.z; return this; }; /** * Do a linear interpolation between two vectors * @method lerp * @param {Vec3} v * @param {Number} t A number between 0 and 1. 0 will make this function return u, and 1 will make it return v. Numbers in between will generate a vector in between them. * @param {Vec3} target */ Vec3.prototype.lerp = function(v,t,target){ var x=this.x, y=this.y, z=this.z; target.x = x + (v.x-x)*t; target.y = y + (v.y-y)*t; target.z = z + (v.z-z)*t; }; /** * Check if a vector equals is almost equal to another one. * @method almostEquals * @param {Vec3} v * @param {Number} precision * @return bool */ Vec3.prototype.almostEquals = function(v,precision){ if(precision===undefined){ precision = 1e-6; } if( Math.abs(this.x-v.x)>precision || Math.abs(this.y-v.y)>precision || Math.abs(this.z-v.z)>precision){ return false; } return true; }; /** * Check if a vector is almost zero * @method almostZero * @param {Number} precision */ Vec3.prototype.almostZero = function(precision){ if(precision===undefined){ precision = 1e-6; } if( Math.abs(this.x)>precision || Math.abs(this.y)>precision || Math.abs(this.z)>precision){ return false; } return true; }; var antip_neg = new Vec3(); /** * Check if the vector is anti-parallel to another vector. * @method isAntiparallelTo * @param {Vec3} v * @param {Number} precision Set to zero for exact comparisons * @return {Boolean} */ Vec3.prototype.isAntiparallelTo = function(v,precision){ this.negate(antip_neg); return antip_neg.almostEquals(v,precision); }; /** * Clone the vector * @method clone * @return {Vec3} */ Vec3.prototype.clone = function(){ return new Vec3(this.x, this.y, this.z); };