mirror of
https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02.git
synced 2024-11-28 23:39:45 +01:00
258 lines
7.0 KiB
Java
258 lines
7.0 KiB
Java
////////////////////////////////////////
|
|
// Programming project code
|
|
// UniBw M, 2022, 2023, 2024
|
|
// www.unibw.de/inf2
|
|
// (c) Mark Minas (mark.minas@unibw.de)
|
|
////////////////////////////////////////
|
|
|
|
package pp.util;
|
|
|
|
import java.util.Objects;
|
|
|
|
import static pp.util.FloatMath.DEG_TO_RAD;
|
|
import static pp.util.FloatMath.FLT_EPSILON;
|
|
import static pp.util.FloatMath.RAD_TO_DEG;
|
|
import static pp.util.FloatMath.abs;
|
|
import static pp.util.FloatMath.atan2;
|
|
import static pp.util.FloatMath.cos;
|
|
import static pp.util.FloatMath.sin;
|
|
import static pp.util.FloatMath.sqrt;
|
|
|
|
/**
|
|
* A class for representing angles by unit vectors where angles define
|
|
* polar coordinates.
|
|
*/
|
|
public class Angle implements Comparable<Angle> {
|
|
/**
|
|
* 0 degrees, i.e., along the x-axis
|
|
*/
|
|
public static final Angle ZERO = new Angle(1f, 0f);
|
|
/**
|
|
* 180 degrees, i.e., along the negative x-axis
|
|
*/
|
|
public static final Angle PI = new Angle(-1f, 0f);
|
|
|
|
/**
|
|
* Returns the minimum of the specified angles with respect to
|
|
* {@linkplain #compareTo(Angle)}.
|
|
*
|
|
* @param u first angle to compare
|
|
* @param v second angle to compare
|
|
*/
|
|
public static Angle min(Angle u, Angle v) {
|
|
return u.compareTo(v) <= 0 ? u : v;
|
|
}
|
|
|
|
/**
|
|
* The x-coordinate of the unit vector.
|
|
*/
|
|
public final float x;
|
|
/**
|
|
* The y-coordinate of the unit vector.
|
|
*/
|
|
public final float y;
|
|
|
|
/**
|
|
* Creates a new angle represented by the vector with the specified
|
|
* coordinates. Note that the vector must have length 1.
|
|
*/
|
|
private Angle(float x, float y) {
|
|
this.x = x;
|
|
this.y = y;
|
|
}
|
|
|
|
/**
|
|
* Returns the polar coordinates angle of the specified vector.
|
|
*
|
|
* @param x the vectors x value
|
|
* @param y the vectors y value
|
|
*/
|
|
public static Angle fromVector(float x, float y) {
|
|
final float len = sqrt(x * x + y * y);
|
|
if (len < FLT_EPSILON)
|
|
throw new IllegalArgumentException("null vector");
|
|
return new Angle(x / len, y / len);
|
|
}
|
|
|
|
/**
|
|
* Returns the polar coordinates angle when looking from the first to the second
|
|
* specified position.
|
|
*
|
|
* @param from first position
|
|
* @param to second position
|
|
*/
|
|
public static Angle direction(Position from, Position to) {
|
|
return fromVector(to.getX() - from.getX(),
|
|
to.getY() - from.getY());
|
|
}
|
|
|
|
/**
|
|
* Returns an Angle object for the specified angle in radians.
|
|
*
|
|
* @param radians the specified radian value
|
|
*/
|
|
public static Angle fromRadians(float radians) {
|
|
return new Angle(cos(radians), sin(radians));
|
|
}
|
|
|
|
/**
|
|
* Returns an Angle object for the specified angle in degrees.
|
|
*
|
|
* @param degrees the specified degrees value
|
|
*/
|
|
public static Angle fromDegrees(float degrees) {
|
|
return fromRadians(degrees * DEG_TO_RAD);
|
|
}
|
|
|
|
/**
|
|
* Returns the value of this angle in radians in the range (-pi,pi].
|
|
*/
|
|
public float radians() {
|
|
return atan2(y, x);
|
|
}
|
|
|
|
/**
|
|
* Returns the value of this angle in degrees in the range (-180,180].
|
|
*/
|
|
public float degrees() {
|
|
return radians() * RAD_TO_DEG;
|
|
}
|
|
|
|
/**
|
|
* Returns the x-coordinate of the unit vector, that is the cosine of the angle.
|
|
*/
|
|
public float getX() {
|
|
return x;
|
|
}
|
|
|
|
/**
|
|
* Returns the y-coordinate of the unit vector, that is the sinus of the angle.
|
|
*/
|
|
public float getY() {
|
|
return y;
|
|
}
|
|
|
|
/**
|
|
* Returns the angle obtained by adding the specified angle to this angle.
|
|
*
|
|
* @param o the other angle
|
|
*/
|
|
public Angle plus(Angle o) {
|
|
return new Angle(x * o.x - y * o.y,
|
|
x * o.y + y * o.x);
|
|
}
|
|
|
|
/**
|
|
* Returns the angle obtained by subtracting the specified angle from this angle.
|
|
*
|
|
* @param o the other angle
|
|
*/
|
|
public Angle minus(Angle o) {
|
|
return new Angle(y * o.y + x * o.x,
|
|
y * o.x - x * o.y);
|
|
}
|
|
|
|
/**
|
|
* Returns the bisector angle between this angle as left angle and the
|
|
* specified right angle, that is, the angle halfway from the right to this
|
|
* angle when turning from right to left.
|
|
*
|
|
* @param right right angle
|
|
* @return the bisector angle between this as left and the specified right angle
|
|
*/
|
|
public Angle bisector(Angle right) {
|
|
// compute vector of this.minus(right)
|
|
final float dx = y * right.y + x * right.x;
|
|
final float dy = y * right.x - x * right.y;
|
|
if (abs(dy) < FLT_EPSILON) {
|
|
// the difference is either 0° or 180°
|
|
if (dx > 0f)
|
|
return this;
|
|
else
|
|
return new Angle(-right.y, right.x);
|
|
}
|
|
final float mid = 0.5f * atan2(dy, dx);
|
|
final float sum = right.radians() + mid;
|
|
if (mid > 0f)
|
|
return new Angle(cos(sum), sin(sum));
|
|
else
|
|
return new Angle(-cos(sum), -sin(sum));
|
|
}
|
|
|
|
/**
|
|
* Returns true if turning left from the specified angle towards this angle is
|
|
* shorter than turning right towards this angle.
|
|
*
|
|
* @param o another angle
|
|
*/
|
|
public boolean leftOf(Angle o) {
|
|
return y * o.x - x * o.y > 0f;
|
|
}
|
|
|
|
/**
|
|
* Returns true if turning right from the specified angle towards this angle is
|
|
* shorter than turning left towards this angle.
|
|
*
|
|
* @param o another angle
|
|
*/
|
|
public boolean rightOf(Angle o) {
|
|
return y * o.x - x * o.y < 0f;
|
|
}
|
|
|
|
/**
|
|
* Compares this angle with the specified one and returns -1, 0, or 1 if
|
|
* the value of this angle is less than, equal to, or greater than the value
|
|
* of the specified angle, respectively, where angle values are in the
|
|
* range [0,2*pi) and 0 means along the x-axis.
|
|
*
|
|
* @param o the other angle
|
|
*/
|
|
@Override
|
|
public int compareTo(Angle o) {
|
|
if (y == 0f) {
|
|
if (o.y < 0f)
|
|
return -1;
|
|
if (o.y > 0f)
|
|
return x > 0f ? -1 : 1;
|
|
if (x > 0f)
|
|
return o.x > 0f ? 0 : 1;
|
|
return o.x > 0f ? -1 : 0;
|
|
}
|
|
if (y > 0f) {
|
|
if (o.y < 0f)
|
|
return -1;
|
|
if (o.y == 0f)
|
|
return o.x > 0f ? 1 : -1;
|
|
}
|
|
else if (o.y >= 0f)
|
|
return 1;
|
|
final float det = x * o.y - y * o.x;
|
|
if (det == 0f)
|
|
return 0;
|
|
return det > 0f ? -1 : 1;
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(Object o) {
|
|
if (this == o) return true;
|
|
if (o instanceof Angle angle)
|
|
return compareTo(angle) == 0;
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public int hashCode() {
|
|
return Objects.hash(x, y);
|
|
}
|
|
|
|
/**
|
|
* Returns a string representation of this angle in degrees in the range [0,2*pi).
|
|
*/
|
|
@Override
|
|
public String toString() {
|
|
if (degrees() < 0f)
|
|
return (degrees() + 360f) + "°";
|
|
return degrees() + "°";
|
|
}
|
|
}
|