package org.newdawn.slick.geom;
import org.newdawn.slick.util.FastTrig;
/**
* A two dimensional vector
*
* @author Kevin Glass
*/
public strictfp class Vector2f {
/** The x component of this vector */
public float x;
/** The y component of this vector */
public float y;
/**
* Create an empty vector
*/
public Vector2f() {
}
/**
* Create a vector based on the contents of a coordinate array
*
* @param coords The coordinates array, index 0 = x, index 1 = y
*/
public Vector2f(float[] coords) {
x = coords[0];
y = coords[1];
}
/**
* Create a new vector based on an angle
*
* @param theta The angle of the vector in degrees
*/
public Vector2f(double theta) {
x = 1;
y = 0;
setTheta(theta);
}
/**
* Calculate the components of the vectors based on a angle
*
* @param theta The angle to calculate the components from (in degrees)
*/
public void setTheta(double theta) {
// Next lines are to prevent numbers like -1.8369701E-16
// when working with negative numbers
if ((theta < -360) || (theta > 360)) {
theta = theta % 360;
}
if (theta < 0) {
theta = 360 + theta;
}
double oldTheta = getTheta();
if ((theta < -360) || (theta > 360)) {
oldTheta = oldTheta % 360;
}
if (theta < 0) {
oldTheta = 360 + oldTheta;
}
float len = length();
x = len * (float) FastTrig.cos(StrictMath.toRadians(theta));
y = len * (float) FastTrig.sin(StrictMath.toRadians(theta));
// x = x / (float) FastTrig.cos(StrictMath.toRadians(oldTheta))
// * (float) FastTrig.cos(StrictMath.toRadians(theta));
// y = x / (float) FastTrig.sin(StrictMath.toRadians(oldTheta))
// * (float) FastTrig.sin(StrictMath.toRadians(theta));
}
/**
* Adjust this vector by a given angle
*
* @param theta
* The angle to adjust the angle by (in degrees)
* @return This vector - useful for chaining operations
*
*/
public Vector2f add(double theta) {
setTheta(getTheta() + theta);
return this;
}
/**
* Adjust this vector by a given angle
*
* @param theta The angle to adjust the angle by (in degrees)
* @return This vector - useful for chaining operations
*/
public Vector2f sub(double theta) {
setTheta(getTheta() - theta);
return this;
}
/**
* Get the angle this vector is at
*
* @return The angle this vector is at (in degrees)
*/
public double getTheta() {
double theta = StrictMath.toDegrees(StrictMath.atan2(y, x));
if ((theta < -360) || (theta > 360)) {
theta = theta % 360;
}
if (theta < 0) {
theta = 360 + theta;
}
return theta;
}
/**
* Get the x component
*
* @return The x component
*/
public float getX() {
return x;
}
/**
* Get the y component
*
* @return The y component
*/
public float getY() {
return y;
}
/**
* Create a new vector based on another
*
* @param other The other vector to copy into this one
*/
public Vector2f(Vector2f other) {
this(other.getX(),other.getY());
}
/**
* Create a new vector
*
* @param x The x component to assign
* @param y The y component to assign
*/
public Vector2f(float x, float y) {
this.x = x;
this.y = y;
}
/**
* Set the value of this vector
*
* @param other The values to set into the vector
*/
public void set(Vector2f other) {
set(other.getX(),other.getY());
}
/**
* Dot this vector against another
*
* @param other The other vector dot agianst
* @return The dot product of the two vectors
*/
public float dot(Vector2f other) {
return (x * other.getX()) + (y * other.getY());
}
/**
* Set the values in this vector
*
* @param x The x component to set
* @param y The y component to set
* @return This vector - useful for chaining operations
*/
public Vector2f set(float x, float y) {
this.x = x;
this.y = y;
return this;
}
/**
* A vector perpendicular to this vector.
*
* @return a vector perpendicular to this vector
*/
public Vector2f getPerpendicular() {
return new Vector2f(-y, x);
}
/**
* Set the values in this vector
*
* @param pt The pair of values to set into the vector
* @return This vector - useful for chaining operations
*/
public Vector2f set(float[] pt) {
return set(pt[0], pt[1]);
}
/**
* Negate this vector
*
* @return A copy of this vector negated
*/
public Vector2f negate() {
return new Vector2f(-x, -y);
}
/**
* Negate this vector without creating a new copy
*
* @return This vector - useful for chaning operations
*/
public Vector2f negateLocal() {
x = -x;
y = -y;
return this;
}
/**
* Add a vector to this vector
*
* @param v The vector to add
* @return This vector - useful for chaning operations
*/
public Vector2f add(Vector2f v)
{
x += v.getX();
y += v.getY();
return this;
}
/**
* Subtract a vector from this vector
*
* @param v The vector subtract
* @return This vector - useful for chaining operations
*/
public Vector2f sub(Vector2f v)
{
x -= v.getX();
y -= v.getY();
return this;
}
/**
* Scale this vector by a value
*
* @param a The value to scale this vector by
* @return This vector - useful for chaining operations
*/
public Vector2f scale(float a)
{
x *= a;
y *= a;
return this;
}
/**
* Normalise the vector
*
* @return This vector - useful for chaning operations
*/
public Vector2f normalise() {
float l = length();
if (l == 0) {
return this;
}
x /= l;
y /= l;
return this;
}
/**
* The normal of the vector
*
* @return A unit vector with the same direction as the vector
*/
public Vector2f getNormal() {
Vector2f cp = copy();
cp.normalise();
return cp;
}
/**
* The length of the vector squared
*
* @return The length of the vector squared
*/
public float lengthSquared() {
return (x * x) + (y * y);
}
/**
* Get the length of this vector
*
* @return The length of this vector
*/
public float length()
{
return (float) Math.sqrt(lengthSquared());
}
/**
* Project this vector onto another
*
* @param b The vector to project onto
* @param result The projected vector
*/
public void projectOntoUnit(Vector2f b, Vector2f result) {
float dp = b.dot(this);
result.x = dp * b.getX();
result.y = dp * b.getY();
}
/**
* Return a copy of this vector
*
* @return The new instance that copies this vector
*/
public Vector2f copy() {
return new Vector2f(x,y);
}
/**
* @see java.lang.Object#toString()
*/
public String toString() {
return "[Vector2f "+x+","+y+" ("+length()+")]";
}
/**
* Get the distance from this point to another
*
* @param other The other point we're measuring to
* @return The distance to the other point
*/
public float distance(Vector2f other) {
return (float) Math.sqrt(distanceSquared(other));
}
/**
* Get the distance from this point to another, squared. This
* can sometimes be used in place of distance and avoids the
* additional sqrt.
*
* @param other The other point we're measuring to
* @return The distance to the other point squared
*/
public float distanceSquared(Vector2f other) {
float dx = other.getX() - getX();
float dy = other.getY() - getY();
return (float) (dx*dx)+(dy*dy);
}
/**
* @see java.lang.Object#hashCode()
*/
public int hashCode() {
return 997 * ((int)x) ^ 991 * ((int)y); //large primes!
}
/**
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object other) {
if (other instanceof Vector2f) {
Vector2f o = ((Vector2f) other);
return (o.x == x) && (o.y == y);
}
return false;
}
}