1 /*
2     SPDX-FileCopyrightText: 2011 See AUTHORS file.
3 
4     SPDX-License-Identifier: Apache-2.0
5 */
6 
7 package org.kde.kstars.math;
8 
9 /** from libgdx: https://github.com/libgdx/libgdx */
10 
11 import java.util.Random;
12 
13 /** Utility and fast math functions.
14  * <p>
15  * Thanks to Riven on JavaGaming.org for the basis of sin/cos/atan2/floor/ceil.
16  * @author Nathan Sweet */
17 public class MathUtils {
18 	static public final float nanoToSec = 1 / 1000000000f;
19 
20 	// ---
21 
22 	static public final float PI = 3.1415927f;
23 
24 	static private final int SIN_BITS = 13; // Adjust for accuracy.
25 	static private final int SIN_MASK = ~(-1 << SIN_BITS);
26 	static private final int SIN_COUNT = SIN_MASK + 1;
27 
28 	static private final float radFull = PI * 2;
29 	static private final float degFull = 360;
30 	static private final float radToIndex = SIN_COUNT / radFull;
31 	static private final float degToIndex = SIN_COUNT / degFull;
32 
33 	static public final float radiansToDegrees = 180f / PI;
34 	static public final float radDeg = radiansToDegrees;
35 	static public final float degreesToRadians = PI / 180;
36 	static public final float degRad = degreesToRadians;
37 
38 	static private class Sin {
39 		static final float[] table = new float[SIN_COUNT];
40 		static {
41 			for (int i = 0; i < SIN_COUNT; i++)
42 				table[i] = (float)Math.sin((i + 0.5f) / SIN_COUNT * radFull);
43 			for (int i = 0; i < 360; i += 90)
44 				table[(int)(i * degToIndex) & SIN_MASK] = (float)Math.sin(i * degreesToRadians);
45 		}
46 	}
47 
48 	static private class Cos {
49 		static final float[] table = new float[SIN_COUNT];
50 		static {
51 			for (int i = 0; i < SIN_COUNT; i++)
52 				table[i] = (float)Math.cos((i + 0.5f) / SIN_COUNT * radFull);
53 			for (int i = 0; i < 360; i += 90)
54 				table[(int)(i * degToIndex) & SIN_MASK] = (float)Math.cos(i * degreesToRadians);
55 		}
56 	}
57 
58 	/** Returns the sine in radians. */
sin(float radians)59 	static public final float sin (float radians) {
60 		return Sin.table[(int)(radians * radToIndex) & SIN_MASK];
61 	}
62 
63 	/** Returns the cosine in radians. */
cos(float radians)64 	static public final float cos (float radians) {
65 		return Cos.table[(int)(radians * radToIndex) & SIN_MASK];
66 	}
67 
68 	/** Returns the sine in radians. */
sinDeg(float degrees)69 	static public final float sinDeg (float degrees) {
70 		return Sin.table[(int)(degrees * degToIndex) & SIN_MASK];
71 	}
72 
73 	/** Returns the cosine in radians. */
cosDeg(float degrees)74 	static public final float cosDeg (float degrees) {
75 		return Cos.table[(int)(degrees * degToIndex) & SIN_MASK];
76 	}
77 
78 	// ---
79 
80 	static private final int ATAN2_BITS = 7; // Adjust for accuracy.
81 	static private final int ATAN2_BITS2 = ATAN2_BITS << 1;
82 	static private final int ATAN2_MASK = ~(-1 << ATAN2_BITS2);
83 	static private final int ATAN2_COUNT = ATAN2_MASK + 1;
84 	static final int ATAN2_DIM = (int)Math.sqrt(ATAN2_COUNT);
85 	static private final float INV_ATAN2_DIM_MINUS_1 = 1.0f / (ATAN2_DIM - 1);
86 
87 	static private class Atan2 {
88 		static final float[] table = new float[ATAN2_COUNT];
89 		static {
90 			for (int i = 0; i < ATAN2_DIM; i++) {
91 				for (int j = 0; j < ATAN2_DIM; j++) {
92 					float x0 = (float)i / ATAN2_DIM;
93 					float y0 = (float)j / ATAN2_DIM;
94 					table[j * ATAN2_DIM + i] = (float)Math.atan2(y0, x0);
95 				}
96 			}
97 		}
98 	}
99 
100 	/** Returns atan2 in radians from a lookup table. */
atan2(float y, float x)101 	static public final float atan2 (float y, float x) {
102 		float add, mul;
103 		if (x < 0) {
104 			if (y < 0) {
105 				y = -y;
106 				mul = 1;
107 			} else
108 				mul = -1;
109 			x = -x;
110 			add = -PI;
111 		} else {
112 			if (y < 0) {
113 				y = -y;
114 				mul = -1;
115 			} else
116 				mul = 1;
117 			add = 0;
118 		}
119 		float invDiv = 1 / ((x < y ? y : x) * INV_ATAN2_DIM_MINUS_1);
120 		int xi = (int)(x * invDiv);
121 		int yi = (int)(y * invDiv);
122 		return (Atan2.table[yi * ATAN2_DIM + xi] + add) * mul;
123 	}
124 
125 	// ---
126 
127 	static public Random random = new Random();
128 
129 	/** Returns a random number between 0 (inclusive) and the specified value (inclusive). */
random(int range)130 	static public final int random (int range) {
131 		return random.nextInt(range + 1);
132 	}
133 
134 	/** Returns a random number between start (inclusive) and end (inclusive). */
random(int start, int end)135 	static public final int random (int start, int end) {
136 		return start + random.nextInt(end - start + 1);
137 	}
138 
randomBoolean()139 	static public final boolean randomBoolean () {
140 		return random.nextBoolean();
141 	}
142 
random()143 	static public final float random () {
144 		return random.nextFloat();
145 	}
146 
147 	/** Returns a random number between 0 (inclusive) and the specified value (inclusive). */
random(float range)148 	static public final float random (float range) {
149 		return random.nextFloat() * range;
150 	}
151 
152 	/** Returns a random number between start (inclusive) and end (inclusive). */
random(float start, float end)153 	static public final float random (float start, float end) {
154 		return start + random.nextFloat() * (end - start);
155 	}
156 
157 	// ---
158 
159 	/** Returns the next power of two. Returns the specified value if the value is already a power of two. */
nextPowerOfTwo(int value)160 	static public int nextPowerOfTwo (int value) {
161 		if (value == 0) return 1;
162 		value--;
163 		value |= value >> 1;
164 		value |= value >> 2;
165 		value |= value >> 4;
166 		value |= value >> 8;
167 		value |= value >> 16;
168 		return value + 1;
169 	}
170 
isPowerOfTwo(int value)171 	static public boolean isPowerOfTwo (int value) {
172 		return value != 0 && (value & value - 1) == 0;
173 	}
174 
175 	// ---
176 
clamp(int value, int min, int max)177 	static public int clamp (int value, int min, int max) {
178 		if (value < min) return min;
179 		if (value > max) return max;
180 		return value;
181 	}
182 
clamp(short value, short min, short max)183 	static public short clamp (short value, short min, short max) {
184 		if (value < min) return min;
185 		if (value > max) return max;
186 		return value;
187 	}
188 
clamp(float value, float min, float max)189 	static public float clamp (float value, float min, float max) {
190 		if (value < min) return min;
191 		if (value > max) return max;
192 		return value;
193 	}
194 
195 	// ---
196 
197 	static private final int BIG_ENOUGH_INT = 16 * 1024;
198 	static private final double BIG_ENOUGH_FLOOR = BIG_ENOUGH_INT;
199 	static private final double CEIL = 0.9999999;
200 	static private final double BIG_ENOUGH_CEIL = NumberUtils
201 		.longBitsToDouble(NumberUtils.doubleToLongBits(BIG_ENOUGH_INT + 1) - 1);
202 	static private final double BIG_ENOUGH_ROUND = BIG_ENOUGH_INT + 0.5f;
203 
204 	/** Returns the largest integer less than or equal to the specified float. This method will only properly floor floats from
205 	 * -(2^14) to (Float.MAX_VALUE - 2^14). */
floor(float x)206 	static public int floor (float x) {
207 		return (int)(x + BIG_ENOUGH_FLOOR) - BIG_ENOUGH_INT;
208 	}
209 
210 	/** Returns the largest integer less than or equal to the specified float. This method will only properly floor floats that are
211 	 * positive. Note this method simply casts the float to int. */
floorPositive(float x)212 	static public int floorPositive (float x) {
213 		return (int)x;
214 	}
215 
216 	/** Returns the smallest integer greater than or equal to the specified float. This method will only properly ceil floats from
217 	 * -(2^14) to (Float.MAX_VALUE - 2^14). */
ceil(float x)218 	static public int ceil (float x) {
219 		return (int)(x + BIG_ENOUGH_CEIL) - BIG_ENOUGH_INT;
220 	}
221 
222 	/** Returns the smallest integer greater than or equal to the specified float. This method will only properly ceil floats that
223 	 * are positive. */
ceilPositive(float x)224 	static public int ceilPositive (float x) {
225 		return (int)(x + CEIL);
226 	}
227 
228 	/** Returns the closest integer to the specified float. This method will only properly round floats from -(2^14) to
229 	 * (Float.MAX_VALUE - 2^14). */
round(float x)230 	static public int round (float x) {
231 		return (int)(x + BIG_ENOUGH_ROUND) - BIG_ENOUGH_INT;
232 	}
233 
234 	/** Returns the closest integer to the specified float. This method will only properly round floats that are positive. */
roundPositive(float x)235 	static public int roundPositive (float x) {
236 		return (int)(x + 0.5f);
237 	}
238 }
239