(function() {
'use strict';
var EPSILON = require('./Epsilon');
/**
* Instantiates a Vec4 object.
* @class Vec4
* @classdesc A four component vector.
*/
function Vec4() {
switch ( arguments.length ) {
case 1:
// array or VecN argument
var argument = arguments[0];
this.x = argument.x || argument[0] || 0.0;
this.y = argument.y || argument[1] || 0.0;
this.z = argument.z || argument[2] || 0.0;
this.w = argument.w || argument[3] || 0.0;
break;
case 4:
// individual component arguments
this.x = arguments[0];
this.y = arguments[1];
this.z = arguments[2];
this.w = arguments[3] || 0.0;
break;
default:
this.x = 0.0;
this.y = 0.0;
this.z = 0.0;
this.w = 0.0;
break;
}
}
/**
* Returns a new Vec4 with each component negated.
* @memberof Vec4
*
* @returns {Vec4} The negated vector.
*/
Vec4.prototype.negate = function() {
return new Vec4( -this.x, -this.y, -this.z, -this.w );
};
/**
* Adds the vector with the provided vector argument, returning a new Vec4
* object representing the sum.
* @memberof Vec4
*
* @param {Vec4|Array} that - The vector to add.
*
* @returns {Vec4} The sum of the two vectors.
*/
Vec4.prototype.add = function( that ) {
if ( that instanceof Array ) {
return new Vec4(
this.x + that[0],
this.y + that[1],
this.z + that[2],
this.w + that[3] );
}
return new Vec4(
this.x + that.x,
this.y + that.y,
this.z + that.z,
this.w + that.w );
};
/**
* Subtracts the provided vector argument from the vector, returning a new Vec4
* object representing the difference.
* @memberof Vec4
*
* @param {Vec4|Array} - The vector to subtract.
*
* @returns {Vec4} The difference of the two vectors.
*/
Vec4.prototype.sub = function( that ) {
if ( that instanceof Array ) {
return new Vec4(
this.x - that[0],
this.y - that[1],
this.z - that[2],
this.w - that[3] );
}
return new Vec4(
this.x - that.x,
this.y - that.y,
this.z - that.z,
this.w - that.w );
};
/**
* Multiplies the vector with the provided scalar argument, returning a new Vec4
* object representing the scaled vector.
* @memberof Vec4
*
* @param {number} - The scalar to multiply the vector by.
*
* @returns {Vec4} The scaled vector.
*/
Vec4.prototype.multScalar = function( that ) {
return new Vec4(
this.x * that,
this.y * that,
this.z * that,
this.w * that );
};
/**
* Divides the vector with the provided scalar argument, returning a new Vec4
* object representing the scaled vector.
* @memberof Vec4
*
* @param {number} - The scalar to divide the vector by.
*
* @returns {Vec4} The scaled vector.
*/
Vec4.prototype.divScalar = function( that ) {
return new Vec4(
this.x / that,
this.y / that,
this.z / that,
this.w / that );
};
/**
* Calculates and returns the dot product of the vector and the provided
* vector argument.
* @memberof Vec4
*
* @param {Vec4|Array} - The other vector argument.
*
* @returns {number} The dot product.
*/
Vec4.prototype.dot = function( that ) {
if ( that instanceof Array ) {
return ( this.x * that[0] ) +
( this.y * that[1] ) +
( this.z * that[2] ) +
( this.w * that[3] );
}
return ( this.x * that.x ) +
( this.y * that.y ) +
( this.z * that.z ) +
( this.w * that.w );
};
/**
* If no argument is provided, this function returns the scalar length of
* the vector. If an argument is provided, this method will return a new
* Vec4 scaled to the provided length.
* @memberof Vec4
*
* @param {number} - The length to scale the vector to. Optional.
*
* @returns {number|Vec4} Either the length, or new scaled vector.
*/
Vec4.prototype.length = function( length ) {
if ( length === undefined ) {
var len = this.dot( this );
if ( Math.abs( len - 1.0 ) < EPSILON ) {
return len;
} else {
return Math.sqrt( len );
}
}
return this.normalize().multScalar( length );
};
/**
* Returns the squared length of the vector.
* @memberof Vec4
*
* @returns {number} The squared length of the vector.
*/
Vec4.prototype.lengthSquared = function() {
return this.dot( this );
};
/**
* Returns true if the vector components match those of a provided vector.
* An optional epsilon value may be provided.
* @memberof Vec4
*
* @param {Vec4|Array} that - The vector to test equality with.
* @param {number} epsilon - The epsilon value. Optional.
*
* @returns {boolean} Whether or not the vector components match.
*/
Vec4.prototype.equals = function( that, epsilon ) {
var x = that.x !== undefined ? that.x : that[0],
y = that.y !== undefined ? that.y : that[1],
z = that.z !== undefined ? that.z : that[2],
w = that.w !== undefined ? that.w : that[3];
epsilon = epsilon === undefined ? 0 : epsilon;
return ( this.x === x || Math.abs( this.x - x ) <= epsilon ) &&
( this.y === y || Math.abs( this.y - y ) <= epsilon ) &&
( this.z === z || Math.abs( this.z - z ) <= epsilon ) &&
( this.w === w || Math.abs( this.w - w ) <= epsilon );
};
/**
* Returns a new Vec4 of unit length.
* @memberof Vec4
*
* @returns {Vec4} The vector of unit length.
*/
Vec4.prototype.normalize = function() {
var mag = this.length();
if ( mag === 0 ) {
throw 'Cannot normalize a vector of zero length';
}
return new Vec4(
this.x / mag,
this.y / mag,
this.z / mag,
this.w / mag );
};
/**
* Returns a random Vec4 of unit length.
* @memberof Vec4
*
* @returns {Vec4} A random vector of unit length.
*/
Vec4.random = function() {
return new Vec4(
Math.random(),
Math.random(),
Math.random(),
Math.random() ).normalize();
};
/**
* Returns a string representation of the vector.
* @memberof Vec4
*
* @returns {String} The string representation of the vector.
*/
Vec4.prototype.toString = function() {
return this.x + ', ' + this.y + ', ' + this.z + ', ' + this.w;
};
/**
* Returns an array representation of the vector.
* @memberof Vec4
*
* @returns {Array} The vector as an array.
*/
Vec4.prototype.toArray = function() {
return [ this.x, this.y, this.z, this.w ];
};
module.exports = Vec4;
}());