added contents
This commit is contained in:
257
Projekte/common/src/main/java/pp/util/Angle.java
Normal file
257
Projekte/common/src/main/java/pp/util/Angle.java
Normal file
@@ -0,0 +1,257 @@
|
||||
////////////////////////////////////////
|
||||
// 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() + "°";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user