package me.stieglmaier.sphereMiners.model.util;
public class Position {
/**
* delta epsilon constant for floating point operations
*/
public static final double DEPS = 1.19209289551e-08;
/**
* The x coordinate.
*/
private final double x;
/**
* The y coordinate.
*/
private final double y;
/**
* Creates a new {@link Position}.
*/
public Position() {
x = 0.0;
y = 0.0;
}
/**
* Creates a new {@link Position}.
*
* @param newX The x-component of the new {@link Position}.
* @param newY The y-component of the new {@link Position}.
*/
public Position(final double newX, final double newY) {
if (Double.isNaN(newX) || Double.isNaN(newY)) {
throw new IllegalArgumentException("The parameters have to be in the range of a double. x: ");
}
this.x = newX;
this.y = newY;
}
/**
* Returns a new {@link Position} calculated by scaling the current
* {@link Position} by a given factor.
*
* @param f The factor to scale the {@link Position} to.
* @return a new {@link Position} calculated by scaling the current
* {@link Position} by a given factor.
*/
public Position mult(final double f) {
return new Position(x * f, y * f);
}
/**
* Returns the sum of the current {@link Position} and a given one.
*
* @param p The {@link Position} to add.
* @return the sum of the current {@link Position} and a given one.
* @throws IllegalArgumentException if the given Position is null this exception will be thrown.
*/
public Position add(final Position p) {
return new Position(x + p.getX(), y + p.getY());
}
/**
* Returns the difference of the current {@link Position} and a given one.
*
* @param p The {@link Position} to add.
* @return the difference of the current {@link Position} and a given one.
* @throws IllegalArgumentException if the given Position is null this exception will be thrown.
*/
public Position sub(final Position p) {
return new Position(x - p.getX(), y - p.getY());
}
/**
* Returns the negative {@link Position}.
*
* @return the negative {@link Position}.
*/
public Position negate() {
return new Position(-x, -y);
}
/**
* Returns the x-component of this {@link Position}.
*
* @return the x-component of this {@link Position}.
*/
public double getX() {
return x;
}
/**
* Returns the y-component of this {@link Position}.
*
* @return the y-component of this {@link Position}.
*/
public double getY() {
return y;
}
/**
* Creates a new Position that has the inverted x coordinate compared to this
* Position.
*
* @return The new Position.
*/
public Position invertX() {
return new Position(-x, y);
}
/**
* Creates a new Position that has the inverted y coordinate compared to this
* Position.
*
* @return The new Position.
*/
public Position invertY() {
return new Position(x, -y);
}
/**
* Returns the length of this {@link Position}. (as seen from 0/0)
*
* @return the length of this {@link Position}.
*/
public double length() {
double sqLen = x * x + y * y;
return Math.sqrt(sqLen);
}
/**
* Calculates the distance of this Position to another one.
*
* @param p The other Position.
* @return The double result.
* @throws IllegalArgumentException if the given Position is null this exception will be thrown.
*/
public double dist(final Position p) {
Position dif = this.sub(p);
return dif.length();
}
/**
* Returns the normalized-vector of this {@link Position}.
*
* @return the normalized-vector of this {@link Position}.
*/
public Position normalize() {
double len = length();
if (len < DEPS) {
return new Position();
} else {
return mult(1 / len);
}
}
/**
* Method that calculates the scalar product of this vector with another
* one.
*
* @param p The other vector as Position.
* @return The double result.
*/
public double scalarProduct(final Position p) {
return x * p.getX() + y * p.getY();
}
/**
* Calculates the angle between two Positions in degrees. The angle is always
* positive and the smaller one of the two possible angles. The Positions must
* not be zero.
*
* @param v The other Position.
* @return The angle between the two Positions in degrees.
*/
public double angleDeg(final Position v) {
if (this.equals(new Position()) || v.equals(new Position())) {
throw new IllegalArgumentException("The Positions must not be zero.");
}
double val = normalize().scalarProduct(v.normalize());
if (val < -1) {
val = -1;
} else if (val > 1) {
val = 1;
}
double rad = Math.acos(val);
return rad * 180 / Math.PI;
}
/**
* Calculates the angle between two Positions in degrees. The angle is between
* -180 and 180 degrees depending on the orientation. Moreover the smaller
* (in absolute values) angle of the two possible is returned. The Positions
* must not be zero.
*
* @param v The other Position.
* @return The angle in degrees.
*/
public double angleDegOriented(final Position v) {
if (this.equals(new Position()) || v.equals(new Position())) {
throw new IllegalArgumentException("The Positions must not be zero.");
}
double angleBetween = this.angleDeg(v);
if (angleBetween < DEPS) {
return 0;
}
double angleThis = this.angleDeg(new Position(1, 0));
if (y < -DEPS) {
angleThis = 360 - angleThis;
}
double angleV = v.angleDeg(new Position(1, 0));
if (v.getY() < -DEPS) {
angleV = 360 - angleV;
}
if (angleThis - angleV > 180 || angleV - angleThis > 180) {
angleBetween = -angleBetween;
}
return angleBetween;
}
/**
* Method that calculates a normalized Position in the direction the angle
* points.
*
* @param deg The angle in degrees.
* @return The result as Position.
*/
public static Position normVecFromAngle(double deg) {
// fix degrees to range from 0 to 360
while (deg > 360) {
deg -= 360;
}
while (deg < 0) {
deg += 360;
}
double rad = deg * Math.PI / 180;
double u = Math.cos(rad);
double v = Math.sqrt(1 - u * u);
if (deg > 180) {
v = -v;
}
return new Position(u, v);
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
long temp;
temp = Double.doubleToLongBits(x);
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(y);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}
/**
* {@inheritDoc}
*
* This equals method compares two Positions in a defined epsilon environment.
*/
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Position other = (Position) obj;
if (Math.abs(x - other.x) > DEPS) {
return false;
}
if (Math.abs(y - other.y) > DEPS) {
return false;
}
return true;
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return "(" + x + ", " + y + ")";
}
}