/*
* Copyright (C) 2014 MillerV
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package aspect.util;
import java.nio.FloatBuffer;
import org.lwjgl.BufferUtils;
import org.lwjgl.util.vector.Vector2f;
/**
* A vector quantity with 2 components. This class also contains static utility
* methods for performing mathematical operations on 2-component vectors.
* Instances are mutable, so copy() should be used whenever a separate copy is
* needed.
*
* @author MillerV
*/
public class Vector2 extends Vector2f {
/**
* Returns a Vector2D with the components (0, 0).
*
* @return the origin
*/
public static Vector2 zero() {
return new Vector2(0, 0);
}
/**
* Create a new Vector2 with the specified x and y components.
*
* @param x the x coordinate of the vector
* @param y the y coordinate of the vector
*/
public Vector2(float x, float y) {
this.x = x;
this.y = y;
}
/**
* Get a Vector3 whose x and y components are equal to the x and y
* components of this Vector2 and whose z is 0.
*
* @return a Vector3 with the components (x, y, 0)
*/
public Vector3 asXY() {
return new Vector3(x, y, 0);
}
/**
* Get a Vector3 whose y and z components are equal to the x and y
* components of this Vector2 and whose x is 0.
*
* @return a Vector3 with the components (0, x, y)
*/
public Vector3 asZY() {
return new Vector3(0, y, x);
}
/**
* Get a Vector3 whose x and z components are equal to the x and y
* components of this Vector2 and whose z is 0.
*
* @return a Vector3 with the components (x, 0, z)
*/
public Vector3 asXZ() {
return new Vector3(x, 0, y);
}
/**
* Find the sum of this Vector2 and another Vector2.
*
* @param v the other Vector2
* @return the sum of the two vectors
*/
public Vector2 plus(Vector2 v) {
return add(this, v);
}
/**
* Find the difference between this Vector2 and another Vector2.
*
* @param v the other Vector2
* @return the sum of the two vectors
*/
public Vector2 minus(Vector2 v) {
return sub(this, v);
}
/**
* Get a Vector2 whose components are equal to the opposite of this
* Vector2's components, resulting in equal magnitude and opposite
* direction.
*
* @return the negated Vector2
*/
@Override
public Vector2 negate() {
return negate(this);
}
/**
* Get a Vector2 whose components are equal to this Vector2's components
* multiplied by the given value.
*
* @param f the multiplier
* @return the multiplied Vector2
*/
public Vector2 times(float f) {
return multiply(this, f);
}
/**
* Get a Vector2 whose magnitude is equal to this vector's magnitude and
* whose direction is equal to this vector's direction plus the given
* angle.
*
* @param angle the angle to add
* @return the rotated vector
*/
public Vector2 rotate(float angle) {
return fromAngle(angle + dir(), mag());
}
/**
* Copy this Vector2.
*
* @return a copy of this Vector2
*/
public Vector2 copy() {
return new Vector2(x, y);
}
/**
* Get the magnitude of this Vector2, or its distance from the origin.
*
* @return the magnitude of this Vector2
*/
public float mag() {
return mag(this);
}
/**
* Get the direction of this vector as an angle.
*
* @return the direction of this vector
*/
public float dir() {
return dir(this);
}
/**
* Get a Vector2 whose magnitude is 1 and whose direction is equal to the
* direction of this Vector2.
*
* @return the normalized Vector2
*/
public Vector2 normalize() {
return normalize(this);
}
/**
* Find the distance between the two given Vector2s.
*
* @param v1 the first Vector2
* @param v2 the second Vector2
* @return the distance between v1 and v2
*/
public static float distance(Vector2 v1, Vector2 v2) {
return mag(sub(v2, v1));
}
/**
* Get the magnitude of the given Vector2.
*
* @param v the Vector2
* @return the magnitude of v
*/
public static float mag(Vector2 v) {
return (float) Math.sqrt(Math.pow(v.x, 2) + Math.pow(v.y, 2));
}
/**
* Find the angle pointing from one Vector2 to another.
*
* @param v1 the first Vector2
* @param v2 the second Vector2
* @return the angle pointing from v1 to v2
*/
public static float toAngle(Vector2 v1, Vector2 v2) {
return dir(sub(v2, v1));
}
/**
* Convert the Cartesian components of a Vector2 to an angle.
*
* @param v the Vector2 to convert
* @return the direction of this vector
*/
public static float dir(Vector2 v) {
return Trig.atan2(v.x, v.y);
}
/**
* Construct a new Vector2 from standard form (direction, magnitude).
*
* @param direction the direction of the new Vector2
* @param magnitude the magnitude of the new Vector2
* @return a new Vector2 with the given direction and magnitude
*/
public static Vector2 fromAngle(float direction, float magnitude) {
float newx = Trig.sin(direction) * magnitude;
float newy = Trig.cos(direction) * magnitude;
return new Vector2(newx, newy);
}
/**
* Find the sum of two Vector2s.
*
* @param v1 the first Vector2
* @param v2 the second Vector2
* @return the sum p1 + p2
*/
public static Vector2 add(Vector2 v1, Vector2 v2) {
return new Vector2(v1.x + v2.x, v1.y + v2.y);
}
/**
* Find the difference of two Vector2s.
*
* @param s the subtrahend Vector2
* @param m the minuend Vector2
* @return the difference s - m
*/
public static Vector2 sub(Vector2 s, Vector2 m) {
return new Vector2(s.x - m.x, s.y - m.y);
}
/**
* Get a Vector2 whose components are equal to the components of the given
* Vector2 multiplied by the given value.
*
* @param v the Vector2 to multiply
* @param scale the multiplier
* @return the scaled Vector2
*/
public static Vector2 multiply(Vector2 v, float scale) {
return new Vector2(v.x * scale, v.y * scale);
}
/**
* Get a Vector2 whose components are equal to the given Vector2's
* components multiplied by -1.
*
* @param v the Vector2 to negate
* @return the negated Vector2
*/
public static Vector2 negate(Vector2 v) {
return new Vector2(-v.x, -v.y);
}
/**
* Find the dot product of two Vector2s, or
* <code>v1.x * v2.x + v1.y * v2.y</code>
*
* @param v1 the first Vector2
* @param v2 the second Vector2
* @return the dot product of v1 and v2
*/
public static float dot(Vector2 v1, Vector2 v2) {
return v1.x * v2.x + v1.y * v2.y;
}
public static float angleBetween(Vector2 v1, Vector2 v2) {
return angle(v1, v2);
}
/**
* Get a Vector2 whose direction is equal to the direction of the given
* Vector2 and whose magnitude is 1.
*
* @param v the Vector2 to normalize
* @return the normalized Vector2
*/
public static Vector2 normalize(Vector2 v) {
if (v.equals(zero())) {
return v;
}
float distance = mag(v);
return multiply(v, 1 / distance);
}
/**
* Find the intersection of the lines v1v2 and v3v4. If the lines are
* parallel, the intersection is (POSITIVE_INFINITY, POSITIVE_INFINITY).
* Source: http://en.wikipedia.org/wiki/Line%E2%80%93line_intersection
*
* @param v1 the first point of the first line
* @param v2 the second point of the first line
* @param v3 the first point of the second line
* @param v4 the second point of the second line
* @return the intersection between lines v1v2 and v3v4
*/
public static Vector2 intersection(Vector2 v1, Vector2 v2, Vector2 v3, Vector2 v4) {
float det = ((v1.x - v2.x) * (v3.y - v4.y)) - ((v1.y - v2.y) * (v3.x - v4.x));
float x = ((v1.x * v2.y - v1.y * v2.x) * (v3.x - v4.x)) - ((v1.x - v2.x) * (v3.x * v4.y - v3.y * v4.x));
x /= det;
float y = ((v1.x * v2.y - v1.y * v2.x) * (v3.y - v4.y)) - ((v1.y - v2.y) * (v3.x * v4.y - v3.y * v4.x));
y /= det;
return new Vector2(x, y);
}
/**
* Find the intersection of the segments v1v2 and v3v4. If the segments do
* not intersect, then null is returned.
* Source: http://en.wikipedia.org/wiki/Line%E2%80%93line_intersection
*
* @param v1 the first point of the first line
* @param v2 the second point of the first line
* @param v3 the first point of the second line
* @param v4 the second point of the second line
* @return the intersection between lines v1v2 and v3v4
*/
public static Vector2 pointOfIntersection(Vector2 v1, Vector2 v2, Vector2 v3, Vector2 v4) {
if (v1.equals(v2) || v3.equals(v4)) {
return null;
}
Vector2 i = intersection(v1, v2, v3, v4);
if (checkIntersection(i, v1, v2) && checkIntersection(i, v3, v4)) {
return i;
} else {
return null;
}
}
/**
* Check whether the segments v1v2 and v3v4 intersect.
*
* @param v1 the first point of the first segment
* @param v2 the second point of the first segment
* @param v3 the first point of the second segment
* @param v4 the second point of the second segment
* @return whether v1v2 and v3v4 intersect
*/
public static boolean checkIntersection(Vector2 v1, Vector2 v2, Vector2 v3, Vector2 v4) {
if (v1.equals(v2) || v3.equals(v4)) {
return false;
}
Vector2 i = intersection(v1, v2, v3, v4);
return checkIntersection(i, v1, v2) && checkIntersection(i, v3, v4);
}
/**
* Check whether the given point of intersection is a valid segment
* intersection. In other words, returns true if i is within the axis
* aligned bounding box defined by the points v1 and v2.
*
* @param i the point of test
* @param v1 the first point of the segment
* @param v2 the second point of the segment
* @return whether the test passed
*/
public static boolean checkIntersection(Vector2 i, Vector2 v1, Vector2 v2) {
if (v1.equals(v2)) {
return false;
}
if (v1.x < v2.x) {
if (i.x > v1.x && i.x < v2.x) {
return true;
}
} else {
if (i.x > v2.x && i.x < v1.x) {
return true;
}
}
if (v1.y < v2.y) {
if (i.y > v1.y && i.y < v2.y) {
return true;
}
} else {
if (i.y > v2.y && i.y < v1.y) {
return true;
}
}
return false;
}
@Override
public String toString() {
return "(" + x + ", " + y + ")";
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Vector2)) {
return false;
}
Vector2 v = (Vector2) obj;
return x == v.x && y == v.y;
}
@Override
public int hashCode() {
int hash = 5;
hash = 79 * hash + Float.floatToIntBits(this.x);
hash = 79 * hash + Float.floatToIntBits(this.y);
return hash;
}
public FloatBuffer getBuffer() {
FloatBuffer buffer = BufferUtils.createFloatBuffer(2);
store(buffer);
buffer.clear();
return buffer;
}
}