src/main/java/math/Vector2f.java
package math;
/**
* Representation of 2D vectors and points.
*
* @author Simon
* @version 0.3, 11 June 2016
*/
public class Vector2f {
/** Shorthand for writing Vector2f(0, -1). */
public static final Vector2f DOWN = new Vector2f(0, -1);
/** Shorthand for writing Vector2f(-1, 0). */
public static final Vector2f LEFT = new Vector2f(-1, 0);
/** Shorthand for writing Vector2f(1, 0). */
public static final Vector2f RIGHT = new Vector2f(1, 0);
/** Shorthand for writing Vector2f(0, 1). */
public static final Vector2f UP = new Vector2f(0, 1);
/** Shorthand for writing Vector2f(1, 1). */
public static final Vector2f ONE = new Vector2f(1, 1);
/** Shorthand for writing Vector2f(0, 0). */
public static final Vector2f ZERO = new Vector2f(0, 0);
/** Shorthand for writing Vector2f(Float.MIN_VALUE, Float.MIN_VALUE). */
public static final Vector2f MIN = new Vector2f(Float.MIN_VALUE, Float.MIN_VALUE);
/** Shorthand for writing Vector2f(Float.MAX_VALUE, Float.MAX_VALUE). */
public static final Vector2f MAX = new Vector2f(Float.MAX_VALUE, Float.MAX_VALUE);
/** Shorthand for writing Vector2f(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY). */
public static final Vector2f POSITIVE_INFINITY =
new Vector2f(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY);
/** Shorthand for writing Vector2f(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY). */
public static final Vector2f NEGATIVE_INFINITY =
new Vector2f(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY);
/** The x component of the vector. */
public float x;
/** The y component of the vector. */
public float y;
/**
* Constructs a new instance of this {@link Vector2f} with x and y set to 0. Equivalent to
* Vector2f(0, 0).
*/
public Vector2f() {
x = y = 0;
}
/**
* Constructs a new instance of the {@link Vector2f} with the given initial x and y values.
*
* @param x the x value of this {@link Vector2f}
* @param y the y value of this {@link Vector2f}
*/
public Vector2f(float x, float y) {
this.x = x;
this.y = y;
}
/**
* Constructs a new instance of this {@link Vector2f} that contains the passed vector's
* information.
*
* @param v the vector to copy
*/
public Vector2f(Vector2f v) {
this.x = v.x;
this.y = v.y;
}
/**
* Returns a new {@link Vector2f} containing the absolute x,y values of this vector. The values of
* this vector remain untouched.
*
* @return the newly created vector
*/
public Vector2f abs() {
return new Vector2f(Mathf.abs(x), Mathf.abs(y));
}
/**
* Sets the x,y components of this vector to their absolute values internally.
*
* @return this
*/
public Vector2f absLocal() {
this.x = Mathf.abs(x);
this.y = Mathf.abs(y);
return this;
}
/**
* Returns a resultant vector that is made from the smallest components of this vector and the
* provided vector v. If the provided vector is null, null is returned. The values of this vector
* remain untouched.
*
* @param v the provided vector v
* @return the resultant vector or null if the provided vector is null
*/
public Vector2f min(Vector2f v) {
if (v == null) {
return null;
}
return new Vector2f(Mathf.min(x, v.x), Mathf.min(y, v.y));
}
/**
* Returns a resultant vector that is made from the largest components of this vector and the
* provided vector v. If the provided vector is null, null is returned. The values of this vector
* remain untouched.
*
* @param v the provided vector v
* @return the resultant vector or null if the provided vector is null
*/
public Vector2f max(Vector2f v) {
if (v == null) {
return null;
}
return new Vector2f(Mathf.max(x, v.x), Mathf.max(y, v.y));
}
/**
* Clamps the x,y components of this vector between 0 and 1 creating a resultant vector which is
* returned. The values of this vector remain untouched.
*
* @return the resultant vector
*/
public Vector2f clamp01() {
return new Vector2f(Mathf.clamp01(x), Mathf.clamp01(y));
}
/**
* Clamps the x,y components of this vector between 0 and 1 internally, and returns a handle to
* this vector for easy chaining of calls.
*
* @return this
*/
public Vector2f clamp01Local() {
x = Mathf.clamp01(x);
y = Mathf.clamp01(y);
return this;
}
/**
* Clamps the x,y components of this vector between min and max creating a resultant vector which
* is returned. The values of this vector remain untouched.
*
* @param min the minimum value for x and y
* @param max the maximum value for x and y
* @return the resultant vector
*/
public Vector2f clamp(float min, float max) {
return new Vector2f(Mathf.clamp(x, min, max), Mathf.clamp(y, min, max));
}
/**
* Clamps the x,y components of this vector between min and max internally, and returns a handle
* to this vector for easy chaining of calls.
*
* @param min the minimum value for x and y
* @param max the maximum value for x and y
* @return this
*/
public Vector2f clampLocal(float min, float max) {
x = Mathf.clamp(x, min, max);
y = Mathf.clamp(y, min, max);
return this;
}
/**
* Clamps the x,y components of this vector between the given values creating a resultant vector
* which is returned. The values of this vector remain untouched.
*
* @param minX the minimum value for x
* @param minY the minimum value for y
* @param maxX the maximum value for x
* @param maxY the maximum value for y
* @return the resultant vector
*/
public Vector2f clamp(float minX, float minY, float maxX, float maxY) {
return new Vector2f(Mathf.clamp(x, minX, maxX), Mathf.clamp(y, minY, maxY));
}
/**
* Clamps the x,y components of this vector between the given values internally, and returns a
* handle to this vector for easy chaining of calls.
*
* @param minX the minimum value for x
* @param minY the minimum value for y
* @param maxX the maximum value for x
* @param maxY the maximum value for y
* @return this
*/
public Vector2f clampLocal(float minX, float minY, float maxX, float maxY) {
x = Mathf.clamp(x, minX, maxX);
y = Mathf.clamp(y, minY, maxY);
return this;
}
/**
* Converts the given angle (in radians) to this vector.
*
* @param angrad the angle to convert this vector into
* @return this
*/
public Vector2f setToAngleRadLocal(float angrad) {
this.x = Mathf.cos(angrad);
this.y = Mathf.sin(angrad);
return this;
}
/**
* Converts the given angle (in degrees) to this vector.
*
* @param angdeg the angle to convert this vector into
* @return this
*/
public Vector2f setToAngleDegLocal(float angdeg) {
this.x = Mathf.cos(Mathf.toRadians(angdeg));
this.y = Mathf.sin(Mathf.toRadians(angdeg));
return this;
}
/**
* Set the components of this vector to the values provided by the float array (values[0] = x,
* values[1] = y).
*
* @param values the values to copy from
* @return this
* @throws IndexOutOfBoundsException if values.length < 0 || values.length < 2
*/
public Vector2f set(float[] values) {
return set(values[0], values[1]);
}
/**
* Sets the x,y components of this vector to the given values.
*
* @param x the x component of the vector
* @param y the y component of the vector
* @return this
*/
public Vector2f set(float x, float y) {
this.x = x;
this.y = y;
return this;
}
/**
* Sets the x,y components of this vector to the values provided by the given vector v.
*
* @param v the vector to copy from
* @return this
*/
public Vector2f set(Vector2f v) {
this.x = v.x;
this.y = v.y;
return this;
}
/**
* Adds the provided vector v to this vector creating a resultant vector which is returned. The
* values of this vector remain untouched. If the provided vector is null, null is returned.
*
* @param v the vector to add to this vector
* @return the resultant vector
*/
public Vector2f add(Vector2f v) {
if (null == v) {
return null;
}
return new Vector2f(x + v.x, y + v.y);
}
/**
* Adds the provided vector v to this vector internally, and returns a handle to this vector for
* easy chaining of calls. If the provided vector is null, null is returned.
*
* @param v the vector to add to this vector
* @return this
*/
public Vector2f addLocal(Vector2f v) {
if (null == v) {
return null;
}
x += v.x;
y += v.y;
return this;
}
/**
* Adds the provided values to this vector internally, and returns a handle to this vector for
* easy chaining of calls.
*
* @param x value to add to x
* @param y value to add to y
* @return this
*/
public Vector2f addLocal(float x, float y) {
this.x += x;
this.y += y;
return this;
}
/**
* Adds this vector to the given vector v and stores the result in the provided result vector. The
* values of this vector remain untouched. If the provided vector v is null, null is returned. If
* the provided result vector is null a new vector is created to store the result in.
*
* @param v the vector to add
* @param result the vector to store the result in
* @return the result vector, after adding
*/
public Vector2f add(Vector2f v, Vector2f result) {
if (null == v) {
return null;
}
if (result == null) result = new Vector2f();
result.x = x + v.x;
result.y = y + v.y;
return result;
}
public Vector2f add(float x, float y) {
return new Vector2f(this.x + x, this.y + y);
}
/**
* Calculates the dot product of this vector and the provided vector v. If the provided vector is
* null, 0 is returned.
*
* @param v the vector to dot with this vector
* @return the resultant dot product of this vector and a given vector
*/
public float dot(Vector2f v) {
if (null == v) {
return 0;
}
return x * v.x + y * v.y;
}
/**
* Calculates the cross product of this vector with a parameter vector v.
*
* @param v the vector to take the cross product of with this
* @return the cross product vector.
*/
public Vector3f cross(Vector2f v) {
return new Vector3f(0, 0, determinant(v));
}
/**
* Calculates the determinant of this vector and the given vector v.
*
* @param v the given vector v
* @return the resulting determinant
*/
public float determinant(Vector2f v) {
return (x * v.y) - (y * v.x);
}
/**
* Sets this vector to the interpolation by changeAmnt from this to the finalVec
* this=(1-changeAmnt)*this + changeAmnt * finalVec
*
* @param finalVec the final vector to interpolate towards
* @param changeAmnt an amount between 0.0 - 1.0 representing a percentage change from this
* towards finalVec
*/
public Vector2f interpolateLocal(Vector2f finalVec, float changeAmnt) {
this.x = (1 - changeAmnt) * this.x + changeAmnt * finalVec.x;
this.y = (1 - changeAmnt) * this.y + changeAmnt * finalVec.y;
return this;
}
/**
* Sets this vector to the interpolation by changeAmnt from beginVec to finalVec
* this=(1-changeAmnt)*beginVec + changeAmnt * finalVec
*
* @param beginVec the beginning vector (delta=0)
* @param finalVec the final vector to interpolate towards (delta=1)
* @param changeAmnt an amount between 0.0 - 1.0 representing a percentage change from beginVec
* towards finalVec
*/
public Vector2f interpolateLocal(Vector2f beginVec, Vector2f finalVec, float changeAmnt) {
this.x = (1 - changeAmnt) * beginVec.x + changeAmnt * finalVec.x;
this.y = (1 - changeAmnt) * beginVec.y + changeAmnt * finalVec.y;
return this;
}
/**
* Checks if the given vector v is valid. A vector is not valid if it is null or its floats are
* NaN or infinite, return false. Else return true.
*
* @param v the vector to check
* @return true or false as stated above
*/
public static boolean isValidVector(Vector2f v) {
if (v == null) return false;
if (Float.isNaN(v.x) || Float.isNaN(v.y)) return false;
if (Float.isInfinite(v.x) || Float.isInfinite(v.y)) return false;
return true;
}
/**
* Calculates the magnitude of this vector.
*
* @return the length (magnitude) of this vector
*/
public float length() {
return Mathf.sqrt(lengthSquared());
}
/**
* Calculates the squared value of the magnitude of this vector.
*
* @return the magnitude squared of this vector
*/
public float lengthSquared() {
return x * x + y * y;
}
/**
* Performs a linear interpolation between this vector and another.
*
* <p>Linear interpolation calculates a new vector that is a portion of the way between two given
* vectors. The parameter `t` determines how far along this line the new vector will be.
*
* <p>Mathematically, the interpolation is calculated as follows: result = this + t * (other -
* this)
*
* <p>Where: - `this` is the current vector - `other` is the target vector - `t` is the
* interpolation factor (between 0 and 1)
*
* @param other The vector to interpolate towards.
* @param t The interpolation factor. A value of 0 returns this vector, a value of 1 returns the
* other vector, and values between 0 and 1 return a vector between the two.
* @return A new vector representing the interpolated result.
*/
public Vector2f lerp(Vector2f other, float t) {
return new Vector2f(this.x + t * (other.x - this.x), this.y + t * (other.y - this.y));
}
/**
* Calculates the distance squared between this vector and the given vector v.
*
* @param v the second vector to determine the distance squared
* @return the distance squared between the two vectors
*/
public float distanceSquared(Vector2f v) {
float dx = x - v.x;
float dy = y - v.y;
return dx * dx + dy * dy;
}
/**
* Calculates the distance squared between this vector and the given vector v.
*
* @param x the x coordinate of the v vector
* @param y the y coordinate of the v vector
* @return the distance squared between the two vectors
*/
public float distanceSquared(float x, float y) {
float dx = this.x - x;
float dy = this.y - y;
return dx * dx + dy * dy;
}
/**
* Calculates the distance between this vector and vector v.
*
* @param v the second vector to determine the distance
* @return the distance between the two vectors
*/
public float distance(Vector2f v) {
return Mathf.sqrt(distanceSquared(v));
}
/**
* Multiplies this vector by a scalar and resultant vector is returned. The values of this vector
* remain untouched.
*
* @param scalar the value to multiply this vector by
* @return the resultant vector
*/
public Vector2f mult(float scalar) {
return new Vector2f(x * scalar, y * scalar);
}
/**
* Project this vector onto the given vector b. If the provided vector v is null, null is
* returned. If the provided result vector is null a new vector is created to store the result in.
*
* @param v the vector to project onto
* @param result the projected vector
* @param result
*/
public Vector2f projectOntoUnit(Vector2f v, Vector2f result) {
if (v == null) {
return null;
}
if (result == null) result = new Vector2f();
float dot = v.dot(this);
result.x = dot * v.getX();
result.y = dot * v.getY();
return result;
}
/**
* Multiplies this vector by a scalar internally, and returns a handle to this vector for easy
* chaining of calls.
*
* @param scalar the value to multiply this vector by
* @return this
*/
public Vector2f multLocal(float scalar) {
x *= scalar;
y *= scalar;
return this;
}
/**
* Multiplies a provided vector to this vector internally, and returns a handle to this vector for
* easy chaining of calls. If the provided vector is null, null is returned.
*
* @param v the vector to multiply with this vector
* @return this
*/
public Vector2f multLocal(Vector2f v) {
if (null == v) {
return null;
}
x *= v.x;
y *= v.y;
return this;
}
public Vector2f mult(Vector2f v) {
if (null == v) {
return null;
}
return new Vector2f(x * v.x, y * v.y);
}
/**
* Multiplies the x and y of this vector by the scalar and stores the result in product. The
* values of this vector remain untouched. The result is returned for chaining.
*
* @param scalar the scalar to multiply by
* @param product the vector to store the result in
* @return product, after multiplication.
*/
public Vector2f mult(float scalar, Vector2f product) {
if (null == product) {
product = new Vector2f();
}
product.x = x * scalar;
product.y = y * scalar;
return product;
}
/**
* Divides the values of this vector by a scalar and returns the result. The values of this vector
* remain untouched. Dividing by zero will result in an exception.
*
* @param scalar the value to divide this vectors attributes by
* @return the result vector
*/
public Vector2f divide(float scalar) {
return new Vector2f(x / scalar, y / scalar);
}
/**
* Divides this vector by a scalar internally, and returns a handle to this vector for easy
* chaining of calls. Dividing by zero will result in an exception.
*
* @param scalar the value to divide this vector by
* @return this
*/
public Vector2f divideLocal(float scalar) {
x /= scalar;
y /= scalar;
return this;
}
/**
* Divides each component of this vector by the corresponding component of the given vector v
* internally.
*
* @param v the vector providing the two divisors
* @return this
*/
public Vector2f divideLocal(Vector2f v) {
x /= v.x;
y /= v.y;
return this;
}
/**
* Returns the negative of this vector. All values are negated and set to a new vector. The values
* of this vector remain untouched.
*
* @return the negated vector
*/
public Vector2f negate() {
return new Vector2f(-x, -y);
}
/**
* Negates the values of this vector internally.
*
* @return this
*/
public Vector2f negateLocal() {
x = -x;
y = -y;
return this;
}
/**
* Subtracts the values of a given vector from those of this vector creating a new vector object.
* If the provided vector is null, an exception is thrown.
*
* @param v the vector to subtract from this vector
* @return the resultant vector
*/
public Vector2f subtract(Vector2f v) {
return subtract(v, null);
}
/**
* Subtracts the values of a given vector from those of this vector storing the result in the
* given vector. If the provided vector v is null, an exception is thrown. If the provided vector
* result is null, a new vector is created.
*
* @param v the vector to subtract from this vector
* @param result the vector to store the result in
* @return the resultant vector
*/
public Vector2f subtract(Vector2f v, Vector2f result) {
if (result == null) result = new Vector2f();
result.x = x - v.x;
result.y = y - v.y;
return result;
}
/**
* Subtracts the given x,y values from those of this vector creating a new vector object.
*
* @param x value to subtract from x
* @param y value to subtract from y
* @return the resultant vector
*/
public Vector2f subtract(float x, float y) {
return new Vector2f(this.x - x, this.y - y);
}
/**
* Subtracts a provided vector to this vector internally, and returns a handle to this vector for
* easy chaining of calls. If the provided vector is null, null is returned.
*
* @param v the vector to subtract
* @return this
*/
public Vector2f subtractLocal(Vector2f v) {
if (null == v) {
return null;
}
x -= v.x;
y -= v.y;
return this;
}
/**
* Subtracts the provided values from this vector internally, and returns a handle to this vector
* for easy chaining of calls.
*
* @param x value to subtract from x
* @param y value to subtract from y
* @return this
*/
public Vector2f subtractLocal(float x, float y) {
this.x -= x;
this.y -= y;
return this;
}
/**
* Returns the unit vector of this vector. The values of this vector remain untouched.
*
* @return the newly created unit vector of this vector
*/
public Vector2f normalize() {
float length = length();
if (length != 0) {
return divide(length);
}
return divide(1);
}
/**
* Makes this vector into a unit vector of itself internally.
*
* @return this
*/
public Vector2f normalizeLocal() {
float length = length();
if (length != 0) {
return divideLocal(length);
}
return divideLocal(1);
}
/**
* Returns the minimum angle (in radians) between two vectors. It is assumed that both this vector
* and the given vector are unit vectors (iow, normalized).
*
* @param otherVector a unit vector to find the angle against
* @return the angle in radians
*/
public float smallestAngleBetween(Vector2f otherVector) {
float dotProduct = dot(otherVector);
float angle = Mathf.acos(dotProduct);
return angle;
}
/**
* Sets the closest int to the x and y components locally, with ties rounding to positive
* infinity.
*
* @return this
*/
public Vector2f roundToIntLocal() {
x = Mathf.roundToInt(x);
y = Mathf.roundToInt(y);
return this;
}
public Vector2f rotate(float[][] rotationMatrix) {
float x0 = x * rotationMatrix[0][0] + y * rotationMatrix[0][1];
float y0 = x * rotationMatrix[1][0] + y * rotationMatrix[1][1];
this.x = x0;
this.y = y0;
return this;
}
public Vector2f rotate(float angle) {
float cos = Mathf.cos(angle);
float sin = Mathf.sin(angle);
return new Vector2f(x * cos - y * sin, x * sin + y * cos);
}
/**
* Returns (in radians) the angle required to rotate a ray represented by this vector to lie
* colinear to a ray described by the given vector. It is assumed that both this vector and the
* given vector are unit vectors (iow, normalized).
*
* @param otherVector the "destination" unit vector
* @return the angle in radians
*/
public float angleBetween(Vector2f otherVector) {
float angle = Mathf.atan2(otherVector.y, otherVector.x) - Mathf.atan2(y, x);
return angle;
}
// /**
// * Computes the angle (in radians) between the vector represented
// * by this vector and the specified vector.
// * @param x the X magnitude of the other vector
// * @param y the Y magnitude of the other vector
// * @return the angle between the two vectors measured in radians
// */
// public float angle(float x, float y) {
// final float ax = getX();
// final float ay = getY();
//
// final float delta = (ax * x + ay * y) / Mathf.sqrt(
// (ax * ax + ay * ay) * (x * x + y * y));
//
// if (delta > 1.0) {
// return 0.0f;
// }
// if (delta < -1.0) {
// return Mathf.PI;
// }
//
// return Mathf.acos(delta);
// }
public Vector2f frac() {
// TODO Check if this is the correct way
return new Vector2f(x - (int) x, y - (int) y);
}
/**
* Returns the x component of this vector.
*
* @return the x component of this vector
*/
public float getX() {
return x;
}
/**
* Sets the x component of this vector to the specified new value, and returns a handle to this
* vector for easy chaining of calls.
*
* @param x the specified new x component
* @return this
*/
public Vector2f setX(float x) {
this.x = x;
return this;
}
/**
* Returns the y component of this vector.
*
* @return the y component of this vector
*/
public float getY() {
return y;
}
/**
* Sets the y component of this vector to the specified new value, and returns a handle to this
* vector for easy chaining of calls.
*
* @param y the specified new y component
* @return this
*/
public Vector2f setY(float y) {
this.y = y;
return this;
}
/**
* Returns the angle (in radians) represented by this vector as expressed by a conversion from
* rectangular coordinates ( <code>x</code>, <code>y</code>) to polar coordinates (r,
* <i>theta</i>).
*
* @return the angle in radians. [-pi, pi)
*/
public float getAngle() {
return Mathf.atan2(y, x);
}
/**
* Resets this vector's data to zero internally, and returns a handle to this vector for easy
* chaining of calls.
*/
public Vector2f zero() {
x = y = 0;
return this;
}
/**
* Returns the perpendicular vector to this vector.
*
* @return the newly created perpendicular to this vector
*/
public Vector2f getPerpendicular() {
return new Vector2f(-y, x);
}
/**
* Stores this vector into the given array.
*
* @param floats the array to store this vector in, if null, a new float array with the size of
* two is created
* @return the array, with x, y float values in that order
*/
public float[] toArray(float[] floats) {
if (floats == null) {
floats = new float[2];
}
floats[0] = x;
floats[1] = y;
return floats;
}
/**
* Stores this vector into a newly created float array with a size of two.
*
* @return the array that stores the vector with x,y component in that order
*/
public float[] toArray() {
return toArray(null);
}
/**
* Rotates this vector around the origin.
*
* @param angle the angle to rotate (in radians)
* @param cw true to rotate clockwise, false to rotate counterclockwise
*/
public Vector2f rotate(float angle, boolean cw) {
if (cw) angle = -angle;
float newX = Mathf.cos(angle) * x - Mathf.sin(angle) * y;
float newY = Mathf.sin(angle) * x + Mathf.cos(angle) * y;
return new Vector2f(newX, newY);
}
/**
* Returns a unique hash code for this vector object based on it's values. If two vectors are
* logically equivalent, they will return the same hash code value.
*
* @return the hash code value of this vector
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Float.floatToIntBits(x);
result = prime * result + Float.floatToIntBits(y);
return result;
}
/**
* Determines if this vector is equals to the given object obj.
*
* @param obj the object to compare for equality
* @return true if they are equal
*/
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
Vector2f other = (Vector2f) obj;
if (Float.floatToIntBits(x) != Float.floatToIntBits(other.x)) return false;
if (Float.floatToIntBits(y) != Float.floatToIntBits(other.y)) return false;
return true;
}
/**
* Returns a string representation of this {@link Vector2f}.
*
* @return a string representation of this {@link Vector2f}
*/
@Override
public String toString() {
return "Vector2f [x=" + x + ", y=" + y + "]";
}
}