|
MathWorx | |||||||
PREV NEXT | FRAMES NO FRAMES |
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.dimension()) { 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 | |||||||
PREV NEXT | FRAMES NO FRAMES |