/*
* Copyright (c) CovertJaguar, 2014 http://railcraft.info
*
* This code is the property of CovertJaguar
* and may only be used with explicit written
* permission unless otherwise specified on the
* license page at http://railcraft.info/wiki/info:license.
*/
package mods.railcraft.common.util.misc;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
/**
* A mutable 2D Vector class that supports a broader range of math operations
* than Minecraft's immutable Vec3D class.
* @author CovertJaguar <http://www.railcraft.info>
*/
public class Vec2D extends Point2D.Double
{
public static final float DEGREES_45 = (float)(0.25 * Math.PI);
public static final float DEGREES_90 = (float)(0.5 * Math.PI);
public static final float DEGREES_135 = (float)(0.75 * Math.PI);
public static final float DEGREES_180 = (float)(Math.PI);
public static final float DEGREES_270 = (float)(1.5 * Math.PI);
public Vec2D()
{
}
public Vec2D(final Point2D p)
{
super(p.getX(), p.getY());
}
public Vec2D(double x, double y)
{
super(x, y);
}
@Override
public Vec2D clone()
{
return new Vec2D(x, y);
}
public static Vec2D fromPolar(double angle, float magnitude)
{
Vec2D v = new Vec2D();
v.setFromPolar(angle, magnitude);
return v;
}
static public Vec2D add(final Point2D a, final Point2D b)
{
return new Vec2D(a.getX() + b.getX(), a.getY() + b.getY());
}
static public Vec2D subtract(final Point2D a, final Point2D b)
{
return new Vec2D(a.getX() - b.getX(), a.getY() - b.getY());
}
public void setLocation(int x, int y)
{
this.x = x;
this.y = y;
}
//==============================================================================
public void setFromPolar(double angle, float magnitude)
{
float x = (float)Math.cos(angle) * magnitude;
float y = (float)Math.sin(angle) * magnitude;
setLocation(x, y);
}
public void zero()
{
x = y = 0;
}
public void normalize()
{
double mag = magnitude();
if(mag != 0) {
setLocation(x / mag, y / mag);
}
}
public Vec2D unitVector()
{
Vec2D v = this.clone();
v.normalize();
return v;
}
public double magnitude()
{
return Math.sqrt(x * x + y * y);
}
public void setMagnitude(float mag)
{
setFromPolar(angle(), mag);
}
public double magnitudeSq()
{
return x * x + y * y;
}
public void negate()
{
x = -x;
y = -y;
}
public float angle()
{
return (float)Math.atan2(y, x);
}
public void rotate(double theta)
{
double nx = x * (float)Math.cos(theta) - y * (float)Math.sin(theta);
double ny = x * (float)Math.sin(theta) + y * (float)Math.cos(theta);
setLocation(nx, ny);
}
public void rotate90()
{
double ox = x;
x = -y;
y = ox;
}
public void rotate270()
{
double ox = x;
x = y;
y = -ox;
}
public void subtract(final Point2D p)
{
x -= p.getX();
y -= p.getY();
}
public void subtract(int x, int y)
{
this.x -= x;
this.y -= y;
}
public void subtract(final double x, final double y)
{
this.x -= (int)x;
this.y -= (int)y;
}
public void add(final Point2D p)
{
x += p.getX();
y += p.getY();
}
public void add(int x, int y)
{
this.x += x;
this.y += y;
}
public void add(final double x, final double y)
{
this.x += (int)x;
this.y += (int)y;
}
public void transform(AffineTransform a)
{
setLocation(a.transform(this, null));
}
public Vec2D makeTransform(AffineTransform a)
{
return new Vec2D(a.transform(this, null));
}
/**
* Finds the dot product of two vectors.
* @param v
* @return
*/
public double dotProduct(final Point2D v)
{
return x * v.getX() + y * v.getY();
}
/**
* Finds the absolute angle between two vectors using the Law of Cosines:<br>
* <b>V . W = |V||W|cos(a)</b>
*/
public double angleBetween(final Vec2D v)
{
double a = dotProduct(v);
double magnitude = magnitude() * v.magnitude();
if(magnitude == 0) {
return 0;
}
a /= magnitude;
// Check bounds, if you don't you WILL get NaNs from acos.
// This is becuase of slight errors in the floating point arithmatic.
if(a > 1) {
a = 1;
} else if(a < -1) {
a = -1;
}
return Math.acos(a);
}
public double angleTo(Point2D a)
{
return Math.atan2(a.getY() - y, a.getX() - x);
}
public double angleFrom(Point2D a)
{
return Math.atan2(y - a.getY(), x - a.getX());
}
public void scale(float scale)
{
x *= scale;
y *= scale;
}
public void addScale(float scale, Point2D v)
{
setLocation(x + v.getX() * scale, y + v.getY() * scale);
}
}