/******************************************************************************* * Copyright 2011 See AUTHORS file. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package com.glview.libgdx.graphics.math; import java.util.Random; /** Utility and fast math functions. * <p> * Thanks to Riven on JavaGaming.org for the basis of sin/cos/atan2/floor/ceil. * @author Nathan Sweet */ public class MathUtils { static public final float nanoToSec = 1 / 1000000000f; // --- static public final float PI = 3.1415927f; static public final float PI2 = PI * 2; static private final int SIN_BITS = 14; // 16KB. Adjust for accuracy. static private final int SIN_MASK = ~(-1 << SIN_BITS); static private final int SIN_COUNT = SIN_MASK + 1; static private final float radFull = PI * 2; static private final float degFull = 360; static private final float radToIndex = SIN_COUNT / radFull; static private final float degToIndex = SIN_COUNT / degFull; static public final float radiansToDegrees = 180f / PI; static public final float radDeg = radiansToDegrees; static public final float degreesToRadians = PI / 180; static public final float degRad = degreesToRadians; static private class Sin { static final float[] table = new float[SIN_COUNT]; static { for (int i = 0; i < SIN_COUNT; i++) table[i] = (float)Math.sin((i + 0.5f) / SIN_COUNT * radFull); for (int i = 0; i < 360; i += 90) table[(int)(i * degToIndex) & SIN_MASK] = (float)Math.sin(i * degreesToRadians); } } /** Returns the sine in radians from a lookup table. */ static public final float sin (float radians) { return Sin.table[(int)(radians * radToIndex) & SIN_MASK]; } /** Returns the cosine in radians from a lookup table. */ static public final float cos (float radians) { return Sin.table[(int)((radians + PI / 2) * radToIndex) & SIN_MASK]; } /** Returns the sine in radians from a lookup table. */ static public final float sinDeg (float degrees) { return Sin.table[(int)(degrees * degToIndex) & SIN_MASK]; } /** Returns the cosine in radians from a lookup table. */ static public final float cosDeg (float degrees) { return Sin.table[(int)((degrees + 90) * degToIndex) & SIN_MASK]; } // --- static private final int ATAN2_BITS = 7; // Adjust for accuracy. static private final int ATAN2_BITS2 = ATAN2_BITS << 1; static private final int ATAN2_MASK = ~(-1 << ATAN2_BITS2); static private final int ATAN2_COUNT = ATAN2_MASK + 1; static final int ATAN2_DIM = (int)Math.sqrt(ATAN2_COUNT); static private final float INV_ATAN2_DIM_MINUS_1 = 1.0f / (ATAN2_DIM - 1); static private class Atan2 { static final float[] table = new float[ATAN2_COUNT]; static { for (int i = 0; i < ATAN2_DIM; i++) { for (int j = 0; j < ATAN2_DIM; j++) { float x0 = (float)i / ATAN2_DIM; float y0 = (float)j / ATAN2_DIM; table[j * ATAN2_DIM + i] = (float)Math.atan2(y0, x0); } } } } /** Returns atan2 in radians from a lookup table. */ static public final float atan2 (float y, float x) { float add, mul; if (x < 0) { if (y < 0) { y = -y; mul = 1; } else mul = -1; x = -x; add = -PI; } else { if (y < 0) { y = -y; mul = -1; } else mul = 1; add = 0; } float invDiv = 1 / ((x < y ? y : x) * INV_ATAN2_DIM_MINUS_1); if (invDiv == Float.POSITIVE_INFINITY) return ((float)Math.atan2(y, x) + add) * mul; int xi = (int)(x * invDiv); int yi = (int)(y * invDiv); return (Atan2.table[yi * ATAN2_DIM + xi] + add) * mul; } // --- static public Random random = new Random(); /** Returns a random number between 0 (inclusive) and the specified value (inclusive). */ static public final int random (int range) { return random.nextInt(range + 1); } /** Returns a random number between start (inclusive) and end (inclusive). */ static public final int random (int start, int end) { return start + random.nextInt(end - start + 1); } /** Returns a random boolean value. */ static public final boolean randomBoolean () { return random.nextBoolean(); } /** Returns true if a random value between 0 and 1 is less than the specified value. */ static public final boolean randomBoolean (float chance) { return MathUtils.random() < chance; } /** Returns random number between 0.0 (inclusive) and 1.0 (exclusive). */ static public final float random () { return random.nextFloat(); } /** Returns a random number between 0 (inclusive) and the specified value (exclusive). */ static public final float random (float range) { return random.nextFloat() * range; } /** Returns a random number between start (inclusive) and end (exclusive). */ static public final float random (float start, float end) { return start + random.nextFloat() * (end - start); } // --- /** Returns the next power of two. Returns the specified value if the value is already a power of two. */ static public int nextPowerOfTwo (int value) { if (value == 0) return 1; value--; value |= value >> 1; value |= value >> 2; value |= value >> 4; value |= value >> 8; value |= value >> 16; return value + 1; } static public boolean isPowerOfTwo (int value) { return value != 0 && (value & value - 1) == 0; } // --- static public int clamp (int value, int min, int max) { if (value < min) return min; if (value > max) return max; return value; } static public short clamp (short value, short min, short max) { if (value < min) return min; if (value > max) return max; return value; } static public float clamp (float value, float min, float max) { if (value < min) return min; if (value > max) return max; return value; } // --- static private final int BIG_ENOUGH_INT = 16 * 1024; static private final double BIG_ENOUGH_FLOOR = BIG_ENOUGH_INT; static private final double CEIL = 0.9999999; // static private final double BIG_ENOUGH_CEIL = NumberUtils // .longBitsToDouble(NumberUtils.doubleToLongBits(BIG_ENOUGH_INT + 1) - 1); static private final double BIG_ENOUGH_CEIL = 16384.999999999996; static private final double BIG_ENOUGH_ROUND = BIG_ENOUGH_INT + 0.5f; /** Returns the largest integer less than or equal to the specified float. This method will only properly floor floats from * -(2^14) to (Float.MAX_VALUE - 2^14). */ static public int floor (float x) { return (int)(x + BIG_ENOUGH_FLOOR) - BIG_ENOUGH_INT; } /** Returns the largest integer less than or equal to the specified float. This method will only properly floor floats that are * positive. Note this method simply casts the float to int. */ static public int floorPositive (float x) { return (int)x; } /** Returns the smallest integer greater than or equal to the specified float. This method will only properly ceil floats from * -(2^14) to (Float.MAX_VALUE - 2^14). */ static public int ceil (float x) { return (int)(x + BIG_ENOUGH_CEIL) - BIG_ENOUGH_INT; } /** Returns the smallest integer greater than or equal to the specified float. This method will only properly ceil floats that * are positive. */ static public int ceilPositive (float x) { return (int)(x + CEIL); } /** Returns the closest integer to the specified float. This method will only properly round floats from -(2^14) to * (Float.MAX_VALUE - 2^14). */ static public int round (float x) { return (int)(x + BIG_ENOUGH_ROUND) - BIG_ENOUGH_INT; } /** Returns the closest integer to the specified float. This method will only properly round floats that are positive. */ static public int roundPositive (float x) { return (int)(x + 0.5f); } public static int constrain(int amount, int low, int high) { return amount < low ? low : (amount > high ? high : amount); } public static long constrain(long amount, long low, long high) { return amount < low ? low : (amount > high ? high : amount); } public static float constrain(float amount, float low, float high) { return amount < low ? low : (amount > high ? high : amount); } }