/* Copyright (C) 2011 Garrett Fleenor
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3.0 of the License, or (at
your option) any later version.
This library is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License (COPYING.txt) for more details.
You should have received a copy of the GNU Lesser General Public License
along with this library; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
This file relicensed with permission from the Spout Project (www.github.com/SpoutDev)
*/
package com.bioxx.libnoise;
import java.awt.Color;
/**
* Class containing various mathematical functions
*/
public class MathHelper {
/**
* A "close to zero" double epsilon value for use
*/
public static final double DBL_EPSILON = Double.longBitsToDouble(0x3cb0000000000000L);
/**
* A "close to zero" float epsilon value for use
*/
public static final float FLT_EPSILON = Float.intBitsToFloat(0x34000000);
public static final double PI = Math.PI;
public static final double SQUARED_PI = PI * PI;
public static final double HALF_PI = 0.5 * PI;
public static final double QUARTER_PI = 0.5 * HALF_PI;
public static final double TWO_PI = 2.0 * PI;
public static final double THREE_PI_HALVES = TWO_PI - HALF_PI;
public static final double DEGTORAD = PI / 180.0;
public static final double RADTODEG = 180.0 / PI;
public static final double SQRTOFTWO = Math.sqrt(2.0);
public static final double HALF_SQRTOFTWO = 0.5 * SQRTOFTWO;
/**
* Calculates the squared length of all axis offsets given
*
* @param values of the axis to get the squared length of
* @return the squared length
*/
public static double lengthSquared(double... values) {
double rval = 0;
for (double value : values) {
rval += value * value;
}
return rval;
}
/**
* Calculates the length of all axis offsets given
*
* @param values of the axis to get the length of
* @return the length
*/
public static double length(double... values) {
return Math.sqrt(lengthSquared(values));
}
/**
* Gets the difference between two angles
* This value is always positive (0 - 180)
*
* @param angle1
* @param angle2
* @return the positive angle difference
*/
public static float getAngleDifference(float angle1, float angle2) {
return Math.abs(wrapAngle(angle1 - angle2));
}
/**
* Gets the difference between two radians
* This value is always positive (0 - PI)
*
* @param radian1
* @param radian2
* @return the positive radian difference
*/
public static double getRadianDifference(double radian1, double radian2) {
return Math.abs(wrapRadian(radian1 - radian2));
}
/**
* Wraps the angle between -180 and 180 degrees
*
* @param angle to wrap
* @return -180 > angle <= 180
*/
public static float wrapAngle(float angle) {
angle %= 360f;
if (angle <= -180) {
return angle + 360;
} else if (angle > 180) {
return angle - 360;
} else {
return angle;
}
}
/**
* Wraps a byte between 0 and 256
*
* @param value to wrap
* @return 0 >= byte < 256
*/
public static byte wrapByte(int value) {
value %= 256;
if (value < 0) {
value += 256;
}
return (byte) value;
}
/**
* Wraps the radian between -PI and PI
*
* @param radian to wrap
* @return -PI > radian <= PI
*/
public static double wrapRadian(double radian) {
radian %= TWO_PI;
if (radian <= -PI) {
return radian + TWO_PI;
} else if (radian > PI) {
return radian - TWO_PI;
} else {
return radian;
}
}
/**
* Rounds a number to the amount of decimals specified
*
* @param input to round
* @param decimals to round to
* @return the rounded number
*/
public static double round(double input, int decimals) {
double p = Math.pow(10, decimals);
return Math.round(input * p) / p;
}
/**
* Calculates the linear interpolation between a and b with the given
* percent
*
* @param a
* @param b
* @param percent
* @return
*/
public static double lerp(double a, double b, double percent) {
return (1 - percent) * a + percent * b;
}
/**
* Calculates the linear interpolation between a and b with the given
* percent
*
* @param a
* @param b
* @param percent
* @return
*/
public static float lerp(float a, float b, float percent) {
return (1 - percent) * a + percent * b;
}
/**
* Calculates the linear interpolation between a and b with the given
* percent
*
* @param a
* @param b
* @param percent
* @return
*/
public static int lerp(int a, int b, double percent) {
return (int) ((1 - percent) * a + percent * b);
}
/**
* Calculates the linear interpolation between a and b with the given
* percent
*
* @param a
* @param b
* @param percent
* @return
*/
public static Color lerp(Color a, Color b, double percent) {
int red = lerp(a.getRed(), b.getRed(), percent);
int blue = lerp(a.getBlue(), b.getBlue(), percent);
int green = lerp(a.getGreen(), b.getGreen(), percent);
int alpha = lerp(a.getAlpha(), b.getAlpha(), percent);
return new Color(red, green, blue, alpha);
}
public static Color blend(Color a, Color b) {
int red = lerp(a.getRed(), b.getRed(), (a.getAlpha()/255.0));
int blue = lerp(a.getBlue(), b.getBlue(), (a.getAlpha()/255.0));
int green = lerp(a.getGreen(), b.getGreen(), (a.getAlpha()/255.0));
int alpha = lerp(a.getAlpha(), b.getAlpha(), (a.getAlpha()/255.0));
return new Color(red, green, blue, alpha);
}
public static double clamp(double value, double low, double high) {
if (value < low) {
return low;
}
if (value > high) {
return high;
}
return value;
}
public static int clamp(int value, int low, int high) {
if (value < low) {
return low;
}
if (value > high) {
return high;
}
return value;
}
//Fast Math Implementation
public final static double cos(final double x) {
return sin(x + (x > HALF_PI ? -THREE_PI_HALVES : HALF_PI));
}
public final static double sin(double x) {
x = sin_a * x * Math.abs(x) + sin_b * x;
return sin_p * (x * Math.abs(x) - x) + x;
}
public final static double tan(final double x) {
return sin(x) / cos(x);
}
public final static double asin(final double x) {
return x * (Math.abs(x) * (Math.abs(x) * asin_a + asin_b) + asin_c) + Math.signum(x) * (asin_d - Math.sqrt(1 - x * x));
}
public final static double acos(final double x) {
return HALF_PI - asin(x);
}
public final static double atan(final double x) {
return Math.abs(x) < 1 ? x / (1 + atan_a * x * x) : Math.signum(x) * HALF_PI - x / (x * x + atan_a);
}
public final static double inverseSqrt(double x) {
final double xhalves = 0.5d * x;
x = Double.longBitsToDouble(0x5FE6EB50C7B537AAl - (Double.doubleToRawLongBits(x) >> 1));
return x * (1.5d - xhalves * x * x);
}
public final static double sqrt(final double x) {
return x * inverseSqrt(x);
}
private static final double sin_a = -4 / SQUARED_PI;
private static final double sin_b = 4 / PI;
private static final double sin_p = 9d / 40;
private final static double asin_a = -0.0481295276831013447d;
private final static double asin_b = -0.343835993947915197d;
private final static double asin_c = 0.962761848425913169d;
private final static double asin_d = 1.00138940860107040d;
private final static double atan_a = 0.280872d;
// Integer Maths
public static int floor(double x) {
int y = (int) x;
if (x < y) {
return y - 1;
}
return y;
}
public static int floor(float x) {
int y = (int) x;
if (x < y) {
return y - 1;
}
return y;
}
/**
* Gets the maximum byte value from two values
*
* @param value1
* @param value2
* @return the maximum value
*/
public static byte max(byte value1, byte value2) {
return value1 > value2 ? value1 : value2;
}
/**
* Rounds an integer up to the next power of 2.
*
* @param x
* @return the lowest power of 2 greater or equal to x
*/
public static int roundUpPow2(int x) {
if (x <= 0) {
return 1;
} else if (x > 0x40000000) {
throw new IllegalArgumentException("Rounding " + x + " to the next highest power of two would exceed the int range");
} else {
x--;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
x++;
return x;
}
}
/**
* Casts a value to a float. May return null.
*
* @param o
* @return
*/
public static Float castFloat(Object o) {
if (o == null) {
return null;
}
if (o instanceof Number) {
return ((Number) o).floatValue();
}
try {
return Float.valueOf(o.toString());
} catch (NumberFormatException e) {
return null;
}
}
/**
* Casts a value to a byte. May return null.
*
* @param o
* @return
*/
public static Byte castByte(Object o) {
if (o == null) {
return null;
}
if (o instanceof Number) {
return ((Number)o).byteValue();
}
try {
return Byte.valueOf(o.toString());
} catch (NumberFormatException e) {
return null;
}
}
/**
* Casts a value to a short. May return null.
*
* @param o
* @return
*/
public static Short castShort(Object o) {
if (o == null) {
return null;
}
if (o instanceof Number) {
return ((Number)o).shortValue();
}
try {
return Short.valueOf(o.toString());
} catch (NumberFormatException e) {
return null;
}
}
/**
* Casts a value to an integer. May return null.
*
* @param o
* @return
*/
public static Integer castInt(Object o) {
if (o == null) {
return null;
}
if (o instanceof Number) {
return ((Number)o).intValue();
}
try {
return Integer.valueOf(o.toString());
} catch (NumberFormatException e) {
return null;
}
}
/**
* Casts a value to a double. May return null.
*
* @param o
* @return
*/
public static Double castDouble(Object o) {
if (o == null) {
return null;
}
if (o instanceof Number) {
return ((Number)o).doubleValue();
}
try {
return Double.valueOf(o.toString());
} catch (NumberFormatException e) {
return null;
}
}
/**
* Casts a value to a long. May return null.
*
* @param o
* @return
*/
public static Long castLong(Object o) {
if (o == null) {
return null;
}
if (o instanceof Number) {
return ((Number)o).longValue();
}
try {
return Long.valueOf(o.toString());
} catch (NumberFormatException e) {
return null;
}
}
/**
* Casts a value to a boolean. May return null.
*
* @param o
* @return
*/
public static Boolean castBoolean(Object o) {
if (o == null) {
return null;
}
if (o instanceof Boolean) {
return (Boolean) o;
} else if (o instanceof String) {
try {
return Boolean.parseBoolean((String) o);
} catch (IllegalArgumentException e) {
return null;
}
}
return null;
}
/**
* Calculates the mean of a set of values
*
* @param values to calculate the mean of
* @return the mean
*/
public static int mean(int... values) {
int sum = 0;
for (int v : values) {
sum += v;
}
return sum/values.length;
}
/**
* Calculates the mean of a set of values.
*
* @param values to calculate the mean of
*/
public static double mean(double... values) {
double sum = 0;
for (double v : values) {
sum += v;
}
return sum/values.length;
}
}