package dwarf.util;
import dwarf.DwarfException;
/**
* Provides an interface for math functions and constants.
*
* @author Matthew 'siD' Van der Bijl
*
* @see java.lang.Math
*/
public final class math {
/**
* you can not instantiate this class.
*/
public math() throws UnsupportedOperationException {
// Prevents instantiation of this class.
throw new UnsupportedOperationException(
"you can not instantiate this class.");
}
/**
* The value PI as a double. (180 degrees)
*/
public static final double PI = Math.PI;
/**
* The value 2PI as a double. (360 degrees)
*/
public static final double TWO_PI = 2.0f * PI;
/**
* The value PI/2 as a double. (90 degrees)
*/
public static final double HALF_PI = 0.5f * PI;
/**
* The value PI/4 as a double. (45 degrees)
*/
public static final double QUARTER_PI = 0.25f * PI;
/**
* The value 1/PI as a double.
*/
public static final double INV_PI = 1.0f / PI;
/**
* The value 1/(2PI) as a double.
*/
public static final double INV_TWO_PI = 1.0f / TWO_PI;
public static int pow(int base, int power) throws DwarfException {
if (power < 0) {
throw new DwarfException("This function does not support negative powers.");
} else {
int ans = (base);
for (int i = 1; i < power; i++) {
ans *= (base);
}
return (ans);
}
}
public static float pow(float base, float power) {
float ans = (base);
for (int i = 1; i < power; i++) {
ans *= (base);
}
return (ans);
}
public static double pow(double base, double power) {
double ans = (base);
for (int i = 1; i < power; i++) {
ans *= (base);
}
return (ans);
}
public static boolean isPrime(int num) {
if (num != 2) {
if (num % 2 == 0 || num == 1) {
return (false);
} else {
for (int i = 3; i < Math.sqrt(num) + 1; i += 2) {
if (num % i == 0) {
return (false);
}
}
}
}
return (true);
}
public static boolean isPrime(long num) {
if (num != 2) {
if (num % 2 == 0 || num == 1) {
return false;
} else {
for (long i = 3; i < Math.sqrt(num) + 1; i += 2) {
if (num % i == 0) {
return false;
}
}
}
}
return true;
}
public static long fact(long n) {
if (n <= 1) {
return 1;
} else {
return n * fact(n - 1);
}
}
public static int fact(int n) {
if (n <= 1) {
return 1;
} else {
return n * fact(n - 1);
}
}
public static int fib(int num) {
if (num < 2) {
return (num);
} else {
return fib(num - 1) + fib(num - 2);
}
}
/**
* Determines the greatest common divisor of a pair of natural numbers using
* the Euclidean algorithm. This method only works with natural numbers. If
* negative integers are passed in, the absolute values will be used. The
* return value is always positive.
*
* @param a The first value.
* @param b The second value.
* @return The greatest common divisor.
*/
public static long highestCommonFactor(long a, long b) {
a = Math.abs(a);
b = Math.abs(b);
while (b != 0) {
long temp = b;
b = a % b;
a = temp;
}
return a;
}
/**
* Calculate logarithms for arbitrary bases.
*
* @param base The base for the logarithm.
* @param arg The value to calculate the logarithm for.
* @return The log of {@code arg} in the specified {@code base}.
*/
public static double log(double base, double arg) {
// Use natural logarithms and translate the base.
return Math.log(arg) / Math.log(base);
}
public static boolean isMultiple(long number, long value) {
return isFactor(value, number);
}
public static boolean isFactor(long number, long value) {
if (number == 0 || value == 0) {
return false;
} else {
return number % value == 0;
}
}
public static boolean hasDecimal(double number) {
return number % 1.0 != 0.0;
}
public static boolean isWhole(double number) {
return !hasDecimal(number);
}
public static boolean isEven(int input) {
return (input % 2) == 0;
}
public static boolean isOdd(int input) {
return !isEven(input);
}
public static boolean isPowerOfTwo(int number) {
return (number > 0) && (number & (number - 1)) == 0;
}
public static int nearestPowerOfTwo(int number) {
return (int) Math.pow(2, Math.ceil(Math.log(number) / Math.log(2)));
}
/**
* 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 Begining 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;
} else if (scale <= 0f) {
return startValue;
} else if (scale >= 1f) {
return endValue;
} else {
return ((1f - scale) * startValue) + (scale * endValue);
}
}
/**
* Returns 1/sqrt(fValue)
*
* @param fValue The value to process.
* @return 1/sqrt(fValue)
* @see java.lang.Math#sqrt(double)
*/
public static float invSqrt(float fValue) {
return (float) (1.0f / Math.sqrt(fValue));
}
/**
* Returns the logarithm of value with given base, calculated as
* log(value)/log(base), so that pow(base, return)==value (contributed by
* vear)
*
* @param value The value to log.
* @param base Base of logarithm.
* @return The logarithm of value with given base
*/
public static float log(float value, float base) {
return (float) (Math.log(value) / Math.log(base));
}
public static float sqr(float fValue) {
return fValue * fValue;
}
public static double sqr(double dValue) {
return dValue * dValue;
}
/**
* Returns the square root of a given value.
*
* @param fValue The value to sqrt.
* @return The square root of the given value.
* @see java.lang.Math#sqrt(double)
*/
public static float sqrt(float fValue) {
return (float) Math.sqrt(fValue);
}
/**
* Returns the tangent of a value. If USE_FAST_TRIG is enabled, an
* approximate value is returned. Otherwise, a direct value is used.
*
* @param fValue The value to tangent, in radians.
* @return The tangent of fValue.
* @see java.lang.Math#tan(double)
*/
public static float tan(float fValue) {
return (float) Math.tan(Math.toDegrees(fValue));
}
/**
* Returns the tangent of a value. If USE_FAST_TRIG is enabled, an
* approximate value is returned. Otherwise, a direct value is used.
*
* @param dValue The value to tangent, in radians.
* @return The tangent of fValue.
* @see java.lang.Math#tan(double)
*/
public static double tan(double dValue) {
return Math.tan(Math.toDegrees(dValue));
}
/**
* Returns the cosine of a value. If USE_FAST_TRIG is enabled, an
* approximate value is returned. Otherwise, a direct value is used.
*
* @param fValue The value to cosine, in radians.
* @return The tangent of dValue.
* @see java.lang.Math#cos(double)
*/
public static float cos(float fValue) {
return (float) Math.cos(Math.toDegrees(fValue));
}
/**
* Returns the cosine of a value. If USE_FAST_TRIG is enabled, an
* approximate value is returned. Otherwise, a direct value is used.
*
* @param dValue The value to cosine, in radians.
* @return The cos of dValue.
* @see java.lang.Math#cos(double)
*/
public static double cos(double dValue) {
return Math.cos(Math.toDegrees(dValue));
}
/**
* Returns the sine of a value. If USE_FAST_TRIG is enabled, an approximate
* value is returned. Otherwise, a direct value is used.
*
* @param fValue The value to sin, in radians.
* @return The sine of fValue.
* @see java.lang.Math#sin(double)
*/
public static float sin(float fValue) {
return (float) Math.sin(Math.toDegrees(fValue));
}
/**
* Returns the sine of a value. If USE_FAST_TRIG is enabled, an approximate
* value is returned. Otherwise, a direct value is used.
*
* @param dValue The value to sine, in radians.
* @return The sine of dValue.
* @see java.lang.Math#sin(double)
*/
public static double sin(double dValue) {
return Math.sin(Math.toDegrees(dValue));
}
/**
* 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) {
if (iValue > 0) {
return 1;
} else if (iValue < 0) {
return -1;
} else {
return 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);
}
/**
* Takes an value and expresses it in terms of min to max.
*
* @param val - the angle to normalize (in radians)
* @param min the minimum value
* @param max the maximum value
* @return the normalized angle (also in radians)
*/
public static float normalize(float val, float min, float max) {
if (Float.isInfinite(val) || Float.isNaN(val)) {
return 0f;
}
float range = max - min;
while (val > max) {
val -= range;
}
while (val < min) {
val += range;
}
return val;
}
/**
* @param x the value whose sign is to be adjusted.
* @param y the value whose sign is to be used.
* @return x with its sign changed to match the sign of y.
*/
public static float copysign(float x, float y) {
if (y >= 0 && x <= -0) {
return -x;
} else if (y < 0 && x >= 0) {
return -x;
} else {
return x;
}
}
/**
* Take a float input and clamp it between min and max.
*
* @param input the value to be inputed
* @param min the minimum value
* @param max the maximum value
* @return clamped input
*/
public static float clamp(float input, float min, float max) {
return (input < min) ? min : (input > max) ? max : input;
}
/**
* Clamps the given float to be between 0 and 1.
*
* @param input the value to be inputed
* @return input clamped between 0 and 1.
*/
public static float saturate(float input) {
return clamp(input, 0f, 1f);
}
/**
* 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 double extrapolateLinear(double scale, double startValue, double 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 Vector3 extrapolateLinear(double scale, Vector3 startValue, Vector3 endValue) {
double x, y, z;
x = extrapolateLinear(scale, startValue.getX(), endValue.getX());
y = extrapolateLinear(scale, startValue.getY(), endValue.getY());
z = extrapolateLinear(scale, startValue.getZ(), endValue.getZ());
return new Vector3(x, y, z);
}
/**
* Interpolate a spline between at least 4 control points following the
* Catmull-Rom equation. here is the interpolation matrix m = [ 0.0 1.0 0.0
* 0.0 ] [-T 0.0 T 0.0 ] [ 2T T-3 3-2T -T ] [-T 2-T T-2 T ] where T is the
* curve tension the result is a value between p1 and p2, t=0 for p1, t=1
* for p2
*
* @param u value from 0 to 1
* @param T The tension of the curve
* @param p0 control point 0
* @param p1 control point 1
* @param p2 control point 2
* @param p3 control point 3
* @return catmull-Rom interpolation
*/
public static double interpolateCatmullRom(double u, double T, double p0, double p1, double p2, double p3) {
double c1, c2, c3, c4;
c1 = p1;
c2 = -1.0f * T * p0 + T * p2;
c3 = 2 * T * p0 + (T - 3) * p1 + (3 - 2 * T) * p2 + -T * p3;
c4 = -T * p0 + (2 - T) * p1 + (T - 2) * p2 + T * p3;
return (((c4 * u + c3) * u + c2) * u + c1);
}
/**
* Interpolate a spline between at least 4 control points following the
* Catmull-Rom equation. here is the interpolation matrix m = [ 0.0 1.0 0.0
* 0.0 ] [-T 0.0 T 0.0 ] [ 2T T-3 3-2T -T ] [-T 2-T T-2 T ] where T is the
* tension of the curve the result is a value between p1 and p2, t=0 for p1,
* t=1 for p2
*
* @param u value from 0 to 1
* @param T The tension of the curve
* @param p0 control point 0
* @param p1 control point 1
* @param p2 control point 2
* @param p3 control point 3
* @return catmull-Rom interpolation
*/
public static Vector3 interpolateCatmullRom(float u, float T, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3) {
double x, y, z;
x = interpolateCatmullRom(u, T, p0.getX(), p1.getX(), p2.getX(), p3.getX());
y = interpolateCatmullRom(u, T, p0.getY(), p1.getY(), p2.getY(), p3.getY());
z = interpolateCatmullRom(u, T, p0.getZ(), p1.getZ(), p2.getZ(), p3.getZ());
return new Vector3(x, y, z);
}
/**
* Interpolate a spline between at least 4 control points following the
* Bezier equation. here is the interpolation matrix m = [ -1.0 3.0 -3.0 1.0
* ] [ 3.0 -6.0 3.0 0.0 ] [ -3.0 3.0 0.0 0.0 ] [ 1.0 0.0 0.0 0.0 ] where T
* is the curve tension the result is a value between p1 and p3, t=0 for p1,
* t=1 for p3
*
* @param u value from 0 to 1
* @param p0 control point 0
* @param p1 control point 1
* @param p2 control point 2
* @param p3 control point 3
* @return Bezier interpolation
*/
public static double interpolateBezier(double u, double p0, double p1, double p2, double p3) {
double oneMinusU = 1.0f - u;
double oneMinusU2 = oneMinusU * oneMinusU;
double u2 = u * u;
return (p0 * oneMinusU2 * oneMinusU
+ 3.0f * p1 * u * oneMinusU2
+ 3.0f * p2 * u2 * oneMinusU
+ p3 * u2 * u);
}
/**
* Interpolate a spline between at least 4 control points following the
* Bezier equation. here is the interpolation matrix m = [ -1.0 3.0 -3.0 1.0
* ] [ 3.0 -6.0 3.0 0.0 ] [ -3.0 3.0 0.0 0.0 ] [ 1.0 0.0 0.0 0.0 ] where T
* is the tension of the curve the result is a value between p1 and p3, t=0
* for p1, t=1 for p3
*
* @param u value from 0 to 1
* @param p0 control point 0
* @param p1 control point 1
* @param p2 control point 2
* @param p3 control point 3
* @return Bezier interpolation
*/
public static Vector3 interpolateBezier(float u, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3) {
double x, y, z;
x = interpolateBezier(u, p0.getX(), p1.getX(), p2.getX(), p3.getX());
y = interpolateBezier(u, p0.getY(), p1.getY(), p2.getY(), p3.getY());
z = interpolateBezier(u, p0.getZ(), p1.getZ(), p2.getZ(), p3.getZ());
return new Vector3(x, y, z);
}
/**
* 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 java.lang.Math#acos(double)
*/
public static double acos(float fValue) {
if (-1.0f < fValue) {
if (fValue < 1.0f) {
return Math.acos(fValue);
} else {
return 0.0f;
}
} else {
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 java.lang.Math#asin(double)
*/
public static double asin(float fValue) {
if (-1.0f < fValue) {
if (fValue < 1.0f) {
return Math.asin(fValue);
} else {
return HALF_PI;
}
} else {
return -HALF_PI;
}
}
public static float clampf(float v, float min, float max) {
if (v < min) {
return min;
} else if (v > max) {
return max;
} else {
return v;
}
}
/**
* Returns the lowest positive root of the quadric equation given by a* x *
* x + b * x + c = 0. If no solution is given Float.Nan is returned.
*
* @param a the first coefficient of the quadric equation
* @param b the second coefficient of the quadric equation
* @param c the third coefficient of the quadric equation
* @return the lowest positive root or Float.Nan
*/
static public float lowestPositiveRoot(float a, float b, float c) {
float det = b * b - 4 * a * c;
if (det < 0) {
return Float.NaN;
} else {
float sqrtD = (float) Math.sqrt(det);
float invA = 1 / (2 * a);
float r1 = (-b - sqrtD) * invA;
float r2 = (-b + sqrtD) * invA;
if (r1 > r2) {
float tmp = r2;
r2 = r1;
r1 = tmp;
} else if (r1 > 0) {
return r1;
} else if (r2 > 0) {
return r2;
}
return Float.NaN;
}
}
/**
* Returns the next power of two. Returns the specified value if the value
* is already a power of two.
*
* @param value the number to tested
* @return the next power of two of the entered value
*/
public static int nextPowerOfTwo(int value) {
if (value == 0) {
return 1;
} else {
value--;
value |= value >> 1;
value |= value >> 2;
value |= value >> 4;
value |= value >> 8;
value |= value >> 16;
return value + 1;
}
}
}