package com.hbm.util; import cpw.mods.fml.relauncher.ReflectionHelper; import net.minecraft.util.MathHelper; import net.minecraft.util.Vec3; import net.minecraftforge.common.util.ForgeDirection; import javax.annotation.Nonnegative; import java.lang.reflect.Field; import java.math.BigDecimal; import java.math.RoundingMode; import java.text.NumberFormat; import java.util.*; import java.util.function.ToIntFunction; public class BobMathUtil { //finally! public static int min(int... nums) { int smallest = Integer.MAX_VALUE; for(int num : nums) if(num < smallest) smallest = num; return smallest; } public static int max(int... nums) { int largest = Integer.MIN_VALUE; for(int num : nums) if(num > largest) largest = num; return largest; } public static long min(long... nums) { long smallest = Long.MAX_VALUE; for(long num : nums) if(num < smallest) smallest = num; return smallest; } public static long max(long... nums) { long largest = Long.MIN_VALUE; for(long num : nums) if(num > largest) largest = num; return largest; } public static float min(float... nums) { float smallest = Float.MAX_VALUE; for(float num : nums) if(num < smallest) smallest = num; return smallest; } public static float max(float... nums) { float largest = Float.MIN_VALUE; for(float num : nums) if(num > largest) largest = num; return largest; } public static double min(double... nums) { double smallest = Double.MAX_VALUE; for(double num : nums) if(num < smallest) smallest = num; return smallest; } public static double max(double... nums) { double largest = Double.MIN_VALUE; for(double num : nums) if(num > largest) largest = num; return largest; } public static double safeClamp(double val, double min, double max) { val = MathHelper.clamp_double(val, min, max); if(val == Double.NaN) { val = (min + max) / 2D; } return val; } public static Vec3 interpVec(Vec3 vec1, Vec3 vec2, float interp) { return Vec3.createVectorHelper( interp(vec1.xCoord, vec2.xCoord, interp), interp(vec1.yCoord, vec2.yCoord, interp), interp(vec1.zCoord, vec2.zCoord, interp) ); } public static double interp(double x, double y, float interp) { return x + (y - x) * interp; } public static double getAngleFrom2DVecs(double x1, double z1, double x2, double z2) { double upper = x1 * x2 + z1 * z2; double lower = Math.sqrt(x1 * x1 + z1 * z1) * Math.sqrt(x2 * x2 + z2 * z2); double result = Math.toDegrees(Math.cos(upper / lower)); if(result >= 180) result -= 180; return result; } public static double getCrossAngle(Vec3 vel, Vec3 rel) { vel.normalize(); rel.normalize(); double vecProd = rel.xCoord * vel.xCoord + rel.yCoord * vel.yCoord + rel.zCoord * vel.zCoord; double bot = rel.lengthVector() * vel.lengthVector(); double angle = Math.acos(vecProd / bot) * 180 / Math.PI; if(angle >= 180) angle -= 180; return angle; } public static float remap(float num, float min1, float max1, float min2, float max2){ return ((num - min1) / (max1 - min1)) * (max2 - min2) + min2; } public static float remap01(float num, float min1, float max1){ return (num - min1) / (max1 - min1); } public static float remap01_clamp(float num, float min1, float max1){ return MathHelper.clamp_float((num - min1) / (max1 - min1), 0, 1); } public static ForgeDirection[] getShuffledDirs() { ForgeDirection[] dirs = new ForgeDirection[6]; List indices = new ArrayList() {{ add(0); add(1); add(2); add(3); add(4); add(5); }}; Collections.shuffle(indices); for(int i = 0; i < 6; i++) { dirs[i] = ForgeDirection.getOrientation(indices.get(i)); } return dirs; } public static String toPercentage(float amount, float total) { return NumberFormat.getPercentInstance().format(amount / total); } public static String[] ticksToDate(long ticks) { int tickDay = 48000; int tickYear = tickDay * 100; final String[] dateOut = new String[3]; long year = Math.floorDiv(ticks, tickYear); byte day = (byte) Math.floorDiv(ticks - tickYear * year, tickDay); float time = ticks - (tickYear * year + tickDay * day); time = (float) convertScale(time, 0, tickDay, 0, 10F); dateOut[0] = String.valueOf(year); dateOut[1] = String.valueOf(day); dateOut[2] = String.valueOf(time); return dateOut; } /** * Rescale a number from one range to another * @param toScale - The integer to scale * @param oldMin - The current minimum value * @param oldMax - The current maximum value * @param newMin - The desired minimum value * @param newMax - The desired maximum value * @return The scaled number */ public static double convertScale(double toScale, double oldMin, double oldMax, double newMin, double newMax) { double prevRange = oldMax - oldMin; double newRange = newMax - newMin; return (((toScale - oldMin) * newRange) / prevRange) + newMin; } /** * Rounds a number to so many significant digits * @param num The number to round * @param digits Amount of digits * @return The rounded double */ public static double roundDecimal(double num, @Nonnegative int digits) { if(digits < 0) throw new IllegalArgumentException("Attempted negative number in non-negative field! Attempted value: " + digits); return new BigDecimal(num).setScale(digits, RoundingMode.HALF_UP).doubleValue(); } /** * @param amount * @return the number as a string with thousand group commas */ public static String format(int amount) { return String.format(Locale.US, "%,d", amount); } public static boolean getBlink() { return System.currentTimeMillis() % 1000 < 500; } public static String getShortNumber(long l) { if(l >= Math.pow(10, 18)) { double res = l / Math.pow(10, 18); res = Math.round(res * 100.0) / 100.0; return res + "E"; } if(l >= Math.pow(10, 15)) { double res = l / Math.pow(10, 15); res = Math.round(res * 100.0) / 100.0; return res + "P"; } if(l >= Math.pow(10, 12)) { double res = l / Math.pow(10, 12); res = Math.round(res * 100.0) / 100.0; return res + "T"; } if(l >= Math.pow(10, 9)) { double res = l / Math.pow(10, 9); res = Math.round(res * 100.0) / 100.0; return res + "G"; } if(l >= Math.pow(10, 6)) { double res = l / Math.pow(10, 6); res = Math.round(res * 100.0) / 100.0; return res + "M"; } if(l >= Math.pow(10, 3)) { double res = l / Math.pow(10, 3); res = Math.round(res * 100.0) / 100.0; return res + "k"; } return Long.toString(l); } /** * Adjusted sqrt, approaches standard sqrt but sqrt(x) is never bigger than x * * ____________ * / 1 | 1 * _ / x + ―――――――― - ――――― * \/ (x + 2)² x + 2 * * @param x * @return */ public static double squirt(double x) { return Math.sqrt(x + 1D / ((x + 2D) * (x + 2D))) - 1D / (x + 2D); } /** A convenient way to re-define the value of pi, should the laws of nature change. */ public static void setPi(double pi) { Field field = ReflectionHelper.findField(Math.class, "PI"); try { field.setDouble(null, pi); } catch(Exception e) { } } public static double angularDifference(double alpha, double beta) { double delta = (beta - alpha + 180) % 360 - 180; return delta < -180 ? delta + 360 : delta; } // I am sick of trying to remember the ridiculous quirks of Java 8 // so I wrote this thing that can shit any int-ish list-ish into a regular fucking int[] // made by mellow, thrown here by 70k public static int[] intCollectionToArray(Collection in) { return intCollectionToArray(in, i -> (int)i); } public static int[] intCollectionToArray(Collection in, ToIntFunction mapper) { return Arrays.stream(in.toArray()).mapToInt(mapper).toArray(); } public static int[] collectionToIntArray(Collection in, ToIntFunction mapper) { return Arrays.stream(in.toArray()).mapToInt(mapper).toArray(); } public static void shuffleIntArray(int[] array) { Random rand = new Random(); for(int i = array.length - 1; i > 0; i--) { int r = rand.nextInt(i + 1); int temp = array[r]; array[r] = array[i]; array[i] = temp; } } public static void reverseIntArray(int[] array) { int len = array.length; for(int i = 0; i < len / 2; i++) { int temp = array[i]; array[i] = array[len - 1 - i]; array[len - 1 - i] = temp; } } /** Soft peak sine */ public static double sps(double x) { return Math.sin(Math.PI / 2D * Math.cos(x)); } /** Square wave sine, make sure squarination is [0;1] */ public static double sws(double x, double squarination) { double s = Math.sin(x); return Math.pow(Math.abs(s), 2 - squarination) / s; } }