hytale-server/com/hypixel/hytale/math/util/MathUtil.java

570 lines
15 KiB
Java

package com.hypixel.hytale.math.util;
import com.hypixel.hytale.math.vector.Vector3d;
import com.hypixel.hytale.math.vector.Vector3f;
import com.hypixel.hytale.math.vector.Vector3i;
import java.util.concurrent.ThreadLocalRandom;
import javax.annotation.Nonnull;
public class MathUtil {
public static final double EPSILON_DOUBLE = Math.ulp(1.0);
public static final float EPSILON_FLOAT = Math.ulp(1.0F);
public static float PITCH_EDGE_PADDING = 0.01F;
public static int abs(int i) {
int mask = i >> 31;
return i + mask ^ mask;
}
public static int floor(double d) {
int i = (int)d;
if (i <= d) {
return i;
} else {
return d < -2.1474836E9F ? Integer.MIN_VALUE : i - 1;
}
}
public static int ceil(double d) {
int i = (int)d;
if (!(d > 0.0) || d == i) {
return i;
} else {
return d > 2.147483647E9 ? Integer.MAX_VALUE : i + 1;
}
}
public static int randomInt(int min, int max) {
return ThreadLocalRandom.current().nextInt(min, max);
}
public static double randomDouble(double min, double max) {
return min + Math.random() * (max - min);
}
public static float randomFloat(float min, float max) {
return min + (float)Math.random() * (max - min);
}
public static double round(double d, int p) {
double pow = Math.pow(10.0, p);
return Math.round(d * pow) / pow;
}
public static boolean within(double val, double min, double max) {
return val >= min && val <= max;
}
public static double minValue(double v, double a, double c) {
if (a < v) {
v = a;
}
if (c < v) {
v = c;
}
return v;
}
public static int minValue(int v, int a, int c) {
if (a < v) {
v = a;
}
if (c < v) {
v = c;
}
return v;
}
public static double maxValue(double v, double a, double b, double c) {
if (a > v) {
v = a;
}
if (b > v) {
v = b;
}
if (c > v) {
v = c;
}
return v;
}
public static double maxValue(double v, double a, double b) {
if (a > v) {
v = a;
}
if (b > v) {
v = b;
}
return v;
}
public static byte maxValue(byte v, byte a, byte b) {
if (a > v) {
v = a;
}
if (b > v) {
v = b;
}
return v;
}
public static byte maxValue(byte v, byte a, byte b, byte c) {
if (a > v) {
v = a;
}
if (b > v) {
v = b;
}
if (c > v) {
v = c;
}
return v;
}
public static int maxValue(int v, int a, int b) {
if (a > v) {
v = a;
}
if (b > v) {
v = b;
}
return v;
}
public static double lengthSquared(double x, double y) {
return x * x + y * y;
}
public static double length(double x, double y) {
return Math.sqrt(lengthSquared(x, y));
}
public static double lengthSquared(double x, double y, double z) {
return x * x + y * y + z * z;
}
public static double length(double x, double y, double z) {
return Math.sqrt(lengthSquared(x, y, z));
}
public static double maxValue(double v, double a) {
return a > v ? a : v;
}
public static double clipToZero(double v) {
return clipToZero(v, EPSILON_DOUBLE);
}
public static double clipToZero(double v, double epsilon) {
return v >= -epsilon && v <= epsilon ? 0.0 : v;
}
public static float clipToZero(float v) {
return clipToZero(v, EPSILON_FLOAT);
}
public static float clipToZero(float v, float epsilon) {
return v >= -epsilon && v <= epsilon ? 0.0F : v;
}
public static boolean closeToZero(double v) {
return closeToZero(v, EPSILON_DOUBLE);
}
public static boolean closeToZero(double v, double epsilon) {
return v >= -epsilon && v <= epsilon;
}
public static boolean closeToZero(float v) {
return closeToZero(v, EPSILON_FLOAT);
}
public static boolean closeToZero(float v, float epsilon) {
return v >= -epsilon && v <= epsilon;
}
public static double clamp(double v, double min, double max) {
if (v > max) {
return v < min ? min : max;
} else {
return v < min ? min : v;
}
}
public static float clamp(float v, float min, float max) {
if (v > max) {
return v < min ? min : max;
} else {
return v < min ? min : v;
}
}
public static int clamp(int v, int min, int max) {
if (v > max) {
return v < min ? min : max;
} else {
return v < min ? min : v;
}
}
public static long clamp(long v, long min, long max) {
if (v > max) {
return v < min ? min : max;
} else {
return v < min ? min : v;
}
}
public static int getPercentageOf(int index, int max) {
return (int)(index / (max - 1.0) * 100.0);
}
public static double percent(int v, int total) {
return total == 0 ? 0.0 : v * 100.0 / total;
}
public static int fastRound(float f) {
return fastFloor(f + 0.5F);
}
public static long fastRound(double d) {
return fastFloor(d + 0.5);
}
public static int fastFloor(float f) {
int i = (int)f;
if (i <= f) {
return i;
} else {
return f < -2.1474836E9F ? Integer.MIN_VALUE : i - 1;
}
}
public static long fastFloor(double d) {
long i = (long)d;
if (i <= d) {
return i;
} else {
return d < -9.223372E18F ? Long.MIN_VALUE : i - 1L;
}
}
public static int fastCeil(float f) {
int i = (int)f;
if (!(f > 0.0F) || f == i) {
return i;
} else {
return f > 2.1474836E9F ? Integer.MAX_VALUE : i + 1;
}
}
public static long fastCeil(double d) {
long i = (long)d;
if (!(d > 0.0) || d == i) {
return i;
} else {
return d > 9.223372E18F ? Long.MAX_VALUE : i + 1L;
}
}
private MathUtil() {
}
public static float halfFloatToFloat(int hbits) {
int mant = hbits & 1023;
int exp = hbits & 31744;
if (exp == 31744) {
exp = 261120;
} else if (exp != 0) {
exp += 114688;
if (mant == 0 && exp > 115712) {
return Float.intBitsToFloat((hbits & 32768) << 16 | exp << 13 | 1023);
}
} else if (mant != 0) {
exp = 115712;
do {
mant <<= 1;
exp -= 1024;
} while ((mant & 1024) == 0);
mant &= 1023;
}
return Float.intBitsToFloat((hbits & 32768) << 16 | (exp | mant) << 13);
}
public static int halfFloatFromFloat(float fval) {
int fbits = Float.floatToIntBits(fval);
int sign = fbits >>> 16 & 32768;
int val = (fbits & 2147483647) + 4096;
if (val >= 1199570944) {
if ((fbits & 2147483647) >= 1199570944) {
return val < 2139095040 ? sign | 31744 : sign | 31744 | (fbits & 8388607) >>> 13;
} else {
return sign | 31743;
}
} else if (val >= 947912704) {
return sign | val - 939524096 >>> 13;
} else if (val < 855638016) {
return sign;
} else {
val = (fbits & 2147483647) >>> 23;
return sign | (fbits & 8388607 | 8388608) + (8388608 >>> val - 102) >>> 126 - val;
}
}
public static int byteCount(int i) {
if (i > 65535) {
return 4;
} else if (i > 255) {
return 2;
} else {
return i > 0 ? 1 : 0;
}
}
public static int packInt(int x, int z) {
return x << 16 | z & 65535;
}
public static int unpackLeft(int packed) {
int i = packed >> 16 & 65535;
if ((i & 32768) != 0) {
i |= -65536;
}
return i;
}
public static int unpackRight(int packed) {
int i = packed & 65535;
if ((i & 32768) != 0) {
i |= -65536;
}
return i;
}
public static long packLong(int left, int right) {
return (long)left << 32 | right & 4294967295L;
}
public static int unpackLeft(long packed) {
return (int)(packed >> 32);
}
public static int unpackRight(long packed) {
return (int)packed;
}
@Nonnull
public static Vector3i rotateVectorYAxis(@Nonnull Vector3i vector, int angle, boolean clockwise) {
float radAngle = (float) (Math.PI / 180.0) * angle;
int x1;
int z1;
if (clockwise) {
x1 = (int)(vector.x * TrigMathUtil.cos(radAngle) - vector.z * TrigMathUtil.sin(radAngle));
z1 = (int)(vector.x * TrigMathUtil.sin(radAngle) + vector.z * TrigMathUtil.cos(radAngle));
} else {
x1 = (int)(vector.x * TrigMathUtil.cos(radAngle) + vector.z * TrigMathUtil.sin(radAngle));
z1 = (int)(-vector.x * TrigMathUtil.sin(radAngle) + vector.z * TrigMathUtil.cos(radAngle));
}
return new Vector3i(x1, vector.y, z1);
}
@Nonnull
public static Vector3d rotateVectorYAxis(@Nonnull Vector3d vector, int angle, boolean clockwise) {
float radAngle = (float) (Math.PI / 180.0) * angle;
double x1;
double z1;
if (clockwise) {
x1 = vector.x * TrigMathUtil.cos(radAngle) - vector.z * TrigMathUtil.sin(radAngle);
z1 = vector.x * TrigMathUtil.sin(radAngle) + vector.z * TrigMathUtil.cos(radAngle);
} else {
x1 = vector.x * TrigMathUtil.cos(radAngle) + vector.z * TrigMathUtil.sin(radAngle);
z1 = -vector.x * TrigMathUtil.sin(radAngle) + vector.z * TrigMathUtil.cos(radAngle);
}
return new Vector3d(x1, vector.y, z1);
}
public static float wrapAngle(float angle) {
angle %= (float) (Math.PI * 2);
if (angle <= (float) -Math.PI) {
angle += (float) (Math.PI * 2);
} else if (angle > (float) Math.PI) {
angle -= (float) (Math.PI * 2);
}
return angle;
}
public static float lerp(float a, float b, float t) {
return lerpUnclamped(a, b, clamp(t, 0.0F, 1.0F));
}
public static float lerpUnclamped(float a, float b, float t) {
return a + t * (b - a);
}
public static double lerp(double a, double b, double t) {
return lerpUnclamped(a, b, clamp(t, 0.0, 1.0));
}
public static double lerpUnclamped(double a, double b, double t) {
return a + t * (b - a);
}
public static float shortAngleDistance(float a, float b) {
float distance = (b - a) % (float) (Math.PI * 2);
return 2.0F * distance % (float) (Math.PI * 2) - distance;
}
public static float lerpAngle(float a, float b, float t) {
return a + shortAngleDistance(a, b) * t;
}
public static double floorMod(double x, double y) {
return x - Math.floor(x / y) * y;
}
public static double compareAngle(double a, double b) {
double diff = b - a;
return floorMod(diff + Math.PI, Math.PI * 2) - Math.PI;
}
public static double percentile(@Nonnull long[] sortedData, double percentile) {
if (sortedData.length == 1) {
return sortedData[0];
} else if (percentile >= 1.0) {
return sortedData[sortedData.length - 1];
} else {
double position = (sortedData.length + 1) * percentile;
double n = percentile * (sortedData.length - 1) + 1.0;
long left;
long right;
if (position >= 1.0) {
left = sortedData[floor(n) - 1];
right = sortedData[floor(n)];
} else {
left = sortedData[0];
right = sortedData[1];
}
if (left == right) {
return left;
} else {
double part = n - floor(n);
return left + part * (right - left);
}
}
}
public static double distanceToLineSq(double x, double y, double ax, double ay, double bx, double by) {
double dx0 = x - ax;
double dy0 = y - ay;
double dx1 = bx - ax;
double dy1 = by - ay;
return distanceToLineSq(x, y, ax, ay, bx, by, dx0, dy0, dx1, dy1);
}
public static double distanceToLineSq(double x, double y, double ax, double ay, double bx, double by, double dxAx, double dyAy, double dBxAx, double dByAy) {
double t = dxAx * dBxAx + dyAy * dByAy;
t /= dBxAx * dBxAx + dByAy * dByAy;
double px = ax;
double py = ay;
if (t > 1.0) {
px = bx;
py = by;
} else if (t > 0.0) {
px = ax + t * dBxAx;
py = ay + t * dByAy;
}
dBxAx = x - px;
dByAy = y - py;
return dBxAx * dBxAx + dByAy * dByAy;
}
public static double distanceToInfLineSq(double x, double y, double ax, double ay, double bx, double by) {
double dx0 = x - ax;
double dy0 = y - ay;
double dx1 = bx - ax;
double dy1 = by - ay;
return distanceToInfLineSq(x, y, ax, ay, dx0, dy0, dx1, dy1);
}
public static double distanceToInfLineSq(double x, double y, double ax, double ay, double dxAx, double dyAy, double dBxAx, double dByAy) {
double t = dxAx * dBxAx + dyAy * dByAy;
t /= dBxAx * dBxAx + dByAy * dByAy;
double px = ax + t * dBxAx;
double py = ay + t * dByAy;
dBxAx = x - px;
dByAy = y - py;
return dBxAx * dBxAx + dByAy * dByAy;
}
public static int sideOfLine(double x, double y, double ax, double ay, double bx, double by) {
return (ax - x) * (by - y) - (ay - y) * (bx - x) >= 0.0 ? 1 : -1;
}
public static Vector3f getRotationForHitNormal(Vector3f normal) {
if (normal == null) {
return Vector3f.ZERO;
} else if (normal.y == 1.0F) {
return Vector3f.ZERO;
} else if (normal.y == -1.0F) {
return new Vector3f(0.0F, 0.0F, (float) Math.PI);
} else if (normal.x == 1.0F) {
return new Vector3f(0.0F, 0.0F, (float) (-Math.PI / 2));
} else if (normal.x == -1.0F) {
return new Vector3f(0.0F, 0.0F, (float) (Math.PI / 2));
} else if (normal.z == 1.0F) {
return new Vector3f((float) (Math.PI / 2), 0.0F, 0.0F);
} else {
return normal.z == -1.0F ? new Vector3f((float) (-Math.PI / 2), 0.0F, 0.0F) : Vector3f.ZERO;
}
}
public static String getNameForHitNormal(Vector3f normal) {
if (normal == null) {
return "UP";
} else if (normal.y == 1.0F) {
return "UP";
} else if (normal.y == -1.0F) {
return "DOWN";
} else if (normal.x == 1.0F) {
return "WEST";
} else if (normal.x == -1.0F) {
return "EAST";
} else if (normal.z == 1.0F) {
return "NORTH";
} else {
return normal.z == -1.0F ? "SOUTH" : "UP";
}
}
public static float mapToRange(float value, float valueMin, float valueMax, float rangeMin, float rangeMax) {
float alpha = (value - valueMin) / (valueMax - valueMin);
return rangeMin + alpha * (rangeMax - rangeMin);
}
}