MathWorx

Vector.js

Summary

This file defines the Vector class, instance methods, and static objects/methods. It has no dependencies but is automatically included with Matrix.js.


Class Summary
Vector  

/**MathWorx Copyright (c) 2008 Shane Steinert-Threlkeld
Dual-licensed under the MIT and GNU GPL Licenses.
For more information, see LICENSE file */

/** @fileoverview This file defines the Vector class, instance methods, and static objects/methods.  It has no dependencies but is automatically included with Matrix.js. */

/**Constructor function.  Takes an Array or a Vector and creates a Vector object.
@param {Object} elements Array to become the components of the Vector; if a Vector, will clone the vector into a new one
@constructor */
function Vector(elements) {
	/**the components of the Vector 
	@type Array */
	this.components = new Array();
	if(elements instanceof Array) {
		this.components = elements;
	} 
	//allows easy cloning of a vector
	if(elements instanceof Vector) {
		//slice so that changes to new vector do not affect old one
		this.components = elements.components.slice();
	}
	/**the dimension of the array (length of components array) 
	@type Integer */
	this.n = this.components.length;
}

Vector.prototype = {

	/**Gets the component of the vector at index.
	@param {Integer} index the index for which you want the component
	@return {Number} the index'th component of the vector */
	get: function(index) {
		return (index < 1 || index > this.components.length) ? null : this.components[index - 1];
	},

	/**Maps the vector to a new vector by the supplied function.
	@param {Function} func the mapping function
	@return {Vector} the new vector generated by the map */
	map: function(func) {
		var elements = new Array();
		if(typeof func == 'function') {
			this.toEach(function(x, i, k) {
				elements.push(func(x, i, k));
			});
			return new Vector(elements);
		} else {
			return null;
		}
	},

	/**Performs a supplied function on every element of the vector.
	@param {Function} func the function to perform on each element*/
	toEach: function(func) {
		for(i = 0; i < this.n; i++) {
			if(typeof k == 'undefined') {
				func(this.components[i], i, 0);
			} else {
				func(this.components[i], i, k);
			}
		}
	},

	/**Tests to see if two vectors are equal to each other.
	@param {Vector} vec - the vector to compare to
	@return {Boolean} true iff vectors are equal (all components are equal and have same dimension), false otherwise*/
	equalTo: function(vec) {
		if(this.n != vec.n) {
			return false;
		}
		for(i = 0; i < this.n; i++) {
			if(Math.abs(this.components[i] - vec.components[i]) > Zero) {
				return false;
			}
		}
		return true;
	},

	/**Normalizes the vector and returns the new unit vector.
	@return {Vector} a new vector that is the normalized version of the original vector */
	normalize: function() {
		var length = this.getLength();
		if(length == 0) {
			return new Vector(this);
		}
		return this.map(function(x) {
				return x / length;
		});
	},

	/**Tests to see if 2 vectors are linearly independent from each other.
	@param {Vector} vec the vector to test for independence 
	@return {Boolean} true iff vectors are independent, false otherwise (null if vectors not of same size) */
	linearlyIndependent: function(vec) {
		if(this.n != vec.n) {
			return null;
		}
		V = this.map(function(x, i) { return vec.components[i] / x });
		for(i = 1; i < this.n; i++) {
			if(V.get(i) != V.get(i+1)) {
				return true;
			}
		}
		return false;
	},

	/**Tests to see if 2 vectors are linearly dependent.
	@param {Vector} vec the vector to compare with
	@return {Boolean} true iff vectors are dependent, false otherwise */
	linearlyDependent: function(vec) {
		return !(this.linearlyIndependent(vec));
	},

	/**Adds a vector to the supplied vector.
	@param {Vector} vec the vector to be added.
	@return {Vector} a new vector that is the sum of the original and supplied.*/
	add: function(vec) {
		if(vec.dimension()) {
			if(this.dimension() == vec.dimension()) {
				return this.map(function(x, i) { return x + vec.components[i]; });
			} else {
				return null;
			}
		} else {
			return null;
		}
	},

	/**Subtracts a vector to the supplied vector.
	@param {Vector} vec the vector to be subtracted.
	@return {Vector} a new vector that is the result of the subtraction.*/
	subtract: function(vec) {
		if(vec.dimension()) {
			if(this.dimension() == vec.dimension()) {
				return this.map(function(x, i) { return x - vec.components[i]; });
			} else {
				return null;
			}
		} else {
			return null;
		}
	},

	/**Rounds all the elements of the vector and returns the copy.
	@return {Vector} a copy of the original vector, but rounded */
	round: function() {
		return this.map(function(x) {
			return Math.round(x);
		});
	},

	/**Multiplies a vector by a scalar k.
	@param {Number} k the scalar by which to multiply the vector
	@return {Vector} a new vector that is the scalar multiplicaiton */
	multiplyBy: function(k) {
		return this.map(function(x) {
			return x*k;
		});
	},

	/**Returns the scalar dot product of this vector and the supplied vector.
	@param {Vector} vec the vector with which to compute the dot product
	@return {Number} null if vector is not a vector or is a different dimension, the dot product of the two vectors otherwise.
	*/
	dot: function(vec) {
		var dotProduct = 0;
		if(vec.dimension()) {
			if(this.n == vec.n) {
				for(i = 0; i < this.n; i++) {
					dotProduct += this.components[i]*vec.components[i];
				}
				return dotProduct;
			} else {
				return null;
			}
		} else {
			return null;
		}
	},

	/**Computes the cross product of two 3-dimensional vectors.
	@param {Vector} vec the vector with which to take the cross product
	@return {Vector} a new vector that is the cross product; null if either of the vectors is not 3-dimensional */
	cross: function(vec) {
		if(this.n == 3 && vec.n == 3) {
			var a = this.components;
			var b = vec.components;
			return new Vector([
				a[1]*b[2] - a[2]*b[1],
				a[2]*b[0] - a[0]*b[2],
				a[0]*b[1] - a[1]*b[0]
			]);
		} else {
			return null;
		}
	},

	/**Projects one Vector onto another.  Gives the component of this Vector in the supplied Vector's direction.
	@param {Vector} vec (or point2D/3D object) the vector onto which to project this vector
	@return {Vector} (or point2D/3D object) a new  Vector, the original projected onto vec */
	resolute: function(vec) {
		if(vec.dimension()) {
			var direction = vec.normalize();
			return direction.multiplyBy(this.dot(direction));
		} else {
			return null;
		}
	},

	/**Reflects the Vector or point2D/3D in the given point, line, or plane
	@param {Object} obj the Line, Plane, or Vector/point2D/3D in which to reflect this
	@return {Object} a new Vector or point3D (depends on which calls this function) that is reflected */
	reflectionIn: function(obj) {
		if(obj.base) { //obj is a Line or Plane
			var point = new point3D(this.get(1),this.get(2),(this.get(3) || 0));
			var closest = obj.pointClosestTo(point);
			var vec = closest.add(closest.subtract(point));
			if(this instanceof point3D) {
				return new point3D(vec.get(1), vec.get(2), vec.get(3));
			} else if (this instanceof Vector) {
				return new Vector(vec);
			}
		} else { //handles point2D/3D or Vector
			if(this.n != obj.n) {
				return null;
			}
			return this.map(function(x, i) { return obj.get(i+1) + (obj.get(i+1) - x); });
		}
	},

	/**Returns a negative copy of the Vector (or point).
	@return {Object} a new, negative copy of the original Vector or point2D/3D */
	negative: function() {
		return this.map(function(x) { return -x; });
	},

	/**Converts a Vector into a 1-column matrix.
	@return {Matrix} the column Matrix representation of the Vector */
	toColumnMatrix: function() {
		var els = new Array();
		for(i = 1; i <= this.n; i++) {
			els[i-1] = new Array();
			els[i-1][0] = this.get(i);
		}
		return new Matrix(els);
	},

	/**Converts a Vector into a 1-row matrix.
	@return {Matrix} the row Matrix representation of the Vector */
	toRowMatrix: function() {
		var els = new Array();
		els[0] = this.components;
		return new Matrix(els);
	},

	/**Returns the length of the vector by modulus definition.
	@return {Number} the length of the vector*/
	getLength: function() {
		return Math.sqrt(this.dot(this));
	},

	/**Finds and returns the angle between two vectors.
	@param {Vector} vec the vector from which to find the angle
	@return {Number} the angle (in radians) between the two vectors */
	angleBetween: function(vec) {
		if(this.dimension() == vec.dimension()) {
			var len1 = this.getLength(), len2 = vec.getLength();
			if(len1 * len2 == 0) {
				return null;
			}
			var theta = this.dot(vec) / (len1*len2);
			if(theta < -1) {
				theta = -1;
			}
			if(theta > 1) {
				theta = 1;
			}
			return Math.acos(theta);
		} else {
			return null;
		}
	},

	/**Tests if two vectors are parallel.
	@param {Vector} vec the vector to compare 
	@return {Boolean} true iff vectors are parallel, false or null otherwise */
	isParallel: function(vec) {
		var angle = this.angleBetween(vec);
		return (angle == null) ? null : (angle <= Zero);
	},

	/**Tests if two vectors are antiparallel.
	@param {Vector} vec the vector to compare 
	@return {Boolean} true iff vectors are antiparallel, false or null otherwise */
	isAntiParallel: function(vec) {
		var angle = this.angleBetween(vec);
		return (angle == null) ? null : (Math.abs(angle - Math.PI) <= Zero);
	},

	/**Tests if two vectors are perpendicular.
	@param {Vector} vec - the vector to compare 
	@return {Boolean} true iff vectors are perpendicular, false or null otherwise */
	isPerpendicular: function(vec) {
		var dotProduct = this.dot(vec);
		return (dotProduct == null) ? null : (Math.abs(dotProduct) <= Zero);
	},

	/**Returns the distance between the vector and an object, as if the vector were a point in its n-space.
	@param {Object} obj the object from which to get the distance
	@return {Number} the distance between the vector and the object */
	distanceFrom: function(obj) {
		//throw in this if for when other objects (line, plane, etc) exist
		if(obj.dimension()) {
			if(this.dimension() == obj.dimension()) {
				var sum = 0, residual;
				this.toEach(function(x, i) {
					residual = x - obj.components[i];
					sum += Math.pow(residual,2);
				});
				return Math.sqrt(sum);
			} else {
				return null;
			}
		} else {
			return null;
		}
	},

	/**Sets and/or returns the dimension of the vector.
	@param {Integer} n (optional) the dimension to set the array.  If n > current dimension, 0s added as all new components; if n < current dimension, all components greater than that dimension are deleted.
	@return {Integer} the dimension of the vector. */
	dimension: function(n) {
		if(n) {
			if(n > this.n) {
				for(i = this.components.length; i < n; i++) {
					this.components.push(0);
				}
			} else {
				this.components.splice((this.n - n) - 1, (this.n - n));
			}
			this.n = n;
		}
		return this.components.length;
	},

	/**Makes a copy of the given vector in 3 dimensions.
	@return {Vector} a new vector that is 3-D, with components decided according to the dimension() method (i.e. 0 if n<3, removed if n > 3)
	@see #dimension */
	make3D: function() {
		var newVec = new Vector(this);
		newVec.dimension(3);
		return newVec;
	},
	
	/**Sets all values within range of Zero (set in easyload.js) to val.
	 * @param {Number} val the number to snap the vector to */
	snapTo: function(val) {
		return this.map(function(x) {
			return (Math.abs(x - val) <= Zero) ? val : x;
		});
	},

	/**Returns the first occurence of x in the vector.
	@param {Number} x the element to search for
	@return {Number} the index of the first occurence of element x; null if never occurs */
	indexOf: function(x) {
		var index = null;
		for(i = 0; i < this.n; i++) {
			if(index == null && this.components[i] == x) {
				index = i + 1;
			}
		}
		return index;
	},

	/**Finds and returns the element with the largest absolute value.
	@return {Number} the absolute largest element */
	max: function() {
		var maximum = 0;
		for(i = 0; i < this.n; i++) {
			if(Math.abs(this.components[i]) > Math.abs(maximum)) {
				maximum = this.components[i];
			}
		}
		return maximum;
	},

	/**Method for setting and getting the elements of a vector.
	@param {Array} els (Optional) if supplied, will set the vector's elements to els.
	@return {Array} the elements of the vector (an array) */
	elements: function(els) {
		if(els) {
			this.components = els;
			this.n = this.components.length;
		}
		return this.components;
	},

	/**Adds a new element to the vector and updates the dimension.
	@param {Number} el the number to add to the vector
	 */
	addElement: function(el) {
		this.components.push(el);
		this.n++;
	},

	/**Converts a Vector to a point object of appropriate dimension in homogeneous coordinates.  If called from a point2D or point3D object, acts as another way to clone the point.
	@return {Object} either a point2D or point3D object, depending on size of Vector, with same  coordinates as the Vector's components */
	toPoint: function() {
		if(this.n == 2) {
			return new point2D(this.get(1),this.get(2));
		} else if(this.n == 3) {
			return new point3D(this.get(1),this.get(2),this.get(3));
		} else if(this.n == 4) {
			return new point3D(this.get(1),this.get(2),this.get(3));
		} else {
			return null;
		}
	},

	/**Returns a string representation of the vector.
	@return {String} the string representatoin of the vector.*/
	toString: function() {
		return "[" + this.components.join(" ") + "]";
	}

} //end Vector prototype

/**Creates and returns a new vector with n random elements less than or equal to max.
@param {Integer} n the number of components the vector should be
@param {Number} max (Optional) the maximum value the elements can be; if not specified, values will be in rand [0,1) 
@return {Vector} a new vector with random components */
Vector.random = function(n, max) {
	var elements = new Array();
	for(i = 0; i < n; i++) {
		if(max) {
			elements[i] = Math.floor(Math.random()*(max+1));
		} else {
			elements[i] = Math.random();
		}
	}
	return new Vector(elements);
}

/**Creates and returns  a new vector of dimension n with all 0 components.
@param {Integer} n the dimension of the new zero vector
@return {Vector} the zero vector of dimension n */
Vector.zero = function(n) {
	var elements = new Array();
	for(i = 0; i < n; i++) {
		elements[i] = 0;
	}
	return new Vector(elements);
}

//The three standard unit vectors in 3 dimensions
/**The unit vector [1,0,0]
@type Vector
@final */
Vector.i = new Vector([1,0,0]);
/**The unit vector [0,1,0]
@type Vector
@final */
Vector.j = new Vector([0,1,0]);
/**The unit vector [0,0,1]
@type Vector
@final */
Vector.k = new Vector([0,0,1]);

MathWorx

Documentation generated by JSDoc on Mon Aug 11 13:58:31 2008