added contents
This commit is contained in:
		
							
								
								
									
										5
									
								
								Projekte/common/build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								Projekte/common/build.gradle
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
plugins {
 | 
			
		||||
    id 'buildlogic.java-library-conventions'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
description = 'Common classes'
 | 
			
		||||
							
								
								
									
										7
									
								
								Projekte/common/logging.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								Projekte/common/logging.properties
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
handlers=java.util.logging.ConsoleHandler
 | 
			
		||||
.level=INFO
 | 
			
		||||
;pp.level=FINE
 | 
			
		||||
pp.util.triangulation.Polygon.level=FINE
 | 
			
		||||
java.util.logging.ConsoleHandler.level=FINER
 | 
			
		||||
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
 | 
			
		||||
java.util.logging.SimpleFormatter.format=[%4$s %2$s] %5$s%6$s%n
 | 
			
		||||
							
								
								
									
										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() + "°";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										425
									
								
								Projekte/common/src/main/java/pp/util/FloatMath.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										425
									
								
								Projekte/common/src/main/java/pp/util/FloatMath.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,425 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.util;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Provides mathematical functions using float precision.
 | 
			
		||||
 */
 | 
			
		||||
public class FloatMath {
 | 
			
		||||
    private FloatMath() { /* don't instantiate */ }
 | 
			
		||||
 | 
			
		||||
    public static final double DBL_EPSILON = 2.220446049250313E-16d;
 | 
			
		||||
    /**
 | 
			
		||||
     * A "close to zero" float epsilon value for use
 | 
			
		||||
     */
 | 
			
		||||
    public static final float FLT_EPSILON = 1.1920928955078125E-7f;
 | 
			
		||||
    /**
 | 
			
		||||
     * A "close to zero" float epsilon value for use
 | 
			
		||||
     */
 | 
			
		||||
    public static final float ZERO_TOLERANCE = 0.0001f;
 | 
			
		||||
    /**
 | 
			
		||||
     * The value 1/3, as a float.
 | 
			
		||||
     */
 | 
			
		||||
    public static final float ONE_THIRD = 1f / 3f;
 | 
			
		||||
    /**
 | 
			
		||||
     * The value PI as a float. (180 degrees)
 | 
			
		||||
     */
 | 
			
		||||
    public static final float PI = (float) Math.PI;
 | 
			
		||||
    /**
 | 
			
		||||
     * The value 2PI as a float. (360 degrees)
 | 
			
		||||
     */
 | 
			
		||||
    public static final float TWO_PI = 2.0f * PI;
 | 
			
		||||
    /**
 | 
			
		||||
     * The value PI/2 as a float. (90 degrees)
 | 
			
		||||
     */
 | 
			
		||||
    public static final float HALF_PI = 0.5f * PI;
 | 
			
		||||
    /**
 | 
			
		||||
     * The value PI/4 as a float. (45 degrees)
 | 
			
		||||
     */
 | 
			
		||||
    public static final float QUARTER_PI = 0.25f * PI;
 | 
			
		||||
    /**
 | 
			
		||||
     * The value 1/PI as a float.
 | 
			
		||||
     */
 | 
			
		||||
    public static final float INV_PI = 1.0f / PI;
 | 
			
		||||
    /**
 | 
			
		||||
     * The value 1/(2PI) as a float.
 | 
			
		||||
     */
 | 
			
		||||
    public static final float INV_TWO_PI = 1.0f / TWO_PI;
 | 
			
		||||
    /**
 | 
			
		||||
     * A value to multiply a degree value by, to convert it to radians.
 | 
			
		||||
     */
 | 
			
		||||
    public static final float DEG_TO_RAD = PI / 180.0f;
 | 
			
		||||
    /**
 | 
			
		||||
     * A value to multiply a radian value by, to convert it to degrees.
 | 
			
		||||
     */
 | 
			
		||||
    public static final float RAD_TO_DEG = 180.0f / PI;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Linear interpolation from startValue to endValue by the given percent.
 | 
			
		||||
     * Basically: ((1 - percent) * startValue) + (percent * endValue)
 | 
			
		||||
     *
 | 
			
		||||
     * @param scale      scale value to use. if 1, use endValue, if 0, use startValue.
 | 
			
		||||
     * @param startValue Beginning value. 0% of f
 | 
			
		||||
     * @param endValue   ending value. 100% of f
 | 
			
		||||
     * @return The interpolated value between startValue and endValue.
 | 
			
		||||
     */
 | 
			
		||||
    public static float interpolateLinear(float scale, float startValue, float endValue) {
 | 
			
		||||
        if (startValue == endValue) {
 | 
			
		||||
            return startValue;
 | 
			
		||||
        }
 | 
			
		||||
        if (scale <= 0f) {
 | 
			
		||||
            return startValue;
 | 
			
		||||
        }
 | 
			
		||||
        if (scale >= 1f) {
 | 
			
		||||
            return endValue;
 | 
			
		||||
        }
 | 
			
		||||
        return ((1f - scale) * startValue) + (scale * endValue);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Linear extrapolation from startValue to endValue by the given scale.
 | 
			
		||||
     * if scale is between 0 and 1 this method returns the same result as interpolateLinear
 | 
			
		||||
     * if the scale is over 1 the value is linearly extrapolated.
 | 
			
		||||
     * Note that the end value is the value for a scale of 1.
 | 
			
		||||
     *
 | 
			
		||||
     * @param scale      the scale for extrapolation
 | 
			
		||||
     * @param startValue the starting value (scale = 0)
 | 
			
		||||
     * @param endValue   the end value (scale = 1)
 | 
			
		||||
     * @return an extrapolation for the given parameters
 | 
			
		||||
     */
 | 
			
		||||
    public static float extrapolateLinear(float scale, float startValue, float endValue) {
 | 
			
		||||
        return ((1f - scale) * startValue) + (scale * endValue);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the arc cosine of a value.<br>
 | 
			
		||||
     * Special cases:
 | 
			
		||||
     * <ul><li>If fValue is smaller than -1, then the result is PI.
 | 
			
		||||
     * <li>If the argument is greater than 1, then the result is 0.</ul>
 | 
			
		||||
     *
 | 
			
		||||
     * @param fValue The value to arc cosine.
 | 
			
		||||
     * @return The angle, in radians.
 | 
			
		||||
     * @see Math#acos(double)
 | 
			
		||||
     */
 | 
			
		||||
    public static float acos(float fValue) {
 | 
			
		||||
        if (-1.0f < fValue) {
 | 
			
		||||
            if (fValue < 1.0f) {
 | 
			
		||||
                return (float) Math.acos(fValue);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return 0.0f;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return PI;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the arc sine of a value.<br>
 | 
			
		||||
     * Special cases:
 | 
			
		||||
     * <ul><li>If fValue is smaller than -1, then the result is -HALF_PI.
 | 
			
		||||
     * <li>If the argument is greater than 1, then the result is HALF_PI.</ul>
 | 
			
		||||
     *
 | 
			
		||||
     * @param fValue The value to arc sine.
 | 
			
		||||
     * @return the angle in radians.
 | 
			
		||||
     * @see Math#asin(double)
 | 
			
		||||
     */
 | 
			
		||||
    public static float asin(float fValue) {
 | 
			
		||||
        if (-1.0f < fValue) {
 | 
			
		||||
            if (fValue < 1.0f) {
 | 
			
		||||
                return (float) Math.asin(fValue);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return HALF_PI;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return -HALF_PI;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the arc tangent of an angle given in radians.<br>
 | 
			
		||||
     *
 | 
			
		||||
     * @param fValue The angle, in radians.
 | 
			
		||||
     * @return fValue's atan
 | 
			
		||||
     * @see Math#atan(double)
 | 
			
		||||
     */
 | 
			
		||||
    public static float atan(float fValue) {
 | 
			
		||||
        return (float) Math.atan(fValue);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A direct call to Math.atan2.
 | 
			
		||||
     *
 | 
			
		||||
     * @param fY ordinate
 | 
			
		||||
     * @param fX abscissa
 | 
			
		||||
     * @return Math.atan2(fY, fX)
 | 
			
		||||
     * @see Math#atan2(double, double)
 | 
			
		||||
     */
 | 
			
		||||
    public static float atan2(float fY, float fX) {
 | 
			
		||||
        return (float) Math.atan2(fY, fX);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static float sinh(float x) {
 | 
			
		||||
        return (float) Math.sinh(x);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static float cosh(float x) {
 | 
			
		||||
        return (float) Math.cosh(x);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static float tanh(float x) {
 | 
			
		||||
        return (float) Math.tanh(x);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static float coth(float x) {
 | 
			
		||||
        return (float) (1d / Math.tanh(x));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static float arsinh(float x) {
 | 
			
		||||
        return log(x + sqrt(x * x + 1f));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static float arcosh(float x) {
 | 
			
		||||
        return log(x + sqrt(x * x - 1f));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static float artanh(float x) {
 | 
			
		||||
        return 0.5f * log((1f + x) / (1f - x));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static float arcoth(float x) {
 | 
			
		||||
        return 0.5f * log((x + 1f) / (x - 1f));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Rounds a fValue up. A call to Math.ceil
 | 
			
		||||
     *
 | 
			
		||||
     * @param fValue The value.
 | 
			
		||||
     * @return The fValue rounded up
 | 
			
		||||
     * @see Math#ceil(double)
 | 
			
		||||
     */
 | 
			
		||||
    public static float ceil(float fValue) {
 | 
			
		||||
        return (float) Math.ceil(fValue);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns cosine of an angle. Direct call to Math
 | 
			
		||||
     *
 | 
			
		||||
     * @param v The angle to cosine.
 | 
			
		||||
     * @return the cosine of the angle.
 | 
			
		||||
     * @see Math#cos(double)
 | 
			
		||||
     */
 | 
			
		||||
    public static float cos(float v) {
 | 
			
		||||
        return (float) Math.cos(v);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the sine of an angle. Direct call to Math
 | 
			
		||||
     *
 | 
			
		||||
     * @param v The angle to sine.
 | 
			
		||||
     * @return the sine of the angle.
 | 
			
		||||
     * @see Math#sin(double)
 | 
			
		||||
     */
 | 
			
		||||
    public static float sin(float v) {
 | 
			
		||||
        return (float) Math.sin(v);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns E^fValue
 | 
			
		||||
     *
 | 
			
		||||
     * @param fValue Value to raise to a power.
 | 
			
		||||
     * @return The value E^fValue
 | 
			
		||||
     * @see Math#exp(double)
 | 
			
		||||
     */
 | 
			
		||||
    public static float exp(float fValue) {
 | 
			
		||||
        return (float) Math.exp(fValue);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static float expm1(float fValue) {
 | 
			
		||||
        return (float) Math.expm1(fValue);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns Absolute value of a float.
 | 
			
		||||
     *
 | 
			
		||||
     * @param fValue The value to abs.
 | 
			
		||||
     * @return The abs of the value.
 | 
			
		||||
     * @see Math#abs(float)
 | 
			
		||||
     */
 | 
			
		||||
    public static float abs(float fValue) {
 | 
			
		||||
        if (fValue < 0) {
 | 
			
		||||
            return -fValue;
 | 
			
		||||
        }
 | 
			
		||||
        return fValue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns a number rounded down.
 | 
			
		||||
     *
 | 
			
		||||
     * @param fValue The value to round
 | 
			
		||||
     * @return The given number rounded down
 | 
			
		||||
     * @see Math#floor(double)
 | 
			
		||||
     */
 | 
			
		||||
    public static float floor(float fValue) {
 | 
			
		||||
        return (float) Math.floor(fValue);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns 1/sqrt(fValue)
 | 
			
		||||
     *
 | 
			
		||||
     * @param fValue The value to process.
 | 
			
		||||
     * @return 1/sqrt(fValue)
 | 
			
		||||
     * @see Math#sqrt(double)
 | 
			
		||||
     */
 | 
			
		||||
    public static float invSqrt(float fValue) {
 | 
			
		||||
        return (float) (1.0f / Math.sqrt(fValue));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Quickly estimate 1/sqrt(fValue).
 | 
			
		||||
     *
 | 
			
		||||
     * @param x the input value (≥0)
 | 
			
		||||
     * @return an approximate value for 1/sqrt(x)
 | 
			
		||||
     */
 | 
			
		||||
    public static float fastInvSqrt(float x) {
 | 
			
		||||
        float halfX = 0.5f * x;
 | 
			
		||||
        int i = Float.floatToIntBits(x); // get bits for floating value
 | 
			
		||||
        i = 0x5f375a86 - (i >> 1); // gives initial guess y0
 | 
			
		||||
        x = Float.intBitsToFloat(i); // convert bits back to float
 | 
			
		||||
        x = x * (1.5f - halfX * x * x); // Newton step, repeating increases accuracy
 | 
			
		||||
        return x;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the log base E of a value.
 | 
			
		||||
     *
 | 
			
		||||
     * @param fValue The value to log.
 | 
			
		||||
     * @return The log of fValue base E
 | 
			
		||||
     * @see Math#log(double)
 | 
			
		||||
     */
 | 
			
		||||
    public static float log(float fValue) {
 | 
			
		||||
        return (float) Math.log(fValue);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns a number raised to an exponent power. fBase^fExponent
 | 
			
		||||
     *
 | 
			
		||||
     * @param fBase     The base value (IE 2)
 | 
			
		||||
     * @param fExponent The exponent value (IE 3)
 | 
			
		||||
     * @return base raised to exponent (IE 8)
 | 
			
		||||
     * @see Math#pow(double, double)
 | 
			
		||||
     */
 | 
			
		||||
    public static float pow(float fBase, float fExponent) {
 | 
			
		||||
        return (float) Math.pow(fBase, fExponent);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the value squared. fValue ^ 2
 | 
			
		||||
     *
 | 
			
		||||
     * @param fValue The value to square.
 | 
			
		||||
     * @return The square of the given value.
 | 
			
		||||
     */
 | 
			
		||||
    public static float sqr(float fValue) {
 | 
			
		||||
        return fValue * fValue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the square root of a given value.
 | 
			
		||||
     *
 | 
			
		||||
     * @param fValue The value to sqrt.
 | 
			
		||||
     * @return The square root of the given value.
 | 
			
		||||
     * @see Math#sqrt(double)
 | 
			
		||||
     */
 | 
			
		||||
    public static float sqrt(float fValue) {
 | 
			
		||||
        return (float) Math.sqrt(fValue);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the tangent of the specified angle.
 | 
			
		||||
     *
 | 
			
		||||
     * @param fValue The value to tangent, in radians.
 | 
			
		||||
     * @return The tangent of fValue.
 | 
			
		||||
     * @see Math#tan(double)
 | 
			
		||||
     */
 | 
			
		||||
    public static float tan(float fValue) {
 | 
			
		||||
        return (float) Math.tan(fValue);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns 1 if the number is positive, -1 if the number is negative, and 0 otherwise
 | 
			
		||||
     *
 | 
			
		||||
     * @param iValue The integer to examine.
 | 
			
		||||
     * @return The integer's sign.
 | 
			
		||||
     */
 | 
			
		||||
    public static int sign(int iValue) {
 | 
			
		||||
        return Integer.compare(iValue, 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns 1 if the number is positive, -1 if the number is negative, and 0 otherwise
 | 
			
		||||
     *
 | 
			
		||||
     * @param fValue The float to examine.
 | 
			
		||||
     * @return The float's sign.
 | 
			
		||||
     */
 | 
			
		||||
    public static float sign(float fValue) {
 | 
			
		||||
        return Math.signum(fValue);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Take a float input and clamp it between min and max.
 | 
			
		||||
     *
 | 
			
		||||
     * @param input the value to be clamped
 | 
			
		||||
     * @param min   the minimum output value
 | 
			
		||||
     * @param max   the maximum output value
 | 
			
		||||
     * @return clamped input
 | 
			
		||||
     */
 | 
			
		||||
    public static float clamp(float input, float min, float max) {
 | 
			
		||||
        return Math.max(min, Math.min(input, max));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Clamps the given float to be between 0 and 1.
 | 
			
		||||
     *
 | 
			
		||||
     * @param input the value to be clamped
 | 
			
		||||
     * @return input clamped between 0 and 1.
 | 
			
		||||
     */
 | 
			
		||||
    public static float saturate(float input) {
 | 
			
		||||
        return clamp(input, 0f, 1f);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Determine if two floats are approximately equal.
 | 
			
		||||
     * This takes into account the magnitude of the floats, since
 | 
			
		||||
     * large numbers will have larger differences be close to each other.
 | 
			
		||||
     * <p>
 | 
			
		||||
     * Should return true for a=100000, b=100001, but false for a=10000, b=10001.
 | 
			
		||||
     *
 | 
			
		||||
     * @param a The first float to compare
 | 
			
		||||
     * @param b The second float to compare
 | 
			
		||||
     * @return True if a and b are approximately equal, false otherwise.
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean approximateEquals(float a, float b) {
 | 
			
		||||
        if (a == b) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            return (abs(a - b) / Math.max(abs(a), abs(b))) <= 0.00001f;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Normalizes the specified angle to lie in the interval (-pi,pi] and returns the normalized value in radians.
 | 
			
		||||
     *
 | 
			
		||||
     * @param angle the specified angle in radians
 | 
			
		||||
     */
 | 
			
		||||
    public static float normalizeAngle(float angle) {
 | 
			
		||||
        final float res = angle % TWO_PI;
 | 
			
		||||
        if (res <= -FloatMath.PI) return res + TWO_PI;
 | 
			
		||||
        else if (res > FloatMath.PI) return res - TWO_PI;
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										47
									
								
								Projekte/common/src/main/java/pp/util/FloatPoint.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								Projekte/common/src/main/java/pp/util/FloatPoint.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.util;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A trivial implementation of points in the plane with float coordinates.
 | 
			
		||||
 *
 | 
			
		||||
 * @param x x-coordinate
 | 
			
		||||
 * @param y y-coordinate
 | 
			
		||||
 */
 | 
			
		||||
public record FloatPoint(float x, float y) implements Position {
 | 
			
		||||
    public static final FloatPoint ZERO = new FloatPoint(0f, 0f);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a new FloatPoint object for the given position.
 | 
			
		||||
     *
 | 
			
		||||
     * @param p a position
 | 
			
		||||
     */
 | 
			
		||||
    public FloatPoint(Position p) {
 | 
			
		||||
        this(p.getX(), p.getY());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the x-coordinate.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public float getX() {
 | 
			
		||||
        return x;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the y-coordinate.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public float getY() {
 | 
			
		||||
        return y;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static Position p(float x, float y) {
 | 
			
		||||
        return new FloatPoint(x, y);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										77
									
								
								Projekte/common/src/main/java/pp/util/Interval.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								Projekte/common/src/main/java/pp/util/Interval.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,77 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.util;
 | 
			
		||||
 | 
			
		||||
import static pp.util.FloatMath.ZERO_TOLERANCE;
 | 
			
		||||
import static pp.util.FloatMath.abs;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents an interval. The start value must not be greater than the end value.
 | 
			
		||||
 *
 | 
			
		||||
 * @param from the start value of the interval
 | 
			
		||||
 * @param to   the end value of the interval
 | 
			
		||||
 */
 | 
			
		||||
public record Interval(float from, float to) {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new interval between two specified values.
 | 
			
		||||
     *
 | 
			
		||||
     * @param from the specified start value
 | 
			
		||||
     * @param to   the specified end value
 | 
			
		||||
     */
 | 
			
		||||
    public Interval {
 | 
			
		||||
        if (from > to)
 | 
			
		||||
            throw new IllegalArgumentException(from + " > " + to);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether this interval has length 0, i.e., from and to are equal.
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isEmpty() {
 | 
			
		||||
        return to == from;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether the specified value is contained in this interval. Note that an empty interval may
 | 
			
		||||
     * contain the value if the value is the start and the end value of the interval.
 | 
			
		||||
     *
 | 
			
		||||
     * @param value the specified value to check
 | 
			
		||||
     */
 | 
			
		||||
    public boolean contains(float value) {
 | 
			
		||||
        return from - value <= ZERO_TOLERANCE && value - to <= ZERO_TOLERANCE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether the specified interval is contained as a sub-interval.
 | 
			
		||||
     *
 | 
			
		||||
     * @param other the potential sub-interval
 | 
			
		||||
     */
 | 
			
		||||
    public boolean contains(Interval other) {
 | 
			
		||||
        return from - other.from < ZERO_TOLERANCE && other.to - to < ZERO_TOLERANCE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns a string representation of this interval.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public String toString() {
 | 
			
		||||
        return "[" + from + "; " + to + "]";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether the specified interval is almost equal to this
 | 
			
		||||
     * interval up to the specified epsilon value.
 | 
			
		||||
     *
 | 
			
		||||
     * @param other the other interval to check
 | 
			
		||||
     * @param eps   the allowed epsilon value
 | 
			
		||||
     */
 | 
			
		||||
    public boolean matches(Interval other, float eps) {
 | 
			
		||||
        return abs(from - other.from) < eps &&
 | 
			
		||||
               abs(to - other.to) < eps;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										84
									
								
								Projekte/common/src/main/java/pp/util/Position.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								Projekte/common/src/main/java/pp/util/Position.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,84 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.util;
 | 
			
		||||
 | 
			
		||||
import static pp.util.FloatMath.sqrt;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Interface for all objects that provide a position in the plane.
 | 
			
		||||
 */
 | 
			
		||||
public interface Position extends Comparable<Position> {
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the x-coordinate of the position
 | 
			
		||||
     *
 | 
			
		||||
     * @return x-coordinate as float
 | 
			
		||||
     */
 | 
			
		||||
    float getX();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the y-coordinate of the position
 | 
			
		||||
     *
 | 
			
		||||
     * @return y-coordinate as float
 | 
			
		||||
     */
 | 
			
		||||
    float getY();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the distance of this position from the specified position.
 | 
			
		||||
     *
 | 
			
		||||
     * @param x x-coordinate of the position
 | 
			
		||||
     * @param y y-coordinate of the position
 | 
			
		||||
     * @return distance
 | 
			
		||||
     */
 | 
			
		||||
    default float distanceTo(float x, float y) {
 | 
			
		||||
        return sqrt(distanceSquaredTo(x, y));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the distance of this position from the specified position.
 | 
			
		||||
     * This is just a convenience method for {@linkplain #distanceTo(float, float)}.
 | 
			
		||||
     *
 | 
			
		||||
     * @param other the other position
 | 
			
		||||
     * @return distance
 | 
			
		||||
     */
 | 
			
		||||
    default float distanceTo(Position other) {
 | 
			
		||||
        return distanceTo(other.getX(), other.getY());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the squared distance of this position from the specified position.
 | 
			
		||||
     *
 | 
			
		||||
     * @param x x-coordinate of the position
 | 
			
		||||
     * @param y y-coordinate of the position
 | 
			
		||||
     * @return squared distance
 | 
			
		||||
     */
 | 
			
		||||
    default float distanceSquaredTo(float x, float y) {
 | 
			
		||||
        final float dx = getX() - x;
 | 
			
		||||
        final float dy = getY() - y;
 | 
			
		||||
        return dx * dx + dy * dy;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the squared distance of this position from the specified position.
 | 
			
		||||
     *
 | 
			
		||||
     * @param p the other position
 | 
			
		||||
     * @return squared distance
 | 
			
		||||
     */
 | 
			
		||||
    default float distanceSquaredTo(Position p) {
 | 
			
		||||
        return distanceSquaredTo(p.getX(), p.getY());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Compares positions in the plane from top to bottom
 | 
			
		||||
     * (y coordinates grow downwards) and then from left ro right.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    default int compareTo(Position other) {
 | 
			
		||||
        final int c = Float.compare(getY(), other.getY());
 | 
			
		||||
        return c != 0 ? c : Float.compare(getX(), other.getX());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										30
									
								
								Projekte/common/src/main/java/pp/util/PreferencesUtils.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								Projekte/common/src/main/java/pp/util/PreferencesUtils.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// 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.prefs.Preferences;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A class with convenience methods for preferences.
 | 
			
		||||
 */
 | 
			
		||||
public class PreferencesUtils {
 | 
			
		||||
    private PreferencesUtils() {
 | 
			
		||||
        // don't instantiate
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns a preferences node for the specified class object. The path of the
 | 
			
		||||
     * preference node corresponds to the fully qualified name of the class.
 | 
			
		||||
     *
 | 
			
		||||
     * @param clazz a class object
 | 
			
		||||
     * @return a preference node for the specified class
 | 
			
		||||
     */
 | 
			
		||||
    public static Preferences getPreferences(Class<?> clazz) {
 | 
			
		||||
        return Preferences.userNodeForPackage(clazz).node(clazz.getSimpleName());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,90 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// 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.HashMap;
 | 
			
		||||
import java.util.Iterator;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.NoSuchElementException;
 | 
			
		||||
import java.util.Random;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * An iterator that creates a random permutation of positions (x, y) where x and y are integer values
 | 
			
		||||
 * in the range {0, ..., width-1} x {0, ..., height-1}. All permutations are uniformly distributed
 | 
			
		||||
 * using the Fisher–Yates shuffle (also known as Knuth shuffle).
 | 
			
		||||
 *
 | 
			
		||||
 * @param <T> the type of elements returned by this iterator
 | 
			
		||||
 */
 | 
			
		||||
public class RandomPositionIterator<T> implements Iterator<T> {
 | 
			
		||||
    private final Random random = new Random();
 | 
			
		||||
    private final int height;
 | 
			
		||||
    private final Map<Integer, T> movedMap = new HashMap<>();
 | 
			
		||||
    private int remaining;
 | 
			
		||||
    private final Creator<T> creator;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Functional interface to create instances of type T.
 | 
			
		||||
     *
 | 
			
		||||
     * @param <T> the type of elements created by this creator
 | 
			
		||||
     */
 | 
			
		||||
    public interface Creator<T> {
 | 
			
		||||
        T create(int x, int y);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a RandomPositionIterator for Position instances with float coordinates.
 | 
			
		||||
     *
 | 
			
		||||
     * @param width  the width of the rectangle
 | 
			
		||||
     * @param height the height of the rectangle
 | 
			
		||||
     * @return a RandomPositionIterator for Position instances
 | 
			
		||||
     */
 | 
			
		||||
    public static RandomPositionIterator<Position> floatPoints(int width, int height) {
 | 
			
		||||
        return new RandomPositionIterator<>(FloatPoint::new, width, height);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new permutation iterator generating a random permutation of positions (x, y)
 | 
			
		||||
     * where x and y are integer values in the range {0, ..., width-1} x {0, ..., height-1}.
 | 
			
		||||
     *
 | 
			
		||||
     * @param creator the creator to create instances of type T
 | 
			
		||||
     * @param width   the width of the rectangle
 | 
			
		||||
     * @param height  the height of the rectangle
 | 
			
		||||
     */
 | 
			
		||||
    public RandomPositionIterator(Creator<T> creator, int width, int height) {
 | 
			
		||||
        this.height = height;
 | 
			
		||||
        this.remaining = width * height;
 | 
			
		||||
        this.creator = creator;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean hasNext() {
 | 
			
		||||
        return remaining > 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public T next() {
 | 
			
		||||
        if (hasNext()) {
 | 
			
		||||
            final int idx = random.nextInt(remaining--); // note that remaining is decremented
 | 
			
		||||
            final T result = getWhere(idx);
 | 
			
		||||
            if (idx < remaining)
 | 
			
		||||
                movedMap.put(idx, getWhere(remaining));
 | 
			
		||||
            movedMap.remove(remaining);
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
        throw new NoSuchElementException();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private T getWhere(int idx) {
 | 
			
		||||
        final T movedWhere = movedMap.get(idx);
 | 
			
		||||
        if (movedWhere != null)
 | 
			
		||||
            return movedWhere;
 | 
			
		||||
        final int x = idx / height;
 | 
			
		||||
        final int y = idx % height;
 | 
			
		||||
        return creator.create(x, y);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								Projekte/common/src/main/java/pp/util/Segment.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								Projekte/common/src/main/java/pp/util/Segment.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.util;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A directed straight line segment between two positions in the plane.
 | 
			
		||||
 *
 | 
			
		||||
 * @param from the start position of the segment
 | 
			
		||||
 * @param to   the end position of the segment
 | 
			
		||||
 */
 | 
			
		||||
public record Segment(Position from, Position to) implements SegmentLike {}
 | 
			
		||||
							
								
								
									
										396
									
								
								Projekte/common/src/main/java/pp/util/SegmentLike.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										396
									
								
								Projekte/common/src/main/java/pp/util/SegmentLike.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,396 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.util;
 | 
			
		||||
 | 
			
		||||
import static java.lang.Float.max;
 | 
			
		||||
import static java.lang.Float.min;
 | 
			
		||||
import static pp.util.FloatMath.FLT_EPSILON;
 | 
			
		||||
import static pp.util.FloatMath.ZERO_TOLERANCE;
 | 
			
		||||
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.sqr;
 | 
			
		||||
import static pp.util.FloatMath.sqrt;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Interface of geometrical objects like segments, i.e., having a start and an end position.
 | 
			
		||||
 */
 | 
			
		||||
public interface SegmentLike {
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the start position of the segment.
 | 
			
		||||
     */
 | 
			
		||||
    Position from();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the end position of the segment.
 | 
			
		||||
     */
 | 
			
		||||
    Position to();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the length, i.e., the distance between the start and the end point of this segment.
 | 
			
		||||
     *
 | 
			
		||||
     * @return length of the line segment
 | 
			
		||||
     */
 | 
			
		||||
    default float length() {
 | 
			
		||||
        return sqrt(lengthSquared());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the length squared where the length is the distance between the start and the
 | 
			
		||||
     * end point of this segment.
 | 
			
		||||
     *
 | 
			
		||||
     * @return length squared of the line segment
 | 
			
		||||
     */
 | 
			
		||||
    default float lengthSquared() {
 | 
			
		||||
        return lengthSquared(from(), to());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the squared length of the vector between the specified points.
 | 
			
		||||
     */
 | 
			
		||||
    static float lengthSquared(Position from, Position to) {
 | 
			
		||||
        final float dx = to.getX() - from.getX();
 | 
			
		||||
        final float dy = to.getY() - from.getY();
 | 
			
		||||
        return dx * dx + dy * dy;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the length of the vector between the specified points.
 | 
			
		||||
     */
 | 
			
		||||
    static float length(Position from, Position to) {
 | 
			
		||||
        return sqrt(lengthSquared(from, to));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the angle of this line segment with the x-axis.
 | 
			
		||||
     *
 | 
			
		||||
     * @return angle with the x-axis
 | 
			
		||||
     */
 | 
			
		||||
    default float angle() {
 | 
			
		||||
        final float dx = to().getX() - from().getX();
 | 
			
		||||
        final float dy = to().getY() - from().getY();
 | 
			
		||||
        return atan2(dy, dx);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the distance of the specified point from this segment.
 | 
			
		||||
     * The distance is the length of the shortest connection between the specified
 | 
			
		||||
     * point and any point of the line segment.
 | 
			
		||||
     *
 | 
			
		||||
     * @param x x-coordinate of the point
 | 
			
		||||
     * @param y y-coordinate of the point
 | 
			
		||||
     * @return the distance
 | 
			
		||||
     */
 | 
			
		||||
    default float distanceTo(float x, float y) {
 | 
			
		||||
        return distance(from().getX(), from().getY(), to().getX(), to().getY(), x, y);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the distance of the point from the segment between the specified points.
 | 
			
		||||
     * The distance is the length of the shortest connection between the specified
 | 
			
		||||
     * point and any point of the line segment.
 | 
			
		||||
     *
 | 
			
		||||
     * @param from the segment start point
 | 
			
		||||
     * @param to   the segment end point
 | 
			
		||||
     * @param p    the point
 | 
			
		||||
     * @return the distance
 | 
			
		||||
     */
 | 
			
		||||
    static float distance(Position from, Position to, Position p) {
 | 
			
		||||
        return distance(from.getX(), from.getY(), to.getX(), to.getY(), p.getX(), p.getY());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the distance of the point (x,y) from the segment from (x1,y1) to (x2,y2)
 | 
			
		||||
     * The distance is the length of the shortest connection between the specified
 | 
			
		||||
     * point and any point of the line segment.
 | 
			
		||||
     *
 | 
			
		||||
     * @param x1 x-coordinate of the segment start point
 | 
			
		||||
     * @param y1 y-coordinate of the segment start point
 | 
			
		||||
     * @param x2 x-coordinate of the segment end point
 | 
			
		||||
     * @param y2 y-coordinate of the segment end point
 | 
			
		||||
     * @param x  x-coordinate of the point
 | 
			
		||||
     * @param y  y-coordinate of the point
 | 
			
		||||
     * @return the distance
 | 
			
		||||
     */
 | 
			
		||||
    static float distance(float x1, float y1, float x2, float y2, float x, float y) {
 | 
			
		||||
        final float dx = x2 - x1;
 | 
			
		||||
        final float dy = y2 - y1;
 | 
			
		||||
        final float dx1 = x - x1;
 | 
			
		||||
        final float dy1 = y - y1;
 | 
			
		||||
        if (dx * dx1 + dy * dy1 <= 0f)
 | 
			
		||||
            return sqrt(dx1 * dx1 + dy1 * dy1);
 | 
			
		||||
        final float dx2 = x - x2;
 | 
			
		||||
        final float dy2 = y - y2;
 | 
			
		||||
        if (dx * dx2 + dy * dy2 >= 0f)
 | 
			
		||||
            return sqrt(dx2 * dx2 + dy2 * dy2);
 | 
			
		||||
        final float len = sqrt(dx * dx + dy * dy);
 | 
			
		||||
        return FloatMath.abs(dx1 * dy - dy1 * dx) / len;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the distance of the specified position from this segment.
 | 
			
		||||
     * This is just a convenience method for {@linkplain #distanceTo(float, float)}.
 | 
			
		||||
     *
 | 
			
		||||
     * @param pos a position
 | 
			
		||||
     * @return the distance
 | 
			
		||||
     */
 | 
			
		||||
    default float distanceTo(Position pos) {
 | 
			
		||||
        return distanceTo(pos.getX(), pos.getY());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the point of this segment with the specified quotient, i.e., q*from()+(1-q)*to().
 | 
			
		||||
     *
 | 
			
		||||
     * @param q the quotient
 | 
			
		||||
     */
 | 
			
		||||
    default Position pointAt(float q) {
 | 
			
		||||
        if (q == 0f) return from();
 | 
			
		||||
        if (q == 1f) return to();
 | 
			
		||||
        return new FloatPoint((1f - q) * from().getX() + q * to().getX(),
 | 
			
		||||
                              (1f - q) * from().getY() + q * to().getY());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Shoots a ray from the specified position in the direction of the specified angle and returns the distance
 | 
			
		||||
     * of the specified position from the intersection point of the ray with the straight line determined by the
 | 
			
		||||
     * end points of this segment. Returns {@linkplain Float#NaN} if there is no intersection.
 | 
			
		||||
     *
 | 
			
		||||
     * @param pos   the specified position
 | 
			
		||||
     * @param angle the specified angle
 | 
			
		||||
     */
 | 
			
		||||
    default float dist(Position pos, float angle) {
 | 
			
		||||
        return quotientDist(pos, quotient(pos, angle));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Shoots a ray from the specified position in the direction of the specified angle and returns the distance
 | 
			
		||||
     * of the specified position from the intersection point of the ray with the straight line determined by the
 | 
			
		||||
     * end points of this segment. Returns {@linkplain Float#NaN} if there is no intersection.
 | 
			
		||||
     *
 | 
			
		||||
     * @param pos   the specified position
 | 
			
		||||
     * @param angle the specified angle
 | 
			
		||||
     */
 | 
			
		||||
    default float dist(Position pos, Angle angle) {
 | 
			
		||||
        return quotientDist(pos, quotient(pos, angle.x, angle.y));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Shoots a ray from the specified position in the direction of the point of this segment with the specified
 | 
			
		||||
     * quotient, i.e., the point at q*from()+(1-q)*to(), and returns the distance
 | 
			
		||||
     * of the specified position from the intersection point of the ray with the straight line determined by the
 | 
			
		||||
     * end points of this segment. Returns {@linkplain Float#NaN} if there is no intersection.
 | 
			
		||||
     *
 | 
			
		||||
     * @param pos the specified position
 | 
			
		||||
     * @param q   the specified quotient
 | 
			
		||||
     */
 | 
			
		||||
    default float quotientDist(Position pos, float q) {
 | 
			
		||||
        final float dx = (1f - q) * from().getX() + q * to().getX() - pos.getX();
 | 
			
		||||
        final float dy = (1f - q) * from().getY() + q * to().getY() - pos.getY();
 | 
			
		||||
        return sqrt(dx * dx + dy * dy);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Shoots a ray from the specified position in the direction of the specified angle and returns the
 | 
			
		||||
     * quotient q such that the intersection point of the ray with the straight line determined by the
 | 
			
		||||
     * end points of this segment is at q*from()+(1-q)*to().
 | 
			
		||||
     *
 | 
			
		||||
     * @param pos   the specified position
 | 
			
		||||
     * @param angle the specified angle
 | 
			
		||||
     */
 | 
			
		||||
    default float quotient(Position pos, float angle) {
 | 
			
		||||
        final float ux = cos(angle);
 | 
			
		||||
        final float uy = sin(angle);
 | 
			
		||||
        return quotient(pos, ux, uy);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Shoots a ray from the specified position in the direction of the specified vector and returns the
 | 
			
		||||
     * quotient q such that the intersection point of the ray with the straight line determined by the
 | 
			
		||||
     * end points of this segment is at q*from()+(1-q)*to().
 | 
			
		||||
     *
 | 
			
		||||
     * @param pos the specified position
 | 
			
		||||
     * @param ux  the vectors x value
 | 
			
		||||
     * @param uy  the vectors y value
 | 
			
		||||
     */
 | 
			
		||||
    private float quotient(Position pos, float ux, float uy) {
 | 
			
		||||
        final float nom = nominator(pos, ux, uy);
 | 
			
		||||
        final float det = determinant(ux, uy);
 | 
			
		||||
        // the following is for dealing with floating point imprecision
 | 
			
		||||
        if (abs(det) > FLT_EPSILON)
 | 
			
		||||
            return nom / det;
 | 
			
		||||
        if (abs(nom) > FLT_EPSILON)
 | 
			
		||||
            return Float.NaN;
 | 
			
		||||
        final float q = project(pos);
 | 
			
		||||
        if (q > -FLT_EPSILON && q - 1f < FLT_EPSILON)
 | 
			
		||||
            // pos lies (almost) within the segment
 | 
			
		||||
            return q;
 | 
			
		||||
        final float distFrom = isCandidate(pos, ux, uy, from());
 | 
			
		||||
        final float distTo = isCandidate(pos, ux, uy, to());
 | 
			
		||||
        if (distFrom >= 0f) {
 | 
			
		||||
            if (distTo >= 0f)
 | 
			
		||||
                return distFrom < distTo ? 0f : 1f;
 | 
			
		||||
            else
 | 
			
		||||
                return 0f;
 | 
			
		||||
        }
 | 
			
		||||
        if (distTo >= 0f)
 | 
			
		||||
            return 1f;
 | 
			
		||||
        return Float.NaN;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the determinant of a specified vector.
 | 
			
		||||
     *
 | 
			
		||||
     * @param ux the vectors x value
 | 
			
		||||
     * @param uy the vectors y value
 | 
			
		||||
     */
 | 
			
		||||
    private float determinant(float ux, float uy) {
 | 
			
		||||
        return diffX() * uy - diffY() * ux;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the nominator of the specified vector starting at a specified position.
 | 
			
		||||
     *
 | 
			
		||||
     * @param pos the specified position
 | 
			
		||||
     * @param ux  the vectors x value
 | 
			
		||||
     * @param uy  the vectors y value
 | 
			
		||||
     */
 | 
			
		||||
    private float nominator(Position pos, float ux, float uy) {
 | 
			
		||||
        final float dx = pos.getX() - from().getX();
 | 
			
		||||
        final float dy = pos.getY() - from().getY();
 | 
			
		||||
        return dx * uy - dy * ux;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether the (ux,uy) ray starting at pos hits (or almost hits) target.
 | 
			
		||||
     *
 | 
			
		||||
     * @param pos    the specified start position
 | 
			
		||||
     * @param ux     the rays x value
 | 
			
		||||
     * @param uy     the rays y value
 | 
			
		||||
     * @param target the specified target position
 | 
			
		||||
     */
 | 
			
		||||
    private float isCandidate(Position pos, float ux, float uy, Position target) {
 | 
			
		||||
        final float lambda = lambda(pos, target, ux, uy);
 | 
			
		||||
        if (lambda < -FLT_EPSILON) return -1f;
 | 
			
		||||
        final float dx = target.getX() - pos.getX() - lambda * ux;
 | 
			
		||||
        final float dy = target.getY() - pos.getY() - lambda * uy;
 | 
			
		||||
        return dx * dx + dy * dy;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private float lambda(Position p1, Position p2, float ux, float uy) {
 | 
			
		||||
        return ux * (p2.getX() - p1.getX()) + uy * (p2.getY() - p1.getY());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the quotient q such that the specified point projected onto this
 | 
			
		||||
     * segment is at q*from()+(1-q)*to().
 | 
			
		||||
     *
 | 
			
		||||
     * @param pos the specified points position
 | 
			
		||||
     */
 | 
			
		||||
    default float project(Position pos) {
 | 
			
		||||
        return ((pos.getX() - from().getX()) * diffX() + (pos.getY() - from().getY()) * diffY()) / lengthSquared();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the interval of quotients between leftAngle and rightAngle
 | 
			
		||||
     * looking from the specified position. The starting point of the
 | 
			
		||||
     * segment must be left of its end point when looking from the
 | 
			
		||||
     * specified position.
 | 
			
		||||
     *
 | 
			
		||||
     * @param pos        the specified position to look from
 | 
			
		||||
     * @param leftAngle  the specified left angle
 | 
			
		||||
     * @param rightAngle the specified right angle
 | 
			
		||||
     */
 | 
			
		||||
    default Interval interval(Position pos, Angle leftAngle, Angle rightAngle) {
 | 
			
		||||
        final float nomLeft = nominator(pos, leftAngle.x, leftAngle.y);
 | 
			
		||||
        final float detLeft = determinant(leftAngle.x, leftAngle.y);
 | 
			
		||||
        final float nomRight = nominator(pos, rightAngle.x, rightAngle.y);
 | 
			
		||||
        final float detRight = determinant(rightAngle.x, rightAngle.y);
 | 
			
		||||
        if (abs(detLeft) <= FLT_EPSILON || abs(detRight) <= FLT_EPSILON)
 | 
			
		||||
            return new Interval(0f, 0f);
 | 
			
		||||
        final float q1 = nomLeft / detLeft;
 | 
			
		||||
        final float q2 = nomRight / detRight;
 | 
			
		||||
        if (q1 > q2)
 | 
			
		||||
            return new Interval(0f, 0f);
 | 
			
		||||
        final float lower = q1 < ZERO_TOLERANCE ? 0f : min(1f, q1);
 | 
			
		||||
        final float upper = q2 > 1f - ZERO_TOLERANCE ? 1f : max(0f, q2);
 | 
			
		||||
        return new Interval(lower, upper);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the x-coordinate of the vector from the start to the end point.
 | 
			
		||||
     */
 | 
			
		||||
    default float diffX() {
 | 
			
		||||
        return to().getX() - from().getX();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the y-coordinate of the vector from the start to the end point.
 | 
			
		||||
     */
 | 
			
		||||
    default float diffY() {
 | 
			
		||||
        return to().getY() - from().getY();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Computes the determinant of the matrix whose first column vector is this segment and the
 | 
			
		||||
     * second column vector is the specified segment.
 | 
			
		||||
     *
 | 
			
		||||
     * @param other the specified segment
 | 
			
		||||
     */
 | 
			
		||||
    default float determinantWith(SegmentLike other) {
 | 
			
		||||
        return diffX() * other.diffY() - diffY() * other.diffX();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Computes the square of the minimal distance between this and the specified segment.
 | 
			
		||||
     *
 | 
			
		||||
     * @param other other segment
 | 
			
		||||
     * @return squared distance
 | 
			
		||||
     */
 | 
			
		||||
    default float minDistanceSquared(SegmentLike other) {
 | 
			
		||||
        final float rx = other.from().getX() - from().getX();
 | 
			
		||||
        final float ry = other.from().getY() - from().getY();
 | 
			
		||||
        final float ux = diffX();
 | 
			
		||||
        final float uy = diffY();
 | 
			
		||||
        final float vx = other.diffX();
 | 
			
		||||
        final float vy = other.diffY();
 | 
			
		||||
 | 
			
		||||
        final float ru = rx * ux + ry * uy;
 | 
			
		||||
        final float rv = rx * vx + ry * vy;
 | 
			
		||||
        final float uu = ux * ux + uy * uy;
 | 
			
		||||
        final float uv = ux * vx + uy * vy;
 | 
			
		||||
        final float vv = vx * vx + vy * vy;
 | 
			
		||||
 | 
			
		||||
        if (uu < ZERO_TOLERANCE) { // this segment is in fact a single point
 | 
			
		||||
            if (vv < ZERO_TOLERANCE) // other is a point, too
 | 
			
		||||
                return rx * rx + ry * ry;
 | 
			
		||||
            else
 | 
			
		||||
                return sqr(other.distanceTo(from()));
 | 
			
		||||
        }
 | 
			
		||||
        if (vv < ZERO_TOLERANCE) // other is in fact a point
 | 
			
		||||
            return sqr(distanceTo(other.from()));
 | 
			
		||||
 | 
			
		||||
        final float det = uu * vv - uv * uv;
 | 
			
		||||
        final float s;
 | 
			
		||||
        final float t;
 | 
			
		||||
 | 
			
		||||
        if (det < ZERO_TOLERANCE * uu * vv) {
 | 
			
		||||
            s = min(max(ru / uu, 0f), 1f);
 | 
			
		||||
            t = 0f;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            s = min(max((ru * vv - rv * uv) / det, 0f), 1f);
 | 
			
		||||
            t = min(max((ru * uv - rv * uu) / det, 0f), 1f);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        final float mu1 = min(max((t * uv + ru) / uu, 0f), 1f);
 | 
			
		||||
        final float mu2 = min(max((s * uv - rv) / vv, 0f), 1f);
 | 
			
		||||
 | 
			
		||||
        return pointAt(mu1).distanceSquaredTo(other.pointAt(mu2));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										90
									
								
								Projekte/common/src/main/java/pp/util/Util.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								Projekte/common/src/main/java/pp/util/Util.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,90 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// 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.ArrayList;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A class with auxiliary functions.
 | 
			
		||||
 */
 | 
			
		||||
public class Util {
 | 
			
		||||
    private Util() { /* do not instantiate */ }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Calculates and returns the area of a polygon defined by a list of points, using the shoelace formula.
 | 
			
		||||
     * The result is positive if the sequence of vertices is in clockwise order, and negative
 | 
			
		||||
     * otherwise.
 | 
			
		||||
     *
 | 
			
		||||
     * @param points A list of positions that define the vertices of the polygon in planar coordinates.
 | 
			
		||||
     * @return The calculated area of the polygon.
 | 
			
		||||
     */
 | 
			
		||||
    public static float getArea(List<? extends Position> points) {
 | 
			
		||||
        float sum = 0;
 | 
			
		||||
        Position prev = getLast(points);
 | 
			
		||||
        for (var next : points) {
 | 
			
		||||
            sum += prev.getX() * next.getY() - next.getX() * prev.getY();
 | 
			
		||||
            prev = next;
 | 
			
		||||
        }
 | 
			
		||||
        return 0.5f * sum;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the last element of the given list.
 | 
			
		||||
     *
 | 
			
		||||
     * @param list the list from which to retrieve the last element
 | 
			
		||||
     * @param <T>  the type of elements in the list
 | 
			
		||||
     * @return the last element of the list
 | 
			
		||||
     * @throws IndexOutOfBoundsException if the list is empty
 | 
			
		||||
     */
 | 
			
		||||
    public static <T> T getLast(List<T> list) {
 | 
			
		||||
        return list.get(list.size() - 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reverses the order of elements in the given list.
 | 
			
		||||
     *
 | 
			
		||||
     * @param list the list to be reversed
 | 
			
		||||
     * @param <T>  the type of elements in the list
 | 
			
		||||
     * @return a new list with elements in reversed order
 | 
			
		||||
     */
 | 
			
		||||
    public static <T> List<T> reverse(List<T> list) {
 | 
			
		||||
        final List<T> reversed = new ArrayList<>(list);
 | 
			
		||||
        Collections.reverse(reversed);
 | 
			
		||||
        return reversed;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a copy of the given list.
 | 
			
		||||
     *
 | 
			
		||||
     * @param list the list to be copied, may be null
 | 
			
		||||
     * @param <T>  the type of elements in the list
 | 
			
		||||
     * @return a new list containing the elements of the original list, or null if the original list is null
 | 
			
		||||
     */
 | 
			
		||||
    public static <T> List<T> copy(List<T> list) {
 | 
			
		||||
        return list == null ? null : new ArrayList<>(list);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds an element to a set and returns a new set containing the original elements and the new element.
 | 
			
		||||
     *
 | 
			
		||||
     * @param set     the original set, must not be null
 | 
			
		||||
     * @param element the element to be added to the set
 | 
			
		||||
     * @param <T>     the type of elements in the set
 | 
			
		||||
     * @param <E>     the type of the element being added, must extend T
 | 
			
		||||
     * @return a new set containing the original elements and the new element
 | 
			
		||||
     */
 | 
			
		||||
    public static <T, E extends T> Set<T> add(Set<T> set, E element) {
 | 
			
		||||
        final Set<T> newSet = new HashSet<>(set);
 | 
			
		||||
        newSet.add(element);
 | 
			
		||||
        return newSet;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										286
									
								
								Projekte/common/src/main/java/pp/util/config/Config.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										286
									
								
								Projekte/common/src/main/java/pp/util/config/Config.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,286 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.util.config;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.FileReader;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.Reader;
 | 
			
		||||
import java.lang.System.Logger;
 | 
			
		||||
import java.lang.System.Logger.Level;
 | 
			
		||||
import java.lang.annotation.Documented;
 | 
			
		||||
import java.lang.annotation.Retention;
 | 
			
		||||
import java.lang.annotation.Target;
 | 
			
		||||
import java.lang.reflect.Array;
 | 
			
		||||
import java.lang.reflect.Field;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Properties;
 | 
			
		||||
import java.util.function.Function;
 | 
			
		||||
 | 
			
		||||
import static java.lang.annotation.ElementType.FIELD;
 | 
			
		||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Abstract base class for representing configurations that can be read from properties files.
 | 
			
		||||
 * Subclasses can define fields annotated with {@link Property} to specify the configuration keys
 | 
			
		||||
 * and optionally {@link Separator} to specify custom separators for array values.
 | 
			
		||||
 */
 | 
			
		||||
public abstract class Config {
 | 
			
		||||
    private static final String BLANK_SEQ = " *";
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Annotation for specifying the property key for a field.
 | 
			
		||||
     */
 | 
			
		||||
    @Retention(RUNTIME)
 | 
			
		||||
    @Target(FIELD)
 | 
			
		||||
    @Documented
 | 
			
		||||
    protected @interface Property {
 | 
			
		||||
        /**
 | 
			
		||||
         * The key of the property.
 | 
			
		||||
         */
 | 
			
		||||
        String value();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Annotation for specifying a custom separator for array values.
 | 
			
		||||
     */
 | 
			
		||||
    @Retention(RUNTIME)
 | 
			
		||||
    @Target(FIELD)
 | 
			
		||||
    @Documented
 | 
			
		||||
    protected @interface Separator {
 | 
			
		||||
        /**
 | 
			
		||||
         * The separator for array values.
 | 
			
		||||
         */
 | 
			
		||||
        String value();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static final Logger LOGGER = System.getLogger(Config.class.getName());
 | 
			
		||||
    private static final Map<Class<?>, Function<String, ?>> CONVERTER_MAP = new HashMap<>();
 | 
			
		||||
 | 
			
		||||
    static {
 | 
			
		||||
        CONVERTER_MAP.put(String.class, x -> x);
 | 
			
		||||
        CONVERTER_MAP.put(byte.class, Byte::parseByte);
 | 
			
		||||
        CONVERTER_MAP.put(short.class, Short::parseShort);
 | 
			
		||||
        CONVERTER_MAP.put(int.class, Integer::parseInt);
 | 
			
		||||
        CONVERTER_MAP.put(long.class, Long::parseLong);
 | 
			
		||||
        CONVERTER_MAP.put(boolean.class, Boolean::parseBoolean);
 | 
			
		||||
        CONVERTER_MAP.put(float.class, Float::parseFloat);
 | 
			
		||||
        CONVERTER_MAP.put(double.class, Double::parseDouble);
 | 
			
		||||
        CONVERTER_MAP.put(Byte.class, Byte::parseByte);
 | 
			
		||||
        CONVERTER_MAP.put(Short.class, Short::parseShort);
 | 
			
		||||
        CONVERTER_MAP.put(Integer.class, Integer::parseInt);
 | 
			
		||||
        CONVERTER_MAP.put(Long.class, Long::parseLong);
 | 
			
		||||
        CONVERTER_MAP.put(Boolean.class, Boolean::parseBoolean);
 | 
			
		||||
        CONVERTER_MAP.put(Float.class, Float::parseFloat);
 | 
			
		||||
        CONVERTER_MAP.put(Double.class, Double::parseDouble);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reads the specified properties file and sets the values of this config using {@link #readFrom(Properties)}.
 | 
			
		||||
     *
 | 
			
		||||
     * @param file the properties file to read
 | 
			
		||||
     * @throws IOException if an I/O error occurs
 | 
			
		||||
     * @see #readFrom(Properties)
 | 
			
		||||
     */
 | 
			
		||||
    public void readFrom(File file) throws IOException {
 | 
			
		||||
        try (Reader reader = new FileReader(file)) {
 | 
			
		||||
            final Properties properties = new Properties();
 | 
			
		||||
            properties.load(reader);
 | 
			
		||||
            readFrom(properties);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the values of fields annotated with {@link Property} using the specified properties.
 | 
			
		||||
     * Array fields can be split into components using the default separator (",") or a custom separator
 | 
			
		||||
     * specified with {@link Separator}.
 | 
			
		||||
     *
 | 
			
		||||
     * @param props the properties to read from
 | 
			
		||||
     */
 | 
			
		||||
    public void readFrom(Properties props) {
 | 
			
		||||
        for (Class<?> clazz = getClass(); Config.class.isAssignableFrom(clazz); clazz = clazz.getSuperclass()) {
 | 
			
		||||
            for (Field field : clazz.getDeclaredFields()) {
 | 
			
		||||
                final Property keyAnnot = field.getAnnotation(Property.class);
 | 
			
		||||
                if (keyAnnot != null && props.containsKey(keyAnnot.value())) {
 | 
			
		||||
                    try {
 | 
			
		||||
                        final String text = props.getProperty(keyAnnot.value());
 | 
			
		||||
                        final Object value = createValue(text, field);
 | 
			
		||||
                        setField(field, value);
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (IllegalAccessException ex) {
 | 
			
		||||
                        LOGGER.log(Level.ERROR, "Cannot access " + field, ex); //NON-NLS
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reads the specified properties file and sets the values of this config if the file exists,
 | 
			
		||||
     * otherwise uses default values. This method is a convenience version of {@link #readFrom(File)}
 | 
			
		||||
     * that checks the existence of the specified file and does nothing if the file does not exist.
 | 
			
		||||
     *
 | 
			
		||||
     * @param file the properties file to read, if it exists
 | 
			
		||||
     */
 | 
			
		||||
    public void readFromIfExists(File file) {
 | 
			
		||||
        if (!file.exists()) {
 | 
			
		||||
            LOGGER.log(Level.INFO, "There is no config file {0}; using default configuration", //NON-NLS
 | 
			
		||||
                       file.getAbsolutePath());
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        try {
 | 
			
		||||
            readFrom(file);
 | 
			
		||||
            LOGGER.log(Level.INFO, "Successfully read config from {0}", file.getAbsolutePath()); //NON-NLS
 | 
			
		||||
        }
 | 
			
		||||
        catch (IOException e) {
 | 
			
		||||
            LOGGER.log(Level.WARNING, "Cannot read config file " + file.getAbsolutePath(), e); //NON-NLS
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Converts a string value from the properties file into an object that can be assigned to the specified field.
 | 
			
		||||
     * For array fields, the string value is first split into components.
 | 
			
		||||
     *
 | 
			
		||||
     * @param value the string value to convert
 | 
			
		||||
     * @param field the field to set with the converted value
 | 
			
		||||
     * @return an object of the appropriate type for the field
 | 
			
		||||
     */
 | 
			
		||||
    private Object createValue(String value, Field field) {
 | 
			
		||||
        if (!field.getType().isArray())
 | 
			
		||||
            return convertToType(value, field.getType());
 | 
			
		||||
        // the field is an array
 | 
			
		||||
        final Separator sepAnn = field.getDeclaredAnnotation(Separator.class);
 | 
			
		||||
        final String sep = sepAnn == null ? "," : sepAnn.value();
 | 
			
		||||
        final String[] split = value.split(BLANK_SEQ + sep + BLANK_SEQ, -1);
 | 
			
		||||
        final Object array = Array.newInstance(field.getType().componentType(), split.length);
 | 
			
		||||
        for (int i = 0; i < split.length; i++)
 | 
			
		||||
            Array.set(array, i, convertToType(split[i], field.getType().componentType()));
 | 
			
		||||
        return array;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Converts a string value into an object of the specified type.
 | 
			
		||||
     *
 | 
			
		||||
     * @param value      the string value to convert
 | 
			
		||||
     * @param targetType the target type to convert to
 | 
			
		||||
     * @return an object of the specified type
 | 
			
		||||
     */
 | 
			
		||||
    protected Object convertToType(String value, Class<?> targetType) {
 | 
			
		||||
        Function<String, ?> handler = CONVERTER_MAP.get(targetType);
 | 
			
		||||
        if (handler != null)
 | 
			
		||||
            return handler.apply(value);
 | 
			
		||||
        throw new IllegalArgumentException("Cannot translate " + value + " to " + targetType);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns a string representation of the configuration object, including all properties and their values.
 | 
			
		||||
     *
 | 
			
		||||
     * @return a string representation of the configuration object
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public String toString() {
 | 
			
		||||
        final List<String> propertyStrings = getPropertyStrings();
 | 
			
		||||
        propertyStrings.sort(String.CASE_INSENSITIVE_ORDER);
 | 
			
		||||
        return "[\n" + String.join(",\n", propertyStrings) + "\n]";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Retrieves all property strings of the configuration object.
 | 
			
		||||
     *
 | 
			
		||||
     * @return a list of property strings
 | 
			
		||||
     */
 | 
			
		||||
    private List<String> getPropertyStrings() {
 | 
			
		||||
        final List<String> propertyStrings = new ArrayList<>();
 | 
			
		||||
        for (Class<?> clazz = getClass(); Config.class.isAssignableFrom(clazz); clazz = clazz.getSuperclass()) {
 | 
			
		||||
            for (Field field : clazz.getDeclaredFields()) {
 | 
			
		||||
                final String stringRepresentation = getStringRepresentation(field);
 | 
			
		||||
                if (stringRepresentation != null)
 | 
			
		||||
                    propertyStrings.add(stringRepresentation);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return propertyStrings;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Retrieves the string representation of a field annotated with {@link Property}.
 | 
			
		||||
     *
 | 
			
		||||
     * @param field the field to retrieve the string representation for
 | 
			
		||||
     * @return the string representation of the field, or null if the field is not annotated with {@link Property}
 | 
			
		||||
     */
 | 
			
		||||
    private String getStringRepresentation(Field field) {
 | 
			
		||||
        final Property keyAnnotation = field.getAnnotation(Property.class);
 | 
			
		||||
        if (keyAnnotation != null) {
 | 
			
		||||
            try {
 | 
			
		||||
                final Object fieldValue = getField(field);
 | 
			
		||||
                final String valueString = asString(fieldValue);
 | 
			
		||||
                return keyAnnotation.value() + " -> " + field.getName() + " = " + valueString;
 | 
			
		||||
            }
 | 
			
		||||
            catch (IllegalAccessException e) {
 | 
			
		||||
                LOGGER.log(Level.ERROR, "Cannot access " + field, e); //NON-NLS
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Converts an object to its string representation. For arrays, string representations of their components are produced.
 | 
			
		||||
     *
 | 
			
		||||
     * @param value the object to convert
 | 
			
		||||
     * @return the string representation of the object
 | 
			
		||||
     */
 | 
			
		||||
    private String asString(Object value) {
 | 
			
		||||
        if (value == null)
 | 
			
		||||
            return "null"; //NON-NLS
 | 
			
		||||
        if (!value.getClass().isArray())
 | 
			
		||||
            return value.toString();
 | 
			
		||||
        final int length = Array.getLength(value);
 | 
			
		||||
        final List<String> components = new ArrayList<>(length);
 | 
			
		||||
        for (int i = 0; i < length; i++) {
 | 
			
		||||
            final Object component = Array.get(value, i);
 | 
			
		||||
            components.add(asString(component));
 | 
			
		||||
        }
 | 
			
		||||
        return "{" + String.join(", ", components) + "}";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the value of a field, making it accessible if necessary.
 | 
			
		||||
     *
 | 
			
		||||
     * @param field the field to set
 | 
			
		||||
     * @param value the value to set
 | 
			
		||||
     * @throws IllegalAccessException if the field cannot be accessed
 | 
			
		||||
     */
 | 
			
		||||
    private void setField(Field field, Object value) throws IllegalAccessException {
 | 
			
		||||
        boolean inaccessible = !field.canAccess(this);
 | 
			
		||||
        if (inaccessible)
 | 
			
		||||
            field.setAccessible(true);
 | 
			
		||||
        field.set(this, value);
 | 
			
		||||
        if (inaccessible)
 | 
			
		||||
            field.setAccessible(false);
 | 
			
		||||
        LOGGER.log(Level.TRACE, "Set {0} to {1}", field, value); //NON-NLS
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Retrieves the value of a field, making it accessible if necessary.
 | 
			
		||||
     *
 | 
			
		||||
     * @param field the field to retrieve the value from
 | 
			
		||||
     * @return the value of the field
 | 
			
		||||
     * @throws IllegalAccessException if the field cannot be accessed
 | 
			
		||||
     */
 | 
			
		||||
    private Object getField(Field field) throws IllegalAccessException {
 | 
			
		||||
        boolean inaccessible = !field.canAccess(this);
 | 
			
		||||
        if (inaccessible)
 | 
			
		||||
            field.setAccessible(true);
 | 
			
		||||
        final Object value = field.get(this);
 | 
			
		||||
        if (inaccessible)
 | 
			
		||||
            field.setAccessible(false);
 | 
			
		||||
        return value;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										109
									
								
								Projekte/common/src/test/java/pp/util/AngleTest.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								Projekte/common/src/test/java/pp/util/AngleTest.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,109 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.util;
 | 
			
		||||
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
import static java.lang.Math.min;
 | 
			
		||||
import static org.junit.Assert.assertEquals;
 | 
			
		||||
import static pp.util.FloatMath.DEG_TO_RAD;
 | 
			
		||||
import static pp.util.FloatMath.ZERO_TOLERANCE;
 | 
			
		||||
import static pp.util.FloatMath.cos;
 | 
			
		||||
import static pp.util.FloatMath.sin;
 | 
			
		||||
 | 
			
		||||
public class AngleTest {
 | 
			
		||||
    @Test
 | 
			
		||||
    public void compareAngles() {
 | 
			
		||||
        for (int i = 0; i < 360; i++) {
 | 
			
		||||
            final Angle u = Angle.fromDegrees(i);
 | 
			
		||||
            for (int j = 0; j < 360; j++) {
 | 
			
		||||
                final Angle v = Angle.fromDegrees(j);
 | 
			
		||||
                assertEquals("compare " + i + "° and " + j + "°", Integer.compare(i, j), (Object) u.compareTo(v));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void addAngles() {
 | 
			
		||||
        for (int i = 0; i < 360; i++) {
 | 
			
		||||
            final Angle u = Angle.fromDegrees(i);
 | 
			
		||||
            for (int j = 0; j < 360; j++) {
 | 
			
		||||
                final Angle v = Angle.fromDegrees(j);
 | 
			
		||||
                final Angle sum = u.plus(v);
 | 
			
		||||
                assertEquals(i + "° + " + j + "°, x coordinate", cos((i + j) * DEG_TO_RAD), sum.x, ZERO_TOLERANCE);
 | 
			
		||||
                assertEquals(i + "° + " + j + "°, y coordinate", sin((i + j) * DEG_TO_RAD), sum.y, ZERO_TOLERANCE);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void subtractAngles() {
 | 
			
		||||
        for (int i = 0; i < 360; i++) {
 | 
			
		||||
            final Angle u = Angle.fromDegrees(i);
 | 
			
		||||
            for (int j = 0; j < 360; j++) {
 | 
			
		||||
                final Angle v = Angle.fromDegrees(j);
 | 
			
		||||
                final Angle diff = u.minus(v);
 | 
			
		||||
                assertEquals(i + "° - " + j + "°, x coordinate", cos((i - j) * DEG_TO_RAD), diff.x, ZERO_TOLERANCE);
 | 
			
		||||
                assertEquals(i + "° - " + j + "°, y coordinate", sin((i - j) * DEG_TO_RAD), diff.y, ZERO_TOLERANCE);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void minAngle() {
 | 
			
		||||
        for (int i = 0; i < 360; i++) {
 | 
			
		||||
            final Angle u = Angle.fromDegrees(i);
 | 
			
		||||
            for (int j = 0; j < 360; j++) {
 | 
			
		||||
                final Angle v = Angle.fromDegrees(j);
 | 
			
		||||
                final Angle diff = Angle.min(u, v);
 | 
			
		||||
                assertEquals(i + "° - " + j + "°, x coordinate", cos(min(i, j) * DEG_TO_RAD), diff.x, ZERO_TOLERANCE);
 | 
			
		||||
                assertEquals(i + "° - " + j + "°, y coordinate", sin(min(i, j) * DEG_TO_RAD), diff.y, ZERO_TOLERANCE);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void bisector() {
 | 
			
		||||
        for (int right = 0; right < 360; right++) {
 | 
			
		||||
            final Angle rightAngle = Angle.fromDegrees(right);
 | 
			
		||||
            for (int add = 0; add < 360; add++) {
 | 
			
		||||
                final int left = right + add;
 | 
			
		||||
                final Angle bisector = Angle.fromDegrees(left).bisector(rightAngle);
 | 
			
		||||
                final float exp = (right + 0.5f * add) * DEG_TO_RAD;
 | 
			
		||||
                assertEquals("left=" + left + "° / right=" + right + "°, x coordinate", cos(exp), bisector.x, ZERO_TOLERANCE);
 | 
			
		||||
                assertEquals("left=" + left + "° / right=" + right + "°, y coordinate", sin(exp), bisector.y, ZERO_TOLERANCE);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void leftOf() {
 | 
			
		||||
        for (int right = 0; right < 360; right++) {
 | 
			
		||||
            final Angle rightAngle = Angle.fromDegrees(right);
 | 
			
		||||
            for (int add = 1; add < 360; add++)
 | 
			
		||||
                if (add != 180) {
 | 
			
		||||
                    final int left = right + add;
 | 
			
		||||
                    final Angle leftAngle = Angle.fromDegrees(left);
 | 
			
		||||
                    assertEquals(left + "° left of " + right + "°", add < 180, leftAngle.leftOf(rightAngle));
 | 
			
		||||
                }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void rightOf() {
 | 
			
		||||
        for (int right = 0; right < 360; right++) {
 | 
			
		||||
            final Angle rightAngle = Angle.fromDegrees(right);
 | 
			
		||||
            for (int add = 1; add < 360; add++)
 | 
			
		||||
                if (add != 180) {
 | 
			
		||||
                    final int left = right + add;
 | 
			
		||||
                    final Angle leftAngle = Angle.fromDegrees(left);
 | 
			
		||||
                    assertEquals(left + "° right of " + right + "°", add > 180, leftAngle.rightOf(rightAngle));
 | 
			
		||||
                }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										39
									
								
								Projekte/common/src/test/java/pp/util/IntervalTest.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								Projekte/common/src/test/java/pp/util/IntervalTest.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.util;
 | 
			
		||||
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
import static org.junit.Assert.assertFalse;
 | 
			
		||||
import static org.junit.Assert.assertTrue;
 | 
			
		||||
import static pp.util.FloatMath.ZERO_TOLERANCE;
 | 
			
		||||
 | 
			
		||||
public class IntervalTest {
 | 
			
		||||
    private Interval interval;
 | 
			
		||||
 | 
			
		||||
    @Before
 | 
			
		||||
    public void setUp() {
 | 
			
		||||
        interval = new Interval(0f, 1f);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void contains() {
 | 
			
		||||
        assertTrue(interval.contains(0.5f));
 | 
			
		||||
        assertTrue(interval.contains(0f));
 | 
			
		||||
        assertTrue(interval.contains(1f));
 | 
			
		||||
        assertFalse(interval.contains(1.5f));
 | 
			
		||||
        assertFalse(interval.contains(-0.5f));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void matches() {
 | 
			
		||||
        assertTrue(interval.matches(new Interval(0f, 1f), ZERO_TOLERANCE));
 | 
			
		||||
        assertFalse(interval.matches(new Interval(0f, 0.99f), ZERO_TOLERANCE));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,36 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.util;
 | 
			
		||||
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import static org.junit.Assert.assertEquals;
 | 
			
		||||
import static org.junit.Assert.assertTrue;
 | 
			
		||||
 | 
			
		||||
public class RandomPositionIteratorTest {
 | 
			
		||||
    public static final int WIDTH = 15;
 | 
			
		||||
    public static final int HEIGHT = 25;
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void permutation() {
 | 
			
		||||
        for (int i = 0; i < 10; i++) {
 | 
			
		||||
            final List<Position> permutation = new ArrayList<>();
 | 
			
		||||
            RandomPositionIterator.floatPoints(WIDTH, HEIGHT).forEachRemaining(permutation::add);
 | 
			
		||||
            assertEquals(WIDTH * HEIGHT, permutation.size());
 | 
			
		||||
            assertEquals(permutation.size(), new HashSet<>(permutation).size());
 | 
			
		||||
            for (Position w : permutation) {
 | 
			
		||||
                assertTrue(w.toString(), 0 <= w.getX() && w.getX() < WIDTH);
 | 
			
		||||
                assertTrue(w.toString(), 0 <= w.getY() && w.getY() < HEIGHT);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										201
									
								
								Projekte/common/src/test/java/pp/util/SegmentTest.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								Projekte/common/src/test/java/pp/util/SegmentTest.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,201 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.util;
 | 
			
		||||
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
import static org.junit.Assert.assertEquals;
 | 
			
		||||
import static pp.util.FloatMath.FLT_EPSILON;
 | 
			
		||||
import static pp.util.FloatMath.PI;
 | 
			
		||||
import static pp.util.FloatMath.ZERO_TOLERANCE;
 | 
			
		||||
import static pp.util.FloatMath.cos;
 | 
			
		||||
import static pp.util.FloatMath.sqr;
 | 
			
		||||
import static pp.util.FloatMath.sqrt;
 | 
			
		||||
import static pp.util.FloatMath.tan;
 | 
			
		||||
 | 
			
		||||
public class SegmentTest {
 | 
			
		||||
    private static final float SQRT2 = sqrt(2f);
 | 
			
		||||
    private static final Segment segment1 = new Segment(new FloatPoint(1f, -1f), new FloatPoint(1f, 1f));
 | 
			
		||||
    private static final Segment segment2 = new Segment(new FloatPoint(SQRT2, 0f), new FloatPoint(0f, SQRT2));
 | 
			
		||||
    private static final Segment segment3 = new Segment(new FloatPoint(2f, -1f), new FloatPoint(2f, 1f));
 | 
			
		||||
    private static final Segment segment4 = new Segment(new FloatPoint(SQRT2, -1f), new FloatPoint(SQRT2, 1f));
 | 
			
		||||
    private static final Segment segment5 = new Segment(new FloatPoint(-SQRT2, 2f * SQRT2), new FloatPoint(2f * SQRT2, -SQRT2));
 | 
			
		||||
    private static final Segment segment6 = new Segment(new FloatPoint(0f, 0f), new FloatPoint(SQRT2, 1f));
 | 
			
		||||
    private static final FloatPoint ZERO = new FloatPoint(0f, 0f);
 | 
			
		||||
    public static final FloatPoint ONE_UP = new FloatPoint(0f, 1f);
 | 
			
		||||
    public static final FloatPoint ONE_DOWN = new FloatPoint(0f, -1f);
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void dist1() {
 | 
			
		||||
        assertEquals(1f, segment1.dist(ZERO, 0f), FLT_EPSILON);
 | 
			
		||||
        assertEquals(1f, segment1.dist(ONE_UP, 0f), FLT_EPSILON);
 | 
			
		||||
        assertEquals(1f, segment1.dist(ONE_DOWN, 0f), FLT_EPSILON);
 | 
			
		||||
        assertEquals(1f / cos(0.125f * PI), segment1.dist(ZERO, 0.125f * PI), FLT_EPSILON);
 | 
			
		||||
        assertEquals(1f / cos(0.125f * PI), segment1.dist(ONE_UP, 0.125f * PI), FLT_EPSILON);
 | 
			
		||||
        assertEquals(1f / cos(0.125f * PI), segment1.dist(ONE_DOWN, 0.125f * PI), FLT_EPSILON);
 | 
			
		||||
        assertEquals(1f / cos(0.125f * PI), segment1.dist(ZERO, -0.125f * PI), FLT_EPSILON);
 | 
			
		||||
        assertEquals(1f / cos(0.125f * PI), segment1.dist(ONE_UP, -0.125f * PI), FLT_EPSILON);
 | 
			
		||||
        assertEquals(1f / cos(0.125f * PI), segment1.dist(ONE_DOWN, -0.125f * PI), FLT_EPSILON);
 | 
			
		||||
        assertEquals(SQRT2, segment1.dist(ZERO, 0.25f * PI), FLT_EPSILON);
 | 
			
		||||
        assertEquals(SQRT2, segment1.dist(ZERO, -0.25f * PI), FLT_EPSILON);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void dist2() {
 | 
			
		||||
        assertEquals(1f, segment2.dist(ZERO, 0.25f * PI), FLT_EPSILON);
 | 
			
		||||
        assertEquals(SQRT2, segment2.dist(ZERO, 0f), FLT_EPSILON);
 | 
			
		||||
        assertEquals(SQRT2, segment2.dist(ZERO, 0.5f * PI), FLT_EPSILON);
 | 
			
		||||
        assertEquals(1f / cos(0.125f * PI), segment2.dist(ZERO, 0.375f * PI), FLT_EPSILON);
 | 
			
		||||
        assertEquals(SQRT2, segment2.dist(ZERO, PI / 2f), FLT_EPSILON);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void quotient1() {
 | 
			
		||||
        assertEquals(0.5f, segment1.quotient(ZERO, 0f), FLT_EPSILON);
 | 
			
		||||
        assertEquals(1f, segment1.quotient(ONE_UP, 0f), FLT_EPSILON);
 | 
			
		||||
        assertEquals(0f, segment1.quotient(ONE_DOWN, 0f), FLT_EPSILON);
 | 
			
		||||
        assertEquals(0.5f * tan(0.125f * PI) + 0.5f, segment1.quotient(ZERO, 0.125f * PI), FLT_EPSILON);
 | 
			
		||||
        assertEquals(0.5f * tan(0.125f * PI) + 1f, segment1.quotient(ONE_UP, 0.125f * PI), FLT_EPSILON);
 | 
			
		||||
        assertEquals(0.5f * tan(0.125f * PI), segment1.quotient(ONE_DOWN, 0.125f * PI), FLT_EPSILON);
 | 
			
		||||
        assertEquals(0.5f - 0.5f * tan(0.125f * PI), segment1.quotient(ZERO, -0.125f * PI), FLT_EPSILON);
 | 
			
		||||
        assertEquals(1f - 0.5f * tan(0.125f * PI), segment1.quotient(ONE_UP, -0.125f * PI), FLT_EPSILON);
 | 
			
		||||
        assertEquals(-0.5f * tan(0.125f * PI), segment1.quotient(ONE_DOWN, -0.125f * PI), FLT_EPSILON);
 | 
			
		||||
        assertEquals(1f, segment1.quotient(ZERO, 0.25f * PI), FLT_EPSILON);
 | 
			
		||||
        assertEquals(0f, segment1.quotient(ZERO, -0.25f * PI), FLT_EPSILON);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void quotient2() {
 | 
			
		||||
        assertEquals(0.5f, segment2.quotient(ZERO, 0.25f * PI), FLT_EPSILON);
 | 
			
		||||
        assertEquals(0f, segment2.quotient(ZERO, 0f), FLT_EPSILON);
 | 
			
		||||
        assertEquals(1f, segment2.quotient(ZERO, 0.5f * PI), FLT_EPSILON);
 | 
			
		||||
        assertEquals(0.5f * SQRT2, segment2.quotient(ZERO, 0.375f * PI), FLT_EPSILON);
 | 
			
		||||
        assertEquals(1f - 0.5f * SQRT2, segment2.quotient(ZERO, 0.125f * PI), FLT_EPSILON);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void project() {
 | 
			
		||||
        assertEquals(0.5f, segment1.project(ZERO), FLT_EPSILON);
 | 
			
		||||
        assertEquals(0.5f, segment2.project(ZERO), FLT_EPSILON);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void minDistanceSquared1() {
 | 
			
		||||
        assertEquals(0f, segment1.minDistanceSquared(segment1), ZERO_TOLERANCE);
 | 
			
		||||
 | 
			
		||||
        assertEquals(0f, segment1.minDistanceSquared(segment2), ZERO_TOLERANCE);
 | 
			
		||||
        assertEquals(0f, segment2.minDistanceSquared(segment1), ZERO_TOLERANCE);
 | 
			
		||||
 | 
			
		||||
        assertEquals(1f, segment1.minDistanceSquared(segment3), ZERO_TOLERANCE);
 | 
			
		||||
        assertEquals(1f, segment3.minDistanceSquared(segment1), ZERO_TOLERANCE);
 | 
			
		||||
 | 
			
		||||
        assertEquals(sqr(SQRT2 - 1f), segment1.minDistanceSquared(segment4), ZERO_TOLERANCE);
 | 
			
		||||
        assertEquals(sqr(SQRT2 - 1f), segment4.minDistanceSquared(segment1), ZERO_TOLERANCE);
 | 
			
		||||
 | 
			
		||||
        assertEquals(0f, segment1.minDistanceSquared(segment5), ZERO_TOLERANCE);
 | 
			
		||||
        assertEquals(0f, segment5.minDistanceSquared(segment1), ZERO_TOLERANCE);
 | 
			
		||||
 | 
			
		||||
        assertEquals(0f, segment1.minDistanceSquared(segment6), ZERO_TOLERANCE);
 | 
			
		||||
        assertEquals(0f, segment6.minDistanceSquared(segment1), ZERO_TOLERANCE);
 | 
			
		||||
 | 
			
		||||
        assertEquals(0f, segment2.minDistanceSquared(segment2), ZERO_TOLERANCE);
 | 
			
		||||
 | 
			
		||||
        assertEquals(sqr(2f - SQRT2), segment2.minDistanceSquared(segment3), ZERO_TOLERANCE);
 | 
			
		||||
        assertEquals(sqr(2f - SQRT2), segment3.minDistanceSquared(segment2), ZERO_TOLERANCE);
 | 
			
		||||
 | 
			
		||||
        assertEquals(0f, segment2.minDistanceSquared(segment4), ZERO_TOLERANCE);
 | 
			
		||||
        assertEquals(0f, segment4.minDistanceSquared(segment2), ZERO_TOLERANCE);
 | 
			
		||||
 | 
			
		||||
        assertEquals(0f, segment2.minDistanceSquared(segment5), ZERO_TOLERANCE);
 | 
			
		||||
        assertEquals(0f, segment5.minDistanceSquared(segment2), ZERO_TOLERANCE);
 | 
			
		||||
 | 
			
		||||
        assertEquals(0f, segment2.minDistanceSquared(segment6), ZERO_TOLERANCE);
 | 
			
		||||
        assertEquals(0f, segment6.minDistanceSquared(segment2), ZERO_TOLERANCE);
 | 
			
		||||
 | 
			
		||||
        assertEquals(0f, segment3.minDistanceSquared(segment3), ZERO_TOLERANCE);
 | 
			
		||||
 | 
			
		||||
        assertEquals(sqr(2f - SQRT2), segment3.minDistanceSquared(segment4), ZERO_TOLERANCE);
 | 
			
		||||
        assertEquals(sqr(2f - SQRT2), segment4.minDistanceSquared(segment3), ZERO_TOLERANCE);
 | 
			
		||||
 | 
			
		||||
        assertEquals(0f, segment3.minDistanceSquared(segment5), ZERO_TOLERANCE);
 | 
			
		||||
        assertEquals(0f, segment5.minDistanceSquared(segment3), ZERO_TOLERANCE);
 | 
			
		||||
 | 
			
		||||
        assertEquals(sqr(2f - SQRT2), segment3.minDistanceSquared(segment6), ZERO_TOLERANCE);
 | 
			
		||||
        assertEquals(sqr(2f - SQRT2), segment6.minDistanceSquared(segment3), ZERO_TOLERANCE);
 | 
			
		||||
 | 
			
		||||
        assertEquals(0f, segment4.minDistanceSquared(segment4), ZERO_TOLERANCE);
 | 
			
		||||
 | 
			
		||||
        assertEquals(0f, segment4.minDistanceSquared(segment5), ZERO_TOLERANCE);
 | 
			
		||||
        assertEquals(0f, segment5.minDistanceSquared(segment4), ZERO_TOLERANCE);
 | 
			
		||||
 | 
			
		||||
        assertEquals(0f, segment4.minDistanceSquared(segment6), ZERO_TOLERANCE);
 | 
			
		||||
        assertEquals(0f, segment6.minDistanceSquared(segment4), ZERO_TOLERANCE);
 | 
			
		||||
 | 
			
		||||
        assertEquals(0f, segment5.minDistanceSquared(segment5), ZERO_TOLERANCE);
 | 
			
		||||
 | 
			
		||||
        assertEquals(0f, segment5.minDistanceSquared(segment6), ZERO_TOLERANCE);
 | 
			
		||||
        assertEquals(0f, segment6.minDistanceSquared(segment5), ZERO_TOLERANCE);
 | 
			
		||||
 | 
			
		||||
        assertEquals(0f, segment6.minDistanceSquared(segment6), ZERO_TOLERANCE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void minDistanceSquared2() {
 | 
			
		||||
        final Segment s1 = new Segment(new FloatPoint(0f, 0f), new FloatPoint(2f, 1f));
 | 
			
		||||
        for (int i = -20; i <= 40; i++) {
 | 
			
		||||
            final float x = i * 0.1f;
 | 
			
		||||
            final Segment s2 = new Segment(new FloatPoint(x, 2f), new FloatPoint(x + 2f, -2f));
 | 
			
		||||
            final float dist;
 | 
			
		||||
            if (i <= -10)
 | 
			
		||||
                dist = 0.8f * sqr(1f + x);
 | 
			
		||||
            else if (i <= 15)
 | 
			
		||||
                dist = 0f;
 | 
			
		||||
            else
 | 
			
		||||
                dist = 0.8f * sqr(x - 1.5f);
 | 
			
		||||
            assertEquals("x = " + x, dist, s1.minDistanceSquared(s2), ZERO_TOLERANCE);
 | 
			
		||||
            assertEquals("x = " + x, dist, s2.minDistanceSquared(s1), ZERO_TOLERANCE);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void minDistanceSquared3() {
 | 
			
		||||
        final Segment s1 = new Segment(new FloatPoint(0f, 0f), new FloatPoint(2f, 1f));
 | 
			
		||||
        for (float i = -30; i <= 30; i++) {
 | 
			
		||||
            final float x = i * 0.1f;
 | 
			
		||||
            final Segment s2 = new Segment(new FloatPoint(x, 0.5f * x), new FloatPoint(x + 2f, 0.5f * x + 1f));
 | 
			
		||||
            final float dist;
 | 
			
		||||
            if (i <= -20)
 | 
			
		||||
                dist = 1.25f * sqr(2f + x);
 | 
			
		||||
            else if (i <= 20)
 | 
			
		||||
                dist = 0f;
 | 
			
		||||
            else
 | 
			
		||||
                dist = 1.25f * sqr(x - 2f);
 | 
			
		||||
            assertEquals("x = " + x, dist, s1.minDistanceSquared(s2), ZERO_TOLERANCE);
 | 
			
		||||
            assertEquals("x = " + x, dist, s2.minDistanceSquared(s1), ZERO_TOLERANCE);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void minDistanceSquared4() {
 | 
			
		||||
        final Segment s1 = new Segment(new FloatPoint(0f, 0f), new FloatPoint(3f, 1.5f));
 | 
			
		||||
        for (float i = -30; i <= 50; i++) {
 | 
			
		||||
            final float x = i * 0.1f;
 | 
			
		||||
            final float y = 1f - 0.5f * x;
 | 
			
		||||
            final Segment s2 = new Segment(new FloatPoint(x, 1f), new FloatPoint(x, 1f));
 | 
			
		||||
            final float dist;
 | 
			
		||||
            if (i <= -5)
 | 
			
		||||
                dist = sqr(x) + 1f;
 | 
			
		||||
            else if (i <= 32)
 | 
			
		||||
                dist = 0.2f * sqr(x - 2f);
 | 
			
		||||
            else
 | 
			
		||||
                dist = sqr(x - 3f) + 0.25f;
 | 
			
		||||
            assertEquals("x = " + x, dist, s1.minDistanceSquared(s2), ZERO_TOLERANCE);
 | 
			
		||||
            assertEquals("x = " + x, dist, s2.minDistanceSquared(s1), ZERO_TOLERANCE);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										101
									
								
								Projekte/common/src/test/java/pp/util/config/ConfigTest.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								Projekte/common/src/test/java/pp/util/config/ConfigTest.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,101 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.util.config;
 | 
			
		||||
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.FileWriter;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.Properties;
 | 
			
		||||
 | 
			
		||||
import static org.junit.Assert.assertArrayEquals;
 | 
			
		||||
import static org.junit.Assert.assertEquals;
 | 
			
		||||
import static org.junit.Assert.assertFalse;
 | 
			
		||||
import static org.junit.Assert.assertTrue;
 | 
			
		||||
 | 
			
		||||
public class ConfigTest {
 | 
			
		||||
 | 
			
		||||
    private TestConfig config;
 | 
			
		||||
 | 
			
		||||
    @Before
 | 
			
		||||
    public void setUp() {
 | 
			
		||||
        config = new TestConfig();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testReadFromProperties() {
 | 
			
		||||
        Properties properties = new Properties();
 | 
			
		||||
        properties.setProperty("test.string", "hello"); //NON-NLS
 | 
			
		||||
        properties.setProperty("test.int", "42");
 | 
			
		||||
        properties.setProperty("test.boolean", "true"); //NON-NLS
 | 
			
		||||
        properties.setProperty("test.intArray", "1; 2 ;3;4");
 | 
			
		||||
 | 
			
		||||
        config.readFrom(properties);
 | 
			
		||||
 | 
			
		||||
        assertEquals("hello", config.getTestString());
 | 
			
		||||
        assertEquals(42, config.getTestInt());
 | 
			
		||||
        assertTrue(config.isTestBoolean());
 | 
			
		||||
        assertArrayEquals(new int[]{1, 2, 3, 4}, config.getTestIntArray());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testReadFromFile() throws IOException {
 | 
			
		||||
        Properties properties = new Properties();
 | 
			
		||||
        properties.setProperty("test.string", "fileTest");
 | 
			
		||||
        properties.setProperty("test.int", "24");
 | 
			
		||||
        properties.setProperty("test.boolean", "false"); //NON-NLS
 | 
			
		||||
        properties.setProperty("test.intArray", "10;20;30");
 | 
			
		||||
 | 
			
		||||
        File tempFile = File.createTempFile("testConfig", ".properties");
 | 
			
		||||
        try (FileWriter writer = new FileWriter(tempFile)) {
 | 
			
		||||
            properties.store(writer, null);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        config.readFrom(tempFile);
 | 
			
		||||
 | 
			
		||||
        assertEquals("fileTest", config.getTestString());
 | 
			
		||||
        assertEquals(24, config.getTestInt());
 | 
			
		||||
        assertFalse(config.isTestBoolean());
 | 
			
		||||
        assertArrayEquals(new int[]{10, 20, 30}, config.getTestIntArray());
 | 
			
		||||
 | 
			
		||||
        // Clean up
 | 
			
		||||
        tempFile.delete();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testConvertToType() {
 | 
			
		||||
        assertEquals(42, config.convertToType("42", int.class));
 | 
			
		||||
        assertEquals(true, config.convertToType("true", boolean.class)); //NON-NLS
 | 
			
		||||
        assertEquals(3.14, config.convertToType("3.14", double.class));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test(expected = IllegalArgumentException.class)
 | 
			
		||||
    public void testConvertToTypeWithUnsupportedType() {
 | 
			
		||||
        config.convertToType("unsupported", Object.class); //NON-NLS
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testToString() {
 | 
			
		||||
        Properties properties = new Properties();
 | 
			
		||||
        properties.setProperty("test.string", "stringValue");
 | 
			
		||||
        properties.setProperty("test.int", "123");
 | 
			
		||||
        properties.setProperty("test.boolean", "true"); //NON-NLS
 | 
			
		||||
        properties.setProperty("test.intArray", "5;6;7");
 | 
			
		||||
 | 
			
		||||
        config.readFrom(properties);
 | 
			
		||||
 | 
			
		||||
        String expected = "[\ntest.boolean -> testBoolean = true,\n" +
 | 
			
		||||
                          "test.int -> testInt = 123,\n" +
 | 
			
		||||
                          "test.intArray -> testIntArray = {5, 6, 7},\n" +
 | 
			
		||||
                          "test.string -> testString = stringValue\n" +
 | 
			
		||||
                          "]";
 | 
			
		||||
        assertEquals(expected, config.toString());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										40
									
								
								Projekte/common/src/test/java/pp/util/config/TestConfig.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								Projekte/common/src/test/java/pp/util/config/TestConfig.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.util.config;
 | 
			
		||||
 | 
			
		||||
class TestConfig extends Config {
 | 
			
		||||
    @Property("test.string")
 | 
			
		||||
    private String testString;
 | 
			
		||||
 | 
			
		||||
    @Property("test.int")
 | 
			
		||||
    private int testInt;
 | 
			
		||||
 | 
			
		||||
    @Property("test.boolean")
 | 
			
		||||
    private boolean testBoolean;
 | 
			
		||||
 | 
			
		||||
    @Property("test.intArray")
 | 
			
		||||
    @Separator(";")
 | 
			
		||||
    private int[] testIntArray;
 | 
			
		||||
 | 
			
		||||
    // Getters for testing
 | 
			
		||||
    public String getTestString() {
 | 
			
		||||
        return testString;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getTestInt() {
 | 
			
		||||
        return testInt;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isTestBoolean() {
 | 
			
		||||
        return testBoolean;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int[] getTestIntArray() {
 | 
			
		||||
        return testIntArray;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user