![JAR search and dependency download from the Maven repository](/logo.png)
com.ardor3d.math.MathUtils Maven / Gradle / Ivy
The newest version!
/**
* Copyright (c) 2008-2012 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
* Ardor3D is free software: you can redistribute it and/or modify it
* under the terms of its license which may be found in the accompanying
* LICENSE file or at .
*/
package com.ardor3d.math;
import java.util.Random;
import com.ardor3d.math.type.ReadOnlyVector3;
public class MathUtils {
/** A "close to zero" double epsilon value for use */
public static final double EPSILON = 2.220446049250313E-16d;
/** A "close to zero" double epsilon value for use */
public static final double ZERO_TOLERANCE = 0.0001;
public static final double ONE_THIRD = 1.0 / 3.0;
/** The value PI as a double. (180 degrees) */
public static final double PI = Math.PI;
/** The value PI^2 as a double. */
public final static double SQUARED_PI = MathUtils.PI * MathUtils.PI;
/** The value 2PI as a double. (360 degrees) */
public static final double TWO_PI = 2.0 * MathUtils.PI;
/** The value PI/2 as a double. (90 degrees) */
public static final double HALF_PI = 0.5 * MathUtils.PI;
/** The value PI/4 as a double. (45 degrees) */
public static final double QUARTER_PI = 0.25 * MathUtils.PI;
/** The value 3/4 PI as a double. (135 degrees) */
public final static double THREE_PI_HALVES = MathUtils.TWO_PI - MathUtils.HALF_PI;
/** The value 1/PI as a double. */
public static final double INV_PI = 1.0 / MathUtils.PI;
/** The value 1/(2PI) as a double. */
public static final double INV_TWO_PI = 1.0 / MathUtils.TWO_PI;
/** A value to multiply a degree value by, to convert it to radians. */
public static final double DEG_TO_RAD = MathUtils.PI / 180.0;
/** A value to multiply a radian value by, to convert it to degrees. */
public static final double RAD_TO_DEG = 180.0 / MathUtils.PI;
/** A precreated random object for random numbers. */
public static final Random rand = new Random(System.currentTimeMillis());
/**
* Fast Trig functions for x86. This forces the trig functiosn to stay within the safe area on the x86 processor
* (-45 degrees to +45 degrees) The results may be very slightly off from what the Math and StrictMath trig
* functions give due to rounding in the angle reduction but it will be very very close.
*
* note: code from wiki posting on java.net by jeffpk
*/
private static double reduceSinAngle(double radians) {
radians %= MathUtils.TWO_PI; // put us in -2PI to +2PI space
if (Math.abs(radians) > MathUtils.PI) { // put us in -PI to +PI space
radians = radians - MathUtils.TWO_PI;
}
if (Math.abs(radians) > MathUtils.HALF_PI) {// put us in -PI/2 to +PI/2 space
radians = MathUtils.PI - radians;
}
return radians;
}
/**
* Returns sine of a value.
*
* note: code from wiki posting on java.net by jeffpk
*
* @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) {
dValue = reduceSinAngle(dValue); // limits angle to between -PI/2 and +PI/2
if (Math.abs(dValue) <= MathUtils.QUARTER_PI) {
return MathConstants.useFastMath ? FastMath.sin(dValue) : Math.sin(dValue);
}
return MathConstants.useFastMath ? FastMath.cos(MathUtils.HALF_PI - dValue) : Math.cos(MathUtils.HALF_PI
- dValue);
}
/**
* Returns cos of a value.
*
* @param dValue
* The value to cosine, in radians.
* @return The cosine of dValue.
* @see java.lang.Math#cos(double)
*/
public static double cos(final double dValue) {
return sin(dValue + MathUtils.HALF_PI);
}
public static double sqrt(final double dValue) {
return MathConstants.useFastMath ? FastMath.sqrt(dValue) : Math.sqrt(dValue);
}
public static double inverseSqrt(final double dValue) {
return MathConstants.useFastMath ? FastMath.inverseSqrt(dValue) : 1 / Math.sqrt(dValue);
}
public static double atan(final double dValue) {
return MathConstants.useFastMath ? FastMath.atan(dValue) : Math.atan(dValue);
}
public static double asin(final double dValue) {
return MathConstants.useFastMath ? FastMath.asin(dValue) : Math.asin(dValue);
}
public static double tan(final double dValue) {
return MathConstants.useFastMath ? FastMath.tan(dValue) : Math.tan(dValue);
}
public static double acos(final double dValue) {
return MathConstants.useFastMath ? FastMath.acos(dValue) : Math.acos(dValue);
}
/**
* Converts a point from Spherical coordinates to Cartesian (using positive Y as up) and stores the results in the
* store var.
*
* @param sphereCoords
* (Radius, Azimuth, Polar)
* @param store
* the vector to store the result in for return. If null, a new vector object is created and returned.
*/
public static Vector3 sphericalToCartesian(final ReadOnlyVector3 sphereCoords, final Vector3 store) {
final double a = sphereCoords.getX() * cos(sphereCoords.getZ());
final double x = a * cos(sphereCoords.getY());
final double y = sphereCoords.getX() * sin(sphereCoords.getZ());
final double z = a * sin(sphereCoords.getY());
Vector3 rVal = store;
if (rVal == null) {
rVal = new Vector3();
}
return rVal.set(x, y, z);
}
/**
* Converts a point from Cartesian coordinates (using positive Y as up) to Spherical and stores the results in the
* store var. (Radius, Azimuth, Polar)
*
* @param cartCoords
* @param store
* the vector to store the result in for return. If null, a new vector object is created and returned.
*/
public static Vector3 cartesianToSpherical(final ReadOnlyVector3 cartCoords, final Vector3 store) {
final double cartX = Math.abs(cartCoords.getX()) <= MathUtils.EPSILON ? MathUtils.EPSILON : cartCoords.getX();
final double cartY = cartCoords.getY();
final double cartZ = cartCoords.getZ();
final double x = sqrt(cartX * cartX + cartY * cartY + cartZ * cartZ);
final double y = atan(cartZ / cartX) + (cartX < 0.0 ? MathUtils.PI : 0);
final double z = asin(cartY / x);
Vector3 rVal = store;
if (rVal == null) {
rVal = new Vector3();
}
return rVal.set(x, y, z);
}
/**
* Converts a point from Spherical coordinates to Cartesian (using positive Z as up) and stores the results in the
* store var.
*
* @param sphereCoords
* (Radius, Azimuth, Polar)
* @param store
* the vector to store the result in for return. If null, a new vector object is created and returned.
*/
public static Vector3 sphericalToCartesianZ(final ReadOnlyVector3 sphereCoords, final Vector3 store) {
final double a = sphereCoords.getX() * cos(sphereCoords.getZ());
final double x = a * cos(sphereCoords.getY());
final double y = a * sin(sphereCoords.getY());
final double z = sphereCoords.getX() * sin(sphereCoords.getZ());
Vector3 rVal = store;
if (rVal == null) {
rVal = new Vector3();
}
return rVal.set(x, y, z);
}
/**
* Converts a point from Cartesian coordinates (using positive Z as up) to Spherical and stores the results in the
* store var. (Radius, Azimuth, Polar)
*
* @param cartCoords
* @param store
* the vector to store the result in for return. If null, a new vector object is created and returned.
*/
public static Vector3 cartesianZToSpherical(final ReadOnlyVector3 cartCoords, final Vector3 store) {
final double cartX = Math.abs(cartCoords.getX()) <= MathUtils.EPSILON ? MathUtils.EPSILON : cartCoords.getX();
final double cartY = cartCoords.getY();
final double cartZ = cartCoords.getZ();
final double x = sqrt(cartX * cartX + cartY * cartY + cartZ * cartZ);
final double y = asin(cartY / x);
final double z = atan(cartZ / cartX) + (cartX < 0.0 ? MathUtils.PI : 0);
Vector3 rVal = store;
if (rVal == null) {
rVal = new Vector3();
}
return rVal.set(x, y, z);
}
/**
* Returns true if the number is a power of 2 (2,4,8,16...)
*
* A good implementation found on the Java boards. note: a number is a power of two if and only if it is the
* smallest number with that number of significant bits. Therefore, if you subtract 1, you know that the new number
* will have fewer bits, so ANDing the original number with anything less than it will give 0.
*
* @param number
* The number to test.
* @return True if it is a power of two.
*/
public static boolean isPowerOfTwo(final int number) {
return number > 0 && (number & number - 1) == 0;
}
/**
* @param number
* @return the closest power of two to the given number.
*/
public static int nearestPowerOfTwo(final int number) {
return (int) Math.pow(2, Math.ceil(Math.log(number) / Math.log(2)));
}
/**
* @param value
* @param base
* @return the logarithm of value with given base, calculated as log(value)/log(base) such that pow(base,
* return)==value
*/
public static double log(final double value, final double base) {
return Math.log(value) / Math.log(base);
}
/**
* Sets the seed to use for "random" operations. The default is the current system milliseconds.
*
* @param seed
*/
public static void setRandomSeed(final long seed) {
MathUtils.rand.setSeed(seed);
}
/**
* Returns a random double between 0 and 1.
*
* @return A random double between 0.0 (inclusive) to 1.0 (exclusive).
*/
public static double nextRandomDouble() {
return MathUtils.rand.nextDouble();
}
/**
* Returns a random float between 0 and 1.
*
* @return A random float between 0.0f (inclusive) to 1.0f (exclusive).
*/
public static float nextRandomFloat() {
return MathUtils.rand.nextFloat();
}
/**
* @return A random int between Integer.MIN_VALUE and Integer.MAX_VALUE.
*/
public static int nextRandomInt() {
return MathUtils.rand.nextInt();
}
/**
* Returns a random int between min and max.
*
* @return A random int between min (inclusive) to max (inclusive).
*/
public static int nextRandomInt(final int min, final int max) {
return (int) (nextRandomFloat() * (max - min + 1)) + min;
}
/**
*
* @param percent
* @param startValue
* @param endValue
* @return
*/
public static float lerp(final float percent, final float startValue, final float endValue) {
if (startValue == endValue) {
return startValue;
}
return (1 - percent) * startValue + percent * endValue;
}
/**
*
* @param percent
* @param startValue
* @param endValue
* @return
*/
public static double lerp(final double percent, final double startValue, final double endValue) {
if (startValue == endValue) {
return startValue;
}
return (1 - percent) * startValue + percent * endValue;
}
/**
* plot a given value on the cubic S-curve: 3t^2 - 2t^3
*
* @param t
* our input value
* @return the plotted value
*/
public static float scurve3(final float t) {
final float t2 = t * t;
final float t3 = t * t2;
return 3f * t2 - 2f * t3;
}
/**
* plot a given value on the cubic S-curve: 3t^2 - 2t^3
*
* @param t
* our input value
* @return the plotted value
*/
public static double scurve3(final double t) {
final double t2 = t * t;
final double t3 = t * t2;
return 3. * t2 - 2. * t3;
}
/**
* plot a given value on the quintic S-curve: 6t^5 - 15t^4 + 10t^3
*
* @param t
* our input value
* @return the plotted value
*/
public static float scurve5(final float t) {
final float t3 = t * t * t;
final float t4 = t * t3;
final float t5 = t * t4;
return 6f * t5 - 15f * t4 + 10f * t3;
}
/**
* plot a given value on the quintic S-curve: 6t^5 - 15t^4 + 10t^3
*
* @param t
* our input value
* @return the plotted value
*/
public static double scurve5(final double t) {
final double t3 = t * t * t;
final double t4 = t * t3;
final double t5 = t * t4;
return 6. * t5 - 15. * t4 + 10. * t3;
}
/**
*
* @param left
* @param right
* @param bottom
* @param top
* @param nearZ
* @param farZ
* @param store
*/
public static void matrixFrustum(final double left, final double right, final double bottom, final double top,
final double nearZ, final double farZ, final Matrix4 store) {
final double x = 2.0 * nearZ / (right - left);
final double y = 2.0 * nearZ / (top - bottom);
final double a = (right + left) / (right - left);
final double b = (top + bottom) / (top - bottom);
final double c = -(farZ + nearZ) / (farZ - nearZ);
final double d = -(2.0 * farZ * nearZ) / (farZ - nearZ);
store.set(x, 0.0, 0.0, 0.0, 0.0, y, 0.0, 0.0, a, b, c, -1.0, 0.0, 0.0, d, 0.0);
}
/**
*
* @param left
* @param right
* @param bottom
* @param top
* @param nearZ
* @param farZ
* @param store
*/
public static void matrixOrtho(final double left, final double right, final double bottom, final double top,
final double nearZ, final double farZ, final Matrix4 store) {
store.set(2.0 / (right - left), 0.0, 0.0, 0.0, 0.0, 2.0 / (top - bottom), 0.0, 0.0, 0.0, 0.0, -2.0
/ (farZ - nearZ), 0.0, -(right + left) / (right - left), -(top + bottom) / (top - bottom),
-(farZ + nearZ) / (farZ - nearZ), 1.0);
}
/**
*
* @param fovY
* @param aspect
* @param zNear
* @param zFar
* @param store
*/
public static void matrixPerspective(final double fovY, final double aspect, final double zNear, final double zFar,
final Matrix4 store) {
final double height = zNear * tan(fovY * 0.5 * MathUtils.DEG_TO_RAD);
final double width = height * aspect;
matrixFrustum(-width, width, -height, height, zNear, zFar, store);
}
/**
*
* @param position
* @param target
* @param up
* @param store
*/
public static void matrixLookAt(final ReadOnlyVector3 position, final ReadOnlyVector3 target,
final ReadOnlyVector3 worldUp, final Matrix4 store) {
final Vector3 direction = Vector3.fetchTempInstance();
final Vector3 side = Vector3.fetchTempInstance();
final Vector3 up = Vector3.fetchTempInstance();
direction.set(target).subtractLocal(position).normalizeLocal();
direction.cross(worldUp, side).normalizeLocal();
side.cross(direction, up);
store.set(side.getX(), up.getX(), -direction.getX(), 0.0, side.getY(), up.getY(), -direction.getY(), 0.0,
side.getZ(), up.getZ(), -direction.getZ(), 0.0, side.getX() * -position.getX() + side.getY()
* -position.getY() + side.getZ() * -position.getZ(), up.getX() * -position.getX() + up.getY()
* -position.getY() + up.getZ() * -position.getZ(), -direction.getX() * -position.getX()
+ -direction.getY() * -position.getY() + -direction.getZ() * -position.getZ(), 1.0);
Vector3.releaseTempInstance(up);
Vector3.releaseTempInstance(side);
Vector3.releaseTempInstance(direction);
}
/**
*
* @param position
* @param target
* @param up
* @param store
*/
public static void matrixLookAt(final ReadOnlyVector3 position, final ReadOnlyVector3 target,
final ReadOnlyVector3 worldUp, final Matrix3 store) {
final Vector3 direction = Vector3.fetchTempInstance();
final Vector3 side = Vector3.fetchTempInstance();
final Vector3 up = Vector3.fetchTempInstance();
direction.set(target).subtractLocal(position).normalizeLocal();
direction.cross(worldUp, side).normalizeLocal();
side.cross(direction, up);
store.set(side.getX(), up.getX(), -direction.getX(), side.getY(), up.getY(), -direction.getY(), side.getZ(),
up.getZ(), -direction.getZ());
Vector3.releaseTempInstance(up);
Vector3.releaseTempInstance(side);
Vector3.releaseTempInstance(direction);
}
/**
* Faster floor function. Does not handle NaN and Infinity. (Not handled when doing Math.floor and just casting
* anyways, so question is if we want to handle it or not)
*
* @param val
* Value to floor
* @return Floored int value
*/
public static int floor(final float val) {
final int intVal = (int) val;
return val < 0 ? val == intVal ? intVal : intVal - 1 : intVal;
}
/**
* Faster floor function. Does not handle NaN and Infinity. (Not handled when doing Math.floor and just casting
* anyways, so question is if we want to handle it or not)
*
* @param val
* Value to floor
* @return Floored long value
*/
public static long floor(final double val) {
final long longVal = (long) val;
return val < 0 ? val == longVal ? longVal : longVal - 1 : longVal;
}
public static int round(final float val) {
return floor(val + 0.5f);
}
public static long round(final double val) {
return floor(val + 0.5d);
}
public static double clamp(final double val, final double min, final double max) {
return val < min ? min : val > max ? max : val;
}
public static float clamp(final float val, final float min, final float max) {
return val < min ? min : val > max ? max : val;
}
public static int clamp(final int val, final int min, final int max) {
return val < min ? min : val > max ? max : val;
}
public static int moduloPositive(final int value, final int size) {
int wrappedValue = value % size;
wrappedValue += wrappedValue < 0 ? size : 0;
return wrappedValue;
}
public static float moduloPositive(final float value, final float size) {
float wrappedValue = value % size;
wrappedValue += wrappedValue < 0 ? size : 0;
return wrappedValue;
}
public static double moduloPositive(final double value, final double size) {
double wrappedValue = value % size;
wrappedValue += wrappedValue < 0 ? size : 0;
return wrappedValue;
}
/**
* Simple 2^x
*
* @param x
* power
* @return 2^x
*/
public static int pow2(final int x) {
if (x <= 0) {
return 1;
}
return 2 << x - 1;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy