/**
* Describes a math vector in the cartesian space (2D).
* This is also very useful and may be used to represent
* points.
*
* @param {number=} x The x component
* @param {number=} y The y component
*
* @constructor
*/
Grape2D.Vector = function(x, y) {
/**
* The x component. The default value is 0.
*
* @type {number}
* @private
*/
this.x = x || 0;
/**
* The y component. The default value is 0.
*
* @type {number}
* @private
*/
this.y = y || 0;
};
Grape2D.Vector.prototype = {
constructor: Grape2D.Vector,
/**
* Gets the x component of the vector.
*
* @return {!number} The x component.
* @public
*/
getX: function() {
return this.x;
},
/**
* Sets the x component of the vector.
*
* @param {!number} x The new value.
* @public
*/
setX: function(x) {
this.x = x;
},
/**
* Gets the y component of the vector.
*
* @return {!number} The y component.
* @public
*/
getY: function() {
return this.y;
},
/**
* Sets the y component of the vector.
*
* @param {!number} y The new value.
* @public
*/
setY: function(y) {
this.y = y;
},
/**
* Sets this vector with the same components of another one.
*
* @param {!Grape2D.Vector} vector The vector to copy.
* @return {!Grape2D.Vector} This vector.
* @public
*/
set: function(vector) {
this.x = vector.x;
this.y = vector.y;
return this;
},
/**
* Adds the components of another vector to this.
*
* @param {!Grape2D.Vector} vector The vector to add.
* @return {!Grape2D.Vector} This vector.
* @public
*/
add: function(vector) {
this.x += vector.x;
this.y += vector.y;
return this;
},
/**
* Subtracts the components of another vector to this.
*
* @param {!Grape2D.Vector} vector The vector to subtract.
* @return {!Grape2D.Vector} This vector.
* @public
*/
sub: function(vector) {
this.x -= vector.x;
this.y -= vector.y;
return this;
},
/**
* Multiplies components by a scalar.
*
* @param {!number} scalar The number to multiply.
* @return {!Grape2D.Vector} This vector.
* @public
*/
multiplyByScalar: function(scalar) {
this.x *= scalar;
this.y *= scalar;
return this;
},
/**
* Divides components by a scalar.
*
* @param {!number} scalar The number to divide.
* @return {!Grape2D.Vector} This vector.
* @public
*/
divideByScalar: function(scalar) {
this.x /= scalar;
this.y /= scalar;
return this;
},
/**
* Inverts the components of the vector. It's the same as
* multiply by -1.
*
* @return {!Grape2D.Vector} This vector.
* @public
*/
negate: function() {
return this.multiplyByScalar(-1);
},
/**
* Normalizes the vector. So that each component have a value
* between 0 and 1.
*
* @return {!Grape2D.Vector} This vector.
* @public
*/
normalize: function() {
return this.divideByScalar(this.getMagnitude());
},
/**
* Gets the magnitude (length) of a vector.
*
* @return {!number} The magnitude of the vector.
* @public
*/
getMagnitude: function() {
return Grape2D.Math.sqrt(this.x * this.x + this.y * this.y);
},
/**
* {@see Grape2D.Vector.getMagnitude}
* @public
*/
length: function() {
return this.getMagnitude();
},
/**
* Gets the length of the vector, before the calculation of its
* square root.
*
* @return {!number} The length squared.
* @public
*/
lengthSquared: function() {
return this.x * this.x + this.y * this.y;
},
/**
* Gets the angle that the vector makes with the x axis.
*
* @return {!number} The angle.
* @public
*/
getAngle: function() {
var angle = 1;
if (this.y < 0) {
angle = -1;
}
return Math.acos(this.x / this.length()) * angle;
},
/**
* Gets the dot product of this and another vector.
*
* @param {!Grape2D.Vector} vector Another vector.
* @return {!number} The dot product.
* @public
*/
dot: function(vector) {
return this.x * vector.x + this.y * vector.y;
},
/**
* Projects this vector into other. This operation
* don't changes the values of the objects.
*
* @param {!Grape2D.Vector} vector The vector to project onto.
* @return {!Grape2D.Vector} The vector resulting from the
* projection.
* @public
*/
project: function(vector) {
var dp = this.dot(vector),
proj = new Grape2D.Vector();
proj.x = dp * vector.x;
proj.y = dp * vector.y;
return proj;
},
/**
* Calculates the right normal of the vector.
*
* @return {!Grape2D.Vector} The right normal vector.
* @public
*/
rightNormal: function() {
return new Grape2D.Vector(-this.y, this.x);
},
/**
* Checks if two vectors are parallel.
*
* @param {!Grape2D.Vector} vector vector to check.
* @return {!boolean} true if the vector is parallel to
* this one, false otherwise.
* @public
*/
isParallelTo: function(vector) {
return Grape2D.Math.abs(vector.x) == Grape2D.Math.abs(this.x) && Grape2D.Math.abs(vector.y) == Grape2D.Math.abs(this.y);
},
/**
* Calculates the distance between this and another vector
*
* @param {!Grape2D.Vector} vector The other vector.
* @return {!number} The distance.
* @public
*/
distanceTo: function(vector) {
return Grape2D.Math.sqrt(Grape2D.Math.sq(vector.x - this.x) + Grape2D.Math.sq(vector.y - this.y));
},
/**
* Calculates the squared distace between this and another vector.
*
* @param {!Grape2D.Vector} vector The other vector.
* @return {!number} The distance squared.
* @public
*/
sqDistanceTo: function(vector) {
return vector.x * this.x + vector.y * this.y;
},
/**
* Positive distance between the x coordinates this vector an
* another one.
*
* @param {!Grape2D.Vector} vector A vector.
* @return {!number} Positive distance of the x coordinate.
* @public
*/
xDistanceTo: function(vector) {
if (this.x > vector.x) {
return Grape2D.Math.abs(this.x - vector.x);
} else {
return Grape2D.Math.abs(vector.x - this.x);
}
},
/**
* Positive distance between the y coordinates this vector an
* another one.
*
* @param {!Grape2D.Vector} vector A vector.
* @return {!number} Positive distance of the y coordinate.
* @public
*/
yDistanceTo: function(vector) {
if (this.y > vector.y) {
return Grape2D.Math.abs(this.y - vector.y);
} else {
return Grape2D.Math.abs(vector.y - this.y);
}
},
/**
* Checks if the components of one vector are equal to the
* components to another one.
*
* @param {!Grape2D.Vector} vector The other vector.
* @return {!boolean} True if they're components are not equal.
* @public
*/
equals: function(vector) {
return this.x == vector.x && this.y == vector.y;
},
/**
* Creates a new vector with the same components.
*
* @return {!Grape2D.Vector} a new vector with the same components
* as this one.
* @public
*/
clone: function() {
return new Grape2D.Vector(this.x, this.y);
},
/**
* Creates a string for this class.
*
* @return {!string} A string representing this class.
* @public
*/
toString: function() {
return "Grape2D.Vector (" + this.x + "," + this.y + ")";
},
/**
* Applies the result of a given function, where the component is
* an argument, to the respective component. This can be useful
* to minimize code or just simplify it. As an example, <code>
* someVector.use(Grape.Math.sqrt)</code>
*
* @param {!Function} fn A function that receives a number and
* returns a number.
* @return {!Grape2D.Vector} This vector.
* @public
*/
use: function(fn) {
this.x = fn(this.x);
this.y = fn(this.y);
return this;
},
/**
* Resets the vector coordinates to 0.
*
* @return {!Grape2D.Vector} This vector.
* @public
*/
reset: function() {
this.x = 0;
this.y = 0;
return this;
},
/**
* Gets the type of the object. This is used by the collision
* dispatcher.
*
* @return {!string} Type.
*/
getStaticType: function() {
return Grape2D.Vector.STATIC_TYPE;
},
/**
* Gets if both x and y coordinates are zero.
*
* @return {!boolean} True if the coordinates are zero.
* @public
*/
isZero: function() {
return this.x == 0 && this.y == 0;
}
};
/**
* Creates a vector from two points (points are represented as vectors).
*
* @param {!Grape2D.Vector} a One point.
* @param {!Grape2D.Vector} b Another point.
* @return {!Grape2D.Vector} Vector with direction from a to b.
* @public
* @static
*/
Grape2D.Vector.createFromPoints = function(a, b) {
return new Grape2D.Vector(b.x - a.x, b.y - a.y);
};
/**
* Creates a vector from an angle and magnitude.
*
* @param {!number} angle angle of the vector against the x axis.
* @param {!number} magnitude magnitude (length) of the vector.
* @return {!Grape2D.Vector} vector with the given angle and magnitude.
* @public
* @static
*/
Grape2D.Vector.createFromAngle = function(angle, magnitude) {
return new Grape2D.Vector(magnitude * Grape2D.Math.cos(angle), magnitude * Grape2D.Math.sin(angle));
};
/**
* Linear interpolation between two vectors.
*
* @param {!Grape2D.Vector} start Start interpolation position.
* @param {!Grape2D.Vector} end End interpolation position.
* @param {!number} prc Percentage of the interpolation.
* @return {!Grape2D.Vector} Interpolated vector.
* @public
*/
Grape2D.Vector.lerp = function(start, end, prc) {
return start.clone().add(end.clone().sub(start).multiplyByScalar(prc));
};
/**
* Type as a string.
*
* @type {!string}
* @static
* @private
*/
Grape2D.Vector.STATIC_TYPE = "Vector";