(function() {
'use strict';
var EPSILON = require('./Epsilon');
/**
* Instantiates a Vec2 object.
* @class Vec2
* @classdesc A two component vector.
*/
function Vec2() {
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;
break;
case 2:
// individual component arguments
this.x = arguments[0];
this.y = arguments[1];
break;
default:
this.x = 0;
this.y = 0;
break;
}
}
/**
* Returns a new Vec2 with each component negated.
* @memberof Vec2
*
* @returns {Vec2} The negated vector.
*/
Vec2.prototype.negate = function() {
return new Vec2( -this.x, -this.y );
};
/**
* Adds the vector with the provided vector argument, returning a new Vec2
* object representing the sum.
* @memberof Vec2
*
* @param {Vec2|Vec3|Vec4|Array} that - The vector to add.
*
* @returns {Vec2} The sum of the two vectors.
*/
Vec2.prototype.add = function( that ) {
if ( that instanceof Array ) {
return new Vec2( this.x + that[0], this.y + that[1] );
}
return new Vec2( this.x + that.x, this.y + that.y );
};
/**
* Subtracts the provided vector argument from the vector, returning a new Vec2
* object representing the difference.
* @memberof Vec2
*
* @param {Vec2|Vec3|Vec4|Array} - The vector to subtract.
*
* @returns {Vec2} The difference of the two vectors.
*/
Vec2.prototype.sub = function( that ) {
if ( that instanceof Array ) {
return new Vec2( this.x - that[0], this.y - that[1] );
}
return new Vec2( this.x - that.x, this.y - that.y );
};
/**
* Multiplies the vector with the provided scalar argument, returning a new Vec2
* object representing the scaled vector.
* @memberof Vec2
*
* @param {number} - The scalar to multiply the vector by.
*
* @returns {Vec2} The scaled vector.
*/
Vec2.prototype.multScalar = function( that ) {
return new Vec2( this.x * that, this.y * that );
};
/**
* Divides the vector with the provided scalar argument, returning a new Vec2
* object representing the scaled vector.
* @memberof Vec2
*
* @param {number} - The scalar to divide the vector by.
*
* @returns {Vec2} The scaled vector.
*/
Vec2.prototype.divScalar = function( that ) {
return new Vec2( this.x / that, this.y / that );
};
/**
* Calculates and returns the dot product of the vector and the provided
* vector argument.
* @memberof Vec2
*
* @param {Vec2|Vec3|Vec4|Array} - The other vector argument.
*
* @returns {number} The dot product.
*/
Vec2.prototype.dot = function( that ) {
if ( that instanceof Array ) {
return ( this.x * that[0] ) + ( this.y * that[1] );
}
return ( this.x * that.x ) + ( this.y * that.y );
};
/**
* Calculates and returns 2D cross product of the vector and the provided
* vector argument. This value represents the magnitude of the vector that
* would result from a regular 3D cross product of the input vectors,
* taking their Z values as 0.
* @memberof Vec2
*
* @param {Vec2|Vec3|Vec4|Array} - The other vector argument.
*
* @returns {number} The 2D cross product.
*/
Vec2.prototype.cross = function( that ) {
if ( that instanceof Array ) {
return ( this.x * that[1] ) - ( this.y * that[0] );
}
return ( this.x * that.y ) - ( this.y * that.x );
};
/**
* 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
* Vec2 scaled to the provided length.
* @memberof Vec2
*
* @param {number} - The length to scale the vector to. Optional.
*
* @returns {number|Vec2} Either the length, or new scaled vector.
*/
Vec2.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 Vec2
*
* @returns {number} The squared length of the vector.
*/
Vec2.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 Vec2
*
* @param {Vec2|Vec3|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.
*/
Vec2.prototype.equals = function( that, epsilon ) {
var x = that.x !== undefined ? that.x : that[0],
y = that.y !== undefined ? that.y : that[1];
epsilon = epsilon === undefined ? 0 : epsilon;
return ( this.x === x || Math.abs( this.x - x ) <= epsilon ) &&
( this.y === y || Math.abs( this.y - y ) <= epsilon );
};
/**
* Returns a new Vec2 of unit length.
* @memberof Vec2
*
* @returns {Vec2} The vector of unit length.
*/
Vec2.prototype.normalize = function() {
var mag = this.length();
if ( mag === 0 ) {
throw 'Cannot normalize a vector of zero length';
}
return new Vec2(
this.x / mag,
this.y / mag );
};
/**
* Returns the unsigned angle between this angle and the argument in radians.
* @memberof Vec2
*
* @param {Vec2|Vec3|Vec4|Array} that - The vector to measure the angle from.
*
* @returns {number} The unsigned angle in radians.
*/
Vec2.prototype.unsignedAngle = function( that ) {
var x = that.x !== undefined ? that.x : that[0];
var y = that.y !== undefined ? that.y : that[1];
var angle = Math.atan2( y, x ) - Math.atan2( this.y, this.x );
if (angle < 0) {
angle += 2 * Math.PI;
}
return angle;
};
/**
* Returns a random Vec2 of unit length.
* @memberof Vec2
*
* @returns {Vec2} A random vector of unit length.
*/
Vec2.random = function() {
return new Vec2(
Math.random(),
Math.random() ).normalize();
};
/**
* Returns a string representation of the vector.
* @memberof Vec2
*
* @returns {String} The string representation of the vector.
*/
Vec2.prototype.toString = function() {
return this.x + ', ' + this.y;
};
/**
* Returns an array representation of the vector.
* @memberof Vec2
*
* @returns {Array} The vector as an array.
*/
Vec2.prototype.toArray = function() {
return [ this.x, this.y ];
};
module.exports = Vec2;
}());