Skip to content

Instantly share code, notes, and snippets.

@Sythelux
Last active August 29, 2015 14:05
Show Gist options
  • Save Sythelux/6b7299e07b7f2b6e112c to your computer and use it in GitHub Desktop.
Save Sythelux/6b7299e07b7f2b6e112c to your computer and use it in GitHub Desktop.
Gears
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import java.util.Random;
/**
* <code>FastMath</code> provides 'fast' math approximations and float equivalents of Math
* functions. These are all used as static values and functions.
*
* @author Various
* @version $Id: FastMath.java,v 1.45 2007/08/26 08:44:20 irrisor Exp $
*/
final public class FastMath {
private FastMath() {
}
/** A "close to zero" double epsilon value for use*/
public static final double DBL_EPSILON = 2.220446049250313E-16d;
/** A "close to zero" float epsilon value for use*/
public static final float FLT_EPSILON = 1.1920928955078125E-7f;
/** A "close to zero" float epsilon value for use*/
public static final float ZERO_TOLERANCE = 0.0001f;
public static final float ONE_THIRD = 1f / 3f;
/** The value PI as a float. (180 degrees) */
public static final float PI = (float) Math.PI;
/** The value 2PI as a float. (360 degrees) */
public static final float TWO_PI = 2.0f * PI;
/** The value PI/2 as a float. (90 degrees) */
public static final float HALF_PI = 0.5f * PI;
/** The value PI/4 as a float. (45 degrees) */
public static final float QUARTER_PI = 0.25f * PI;
/** The value 1/PI as a float. */
public static final float INV_PI = 1.0f / PI;
/** The value 1/(2PI) as a float. */
public static final float INV_TWO_PI = 1.0f / TWO_PI;
/** A value to multiply a degree value by, to convert it to radians. */
public static final float DEG_TO_RAD = PI / 180.0f;
/** A value to multiply a radian value by, to convert it to degrees. */
public static final float RAD_TO_DEG = 180.0f / PI;
/** A precreated random object for random numbers. */
public static final Random rand = new Random(System.currentTimeMillis());
/**
* 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(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
* Beginning 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;
}
if (scale <= 0f) {
return startValue;
}
if (scale >= 1f) {
return endValue;
}
return ((1f - scale) * startValue) + (scale * endValue);
}
/**
* 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
* Beginning value. 0% of f
* @param endValue
* ending value. 100% of f
* @param store a vector3f to store the result
* @return The interpolated value between startValue and endValue.
*/
public static Vector3f interpolateLinear(float scale, Vector3f startValue, Vector3f endValue, Vector3f store) {
if (store == null) {
store = new Vector3f();
}
store.x = interpolateLinear(scale, startValue.x, endValue.x);
store.y = interpolateLinear(scale, startValue.y, endValue.y);
store.z = interpolateLinear(scale, startValue.z, endValue.z);
return store;
}
/**
* 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
* Beginning value. 0% of f
* @param endValue
* ending value. 100% of f
* @return The interpolated value between startValue and endValue.
*/
public static Vector3f interpolateLinear(float scale, Vector3f startValue, Vector3f endValue) {
return interpolateLinear(scale, startValue, endValue, null);
}
/**
* 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 float extrapolateLinear(float scale, float startValue, float endValue) {
// if (scale <= 0f) {
// return startValue;
// }
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)
* @param store an initialized vector to store the return value
* @return an extrapolation for the given parameters
*/
public static Vector3f extrapolateLinear(float scale, Vector3f startValue, Vector3f endValue, Vector3f store) {
if (store == null) {
store = new Vector3f();
}
// if (scale <= 1f) {
// return interpolateLinear(scale, startValue, endValue, store);
// }
store.x = extrapolateLinear(scale, startValue.x, endValue.x);
store.y = extrapolateLinear(scale, startValue.y, endValue.y);
store.z = extrapolateLinear(scale, startValue.z, endValue.z);
return store;
}
/**
* 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 Vector3f extrapolateLinear(float scale, Vector3f startValue, Vector3f endValue) {
return extrapolateLinear(scale, startValue, endValue, null);
}
/**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 float interpolateCatmullRom(float u, float T, float p0, float p1, float p2, float p3) {
float 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 (float) (((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
* @param store a Vector3f to store the result
* @return Catmull–Rom interpolation
*/
public static Vector3f interpolateCatmullRom(float u, float T, Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3, Vector3f store) {
if (store == null) {
store = new Vector3f();
}
store.x = interpolateCatmullRom(u, T, p0.x, p1.x, p2.x, p3.x);
store.y = interpolateCatmullRom(u, T, p0.y, p1.y, p2.y, p3.y);
store.z = interpolateCatmullRom(u, T, p0.z, p1.z, p2.z, p3.z);
return store;
}
/**
* Interpolate a spline between at least 4 control points using 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 Vector3f interpolateCatmullRom(float u, float T, Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3) {
return interpolateCatmullRom(u, T, p0, p1, p2, p3, null);
}
/**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 float interpolateBezier(float u, float p0, float p1, float p2, float p3) {
float oneMinusU = 1.0f - u;
float oneMinusU2 = oneMinusU * oneMinusU;
float 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
* @param store a Vector3f to store the result
* @return Bezier interpolation
*/
public static Vector3f interpolateBezier(float u, Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3, Vector3f store) {
if (store == null) {
store = new Vector3f();
}
store.x = interpolateBezier(u, p0.x, p1.x, p2.x, p3.x);
store.y = interpolateBezier(u, p0.y, p1.y, p2.y, p3.y);
store.z = interpolateBezier(u, p0.z, p1.z, p2.z, p3.z);
return store;
}
/**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 Vector3f interpolateBezier(float u, Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3) {
return interpolateBezier(u, p0, p1, p2, p3, null);
}
/**
* Compute the length of a Catmull–Rom spline between control points 1 and 2
* @param p0 control point 0
* @param p1 control point 1
* @param p2 control point 2
* @param p3 control point 3
* @param startRange the starting range on the segment (use 0)
* @param endRange the end range on the segment (use 1)
* @param curveTension the curve tension
* @return the length of the segment
*/
public static float getCatmullRomP1toP2Length(Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3, float startRange, float endRange, float curveTension) {
float epsilon = 0.001f;
float middleValue = (startRange + endRange) * 0.5f;
Vector3f start = p1.clone();
if (startRange != 0) {
FastMath.interpolateCatmullRom(startRange, curveTension, p0, p1, p2, p3, start);
}
Vector3f end = p2.clone();
if (endRange != 1) {
FastMath.interpolateCatmullRom(endRange, curveTension, p0, p1, p2, p3, end);
}
Vector3f middle = FastMath.interpolateCatmullRom(middleValue, curveTension, p0, p1, p2, p3);
float l = end.subtract(start).length();
float l1 = middle.subtract(start).length();
float l2 = end.subtract(middle).length();
float len = l1 + l2;
if (l + epsilon < len) {
l1 = getCatmullRomP1toP2Length(p0, p1, p2, p3, startRange, middleValue, curveTension);
l2 = getCatmullRomP1toP2Length(p0, p1, p2, p3, middleValue, endRange, curveTension);
}
l = l1 + l2;
return l;
}
/**
* Compute the length on a Bezier spline between control points 1 and 2.
* @param p0 control point 0
* @param p1 control point 1
* @param p2 control point 2
* @param p3 control point 3
* @return the length of the segment
*/
public static float getBezierP1toP2Length(Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3) {
float delta = 0.02f, t = 0.0f, result = 0.0f;
Vector3f v1 = p0.clone(), v2 = new Vector3f();
while (t <= 1.0f) {
FastMath.interpolateBezier(t, p0, p1, p2, p3, v2);
result += v1.subtractLocal(v2).length();
v1.set(v2);
t += delta;
}
return result;
}
/**
* 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 float acos(float fValue) {
if (-1.0f < fValue) {
if (fValue < 1.0f) {
return (float) Math.acos(fValue);
}
return 0.0f;
}
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 float asin(float fValue) {
if (-1.0f < fValue) {
if (fValue < 1.0f) {
return (float) Math.asin(fValue);
}
return HALF_PI;
}
return -HALF_PI;
}
/**
* Returns the arc tangent of an angle given in radians.<br>
* @param fValue The angle, in radians.
* @return fValue's atan
* @see java.lang.Math#atan(double)
*/
public static float atan(float fValue) {
return (float) Math.atan(fValue);
}
/**
* A direct call to Math.atan2.
* @param fY
* @param fX
* @return Math.atan2(fY,fX)
* @see java.lang.Math#atan2(double, double)
*/
public static float atan2(float fY, float fX) {
return (float) Math.atan2(fY, fX);
}
/**
* Rounds a fValue up. A call to Math.ceil
* @param fValue The value.
* @return The fValue rounded up
* @see java.lang.Math#ceil(double)
*/
public static float ceil(float fValue) {
return (float) Math.ceil(fValue);
}
/**
* Returns cosine of an angle. Direct call to java.lang.Math
* @see Math#cos(double)
* @param v The angle to cosine.
* @return the cosine of the angle.
*/
public static float cos(float v) {
return (float) Math.cos(v);
}
/**
* Returns the sine of an angle. Direct call to java.lang.Math
* @see Math#sin(double)
* @param v The angle to sine.
* @return the sine of the angle.
*/
public static float sin(float v) {
return (float) Math.sin(v);
}
/**
* Returns E^fValue
* @param fValue Value to raise to a power.
* @return The value E^fValue
* @see java.lang.Math#exp(double)
*/
public static float exp(float fValue) {
return (float) Math.exp(fValue);
}
/**
* Returns Absolute value of a float.
* @param fValue The value to abs.
* @return The abs of the value.
* @see java.lang.Math#abs(float)
*/
public static float abs(float fValue) {
if (fValue < 0) {
return -fValue;
}
return fValue;
}
/**
* Returns a number rounded down.
* @param fValue The value to round
* @return The given number rounded down
* @see java.lang.Math#floor(double)
*/
public static float floor(float fValue) {
return (float) Math.floor(fValue);
}
/**
* 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));
}
public static float fastInvSqrt(float x) {
float xhalf = 0.5f * x;
int i = Float.floatToIntBits(x); // get bits for floating value
i = 0x5f375a86 - (i >> 1); // gives initial guess y0
x = Float.intBitsToFloat(i); // convert bits back to float
x = x * (1.5f - xhalf * x * x); // Newton step, repeating increases accuracy
return x;
}
/**
* Returns the log base E of a value.
* @param fValue The value to log.
* @return The log of fValue base E
* @see java.lang.Math#log(double)
*/
public static float log(float fValue) {
return (float) Math.log(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));
}
/**
* Returns a number raised to an exponent power. fBase^fExponent
* @param fBase The base value (IE 2)
* @param fExponent The exponent value (IE 3)
* @return base raised to exponent (IE 8)
* @see java.lang.Math#pow(double, double)
*/
public static float pow(float fBase, float fExponent) {
return (float) Math.pow(fBase, fExponent);
}
/**
* Returns the value squared. fValue ^ 2
* @param fValue The value to square.
* @return The square of the given value.
*/
public static float sqr(float fValue) {
return fValue * fValue;
}
/**
* 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(fValue);
}
/**
* 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;
}
if (iValue < 0) {
return -1;
}
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);
}
/**
* Given 3 points in a 2d plane, this function computes if the points going from A-B-C
* are moving counter clock wise.
* @param p0 Point 0.
* @param p1 Point 1.
* @param p2 Point 2.
* @return 1 If they are CCW, -1 if they are not CCW, 0 if p2 is between p0 and p1.
*/
public static int counterClockwise(Vector2f p0, Vector2f p1, Vector2f p2) {
float dx1, dx2, dy1, dy2;
dx1 = p1.x - p0.x;
dy1 = p1.y - p0.y;
dx2 = p2.x - p0.x;
dy2 = p2.y - p0.y;
if (dx1 * dy2 > dy1 * dx2) {
return 1;
}
if (dx1 * dy2 < dy1 * dx2) {
return -1;
}
if ((dx1 * dx2 < 0) || (dy1 * dy2 < 0)) {
return -1;
}
if ((dx1 * dx1 + dy1 * dy1) < (dx2 * dx2 + dy2 * dy2)) {
return 1;
}
return 0;
}
/**
* Test if a point is inside a triangle. 1 if the point is on the ccw side,
* -1 if the point is on the cw side, and 0 if it is on neither.
* @param t0 First point of the triangle.
* @param t1 Second point of the triangle.
* @param t2 Third point of the triangle.
* @param p The point to test.
* @return Value 1 or -1 if inside triangle, 0 otherwise.
*/
public static int pointInsideTriangle(Vector2f t0, Vector2f t1, Vector2f t2, Vector2f p) {
int val1 = counterClockwise(t0, t1, p);
if (val1 == 0) {
return 1;
}
int val2 = counterClockwise(t1, t2, p);
if (val2 == 0) {
return 1;
}
if (val2 != val1) {
return 0;
}
int val3 = counterClockwise(t2, t0, p);
if (val3 == 0) {
return 1;
}
if (val3 != val1) {
return 0;
}
return val3;
}
/**
* A method that computes normal for a triangle defined by three vertices.
* @param v1 first vertex
* @param v2 second vertex
* @param v3 third vertex
* @return a normal for the face
*/
public static Vector3f computeNormal(Vector3f v1, Vector3f v2, Vector3f v3) {
Vector3f a1 = v1.subtract(v2);
Vector3f a2 = v3.subtract(v2);
return a2.crossLocal(a1).normalizeLocal();
}
/**
* Returns the determinant of a 4x4 matrix.
*/
public static float determinant(double m00, double m01, double m02,
double m03, double m10, double m11, double m12, double m13,
double m20, double m21, double m22, double m23, double m30,
double m31, double m32, double m33) {
double det01 = m20 * m31 - m21 * m30;
double det02 = m20 * m32 - m22 * m30;
double det03 = m20 * m33 - m23 * m30;
double det12 = m21 * m32 - m22 * m31;
double det13 = m21 * m33 - m23 * m31;
double det23 = m22 * m33 - m23 * m32;
return (float) (m00 * (m11 * det23 - m12 * det13 + m13 * det12) - m01
* (m10 * det23 - m12 * det03 + m13 * det02) + m02
* (m10 * det13 - m11 * det03 + m13 * det01) - m03
* (m10 * det12 - m11 * det02 + m12 * det01));
}
/**
* Returns a random float between 0 and 1.
*
* @return A random float between <tt>0.0f</tt> (inclusive) to
* <tt>1.0f</tt> (exclusive).
*/
public static float nextRandomFloat() {
return rand.nextFloat();
}
/**
* Returns a random integer between min and max.
*
* @return A random int between <tt>min</tt> (inclusive) to
* <tt>max</tt> (inclusive).
*/
public static int nextRandomInt(int min, int max) {
return (int) (nextRandomFloat() * (max - min + 1)) + min;
}
public static int nextRandomInt() {
return rand.nextInt();
}
/**
* Converts a point from Spherical coordinates to Cartesian (using positive
* Y as up) and stores the results in the store var.
*/
public static Vector3f sphericalToCartesian(Vector3f sphereCoords,
Vector3f store) {
if (store == null) {
store = new Vector3f();
}
store.y = sphereCoords.x * FastMath.sin(sphereCoords.z);
float a = sphereCoords.x * FastMath.cos(sphereCoords.z);
store.x = a * FastMath.cos(sphereCoords.y);
store.z = a * FastMath.sin(sphereCoords.y);
return store;
}
/**
* Converts a point from Cartesian coordinates (using positive Y as up) to
* Spherical and stores the results in the store var. (Radius, Azimuth,
* Polar)
*/
public static Vector3f cartesianToSpherical(Vector3f cartCoords,
Vector3f store) {
if (store == null) {
store = new Vector3f();
}
float x = cartCoords.x;
if (x == 0) {
x = FastMath.FLT_EPSILON;
}
store.x = FastMath.sqrt((x * x)
+ (cartCoords.y * cartCoords.y)
+ (cartCoords.z * cartCoords.z));
store.y = FastMath.atan(cartCoords.z / x);
if (x < 0) {
store.y += FastMath.PI;
}
store.z = FastMath.asin(cartCoords.y / store.x);
return store;
}
/**
* Converts a point from Spherical coordinates to Cartesian (using positive
* Z as up) and stores the results in the store var.
*/
public static Vector3f sphericalToCartesianZ(Vector3f sphereCoords,
Vector3f store) {
if (store == null) {
store = new Vector3f();
}
store.z = sphereCoords.x * FastMath.sin(sphereCoords.z);
float a = sphereCoords.x * FastMath.cos(sphereCoords.z);
store.x = a * FastMath.cos(sphereCoords.y);
store.y = a * FastMath.sin(sphereCoords.y);
return store;
}
/**
* Converts a point from Cartesian coordinates (using positive Z as up) to
* Spherical and stores the results in the store var. (Radius, Azimuth,
* Polar)
*/
public static Vector3f cartesianZToSpherical(Vector3f cartCoords,
Vector3f store) {
if (store == null) {
store = new Vector3f();
}
float x = cartCoords.x;
if (x == 0) {
x = FastMath.FLT_EPSILON;
}
store.x = FastMath.sqrt((x * x)
+ (cartCoords.y * cartCoords.y)
+ (cartCoords.z * cartCoords.z));
store.z = FastMath.atan(cartCoords.z / x);
if (x < 0) {
store.z += FastMath.PI;
}
store.y = FastMath.asin(cartCoords.y / store.x);
return store;
}
/**
* Takes an value and expresses it in terms of min to max.
*
* @param val -
* the angle to normalize (in radians)
* @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
* @param min
* @param max
* @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
* @return input clamped between 0 and 1.
*/
public static float saturate(float input) {
return clamp(input, 0f, 1f);
}
/**
* Converts a single precision (32 bit) floating point value
* into half precision (16 bit).
*
* <p>Source: <a href="http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf">
* http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf</a><br><strong>broken link</strong>
*
* @param half The half floating point value as a short.
* @return floating point value of the half.
*/
public static float convertHalfToFloat(short half) {
switch ((int) half) {
case 0x0000:
return 0f;
case 0x8000:
return -0f;
case 0x7c00:
return Float.POSITIVE_INFINITY;
case 0xfc00:
return Float.NEGATIVE_INFINITY;
// TODO: Support for NaN?
default:
return Float.intBitsToFloat(((half & 0x8000) << 16)
| (((half & 0x7c00) + 0x1C000) << 13)
| ((half & 0x03FF) << 13));
}
}
public static short convertFloatToHalf(float flt) {
if (Float.isNaN(flt)) {
throw new UnsupportedOperationException("NaN to half conversion not supported!");
} else if (flt == Float.POSITIVE_INFINITY) {
return (short) 0x7c00;
} else if (flt == Float.NEGATIVE_INFINITY) {
return (short) 0xfc00;
} else if (flt == 0f) {
return (short) 0x0000;
} else if (flt == -0f) {
return (short) 0x8000;
} else if (flt > 65504f) {
// max value supported by half float
return 0x7bff;
} else if (flt < -65504f) {
return (short) (0x7bff | 0x8000);
} else if (flt > 0f && flt < 5.96046E-8f) {
return 0x0001;
} else if (flt < 0f && flt > -5.96046E-8f) {
return (short) 0x8001;
}
int f = Float.floatToIntBits(flt);
return (short) (((f >> 16) & 0x8000)
| ((((f & 0x7f800000) - 0x38000000) >> 13) & 0x7c00)
| ((f >> 13) & 0x03ff));
}
}
/**
* Copyright (C) 2007 Aaron Spike (aaron @ ekips.org)
* Copyright (C) 2007 Tavmjong Bah (tavmjong @ free.fr)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* @author Sythelux Rikd (ported from Python) origin see above
*/
import java.util.Arrays;
import java.util.Collection;
import java.util.Formatter;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Stack;
import com.sun.xml.internal.ws.policy.privateutil.PolicyUtils.Collections;
public class Gears {
public static float involute_intersect_angle(float Rb, float R) {
return (FastMath.sqrt(FastMath.pow(R , 2) - FastMath.pow(Rb , 2)) / (Rb)) - (FastMath.acos(Rb / R));
}
public static Vector2f Vector2f_on_circle(float radius, float angle) {
float x = radius * FastMath.cos(angle);
float y = radius * FastMath.sin(angle);
return new Vector2f(x, y);
}
public static String Vector2fs_to_svgd(Vector2f[] p) {
Formatter format = new Formatter(Locale.ENGLISH);
String svgd;
for (int i = 0; i < p.length; i++) {
Vector2f f = p[i];
if (i == 0) {
format.format("M%.3f,%.3f", f.x, f.y).toString();
} else {
format.format("L%.3f,%.3f", f.x, f.y).toString();
}
}
svgd = format.toString() + 'z';
format.close();
return svgd;
}
private int teeth = 24;
private float pitch = 20;
private float angle = 20;
private String path;
public Gears(int teeth, float pitch, float angle) {
this.teeth = teeth;
this.pitch = pitch;
this.angle = angle;
init();
}
public Gears() {
init();
}
public void init() {
float two_pi = 2f * FastMath.PI;
float pitch_diameter = teeth * pitch / FastMath.PI;
float pitch_radius = pitch_diameter / 2f;
// Base Circle
float base_diameter = pitch_diameter * FastMath.cos(FastMath.DEG_TO_RAD * angle);
float base_radius = base_diameter / 2f;
// Diametrial pitch: Number of teeth per unit length.
float pitch_diametrial = teeth / pitch_diameter;
// Addendum: Radial distance from pitch circle to outside circle.
float addendum = 1f / pitch_diametrial;
// Outer Circle
float outer_radius = pitch_radius + addendum;
float outer_diameter = outer_radius * 2f;
// Tooth thickness: Tooth width along pitch circle.
float tooth = (FastMath.PI * pitch_diameter) / (2f * teeth);
// Undercut?
float undercut = (2f / FastMath.pow(FastMath.sin(FastMath.DEG_TO_RAD * angle), 2f));
boolean needs_undercut = teeth < undercut;
// Clearance: Radial distance between top of tooth on one gear to bottom
// of gap on another.
float clearance = 0f;
// Dedendum: Radial distance from pitch circle to root diameter.
float dedendum = addendum + clearance;
// Root diameter: Diameter of bottom of tooth spaces.
float root_radius = pitch_radius - dedendum;
float root_diameter = root_radius * 2f;
float half_thick_angle = two_pi / (4f * teeth);
float pitch_to_base_angle = involute_intersect_angle(base_radius, pitch_radius);
float pitch_to_outer_angle = involute_intersect_angle(base_radius, outer_radius) - pitch_to_base_angle;
float[] centers = new float[teeth];
for (int i = 0; i < centers.length; i++) {
centers[i] = i * two_pi / teeth;
}
List<Vector2f> points = new LinkedList<>();
for (float c : centers) {
// Angles
float pitch1 = c - half_thick_angle;
float base1 = pitch1 - pitch_to_base_angle;
float outer1 = pitch1 + pitch_to_outer_angle;
float pitch2 = c + half_thick_angle;
float base2 = pitch2 + pitch_to_base_angle;
float outer2 = pitch2 - pitch_to_outer_angle;
// Vector2fs
Vector2f b1 = Vector2f_on_circle(base_radius, base1);
Vector2f p1 = Vector2f_on_circle(pitch_radius, pitch1);
Vector2f o1 = Vector2f_on_circle(outer_radius, outer1);
Vector2f b2 = Vector2f_on_circle(base_radius, base2);
Vector2f p2 = Vector2f_on_circle(pitch_radius, pitch2);
Vector2f o2 = Vector2f_on_circle(outer_radius, outer2);
Vector2f[] p_tmp = null;
if (root_radius > base_radius) {
float pitch_to_root_angle = pitch_to_base_angle - involute_intersect_angle(base_radius, root_radius);
float root1 = pitch1 - pitch_to_root_angle;
float root2 = pitch2 + pitch_to_root_angle;
Vector2f r1 = Vector2f_on_circle(root_radius, root1);
Vector2f r2 = Vector2f_on_circle(root_radius, root2);
p_tmp = new Vector2f[] { r1, p1, o1, o2, p2, r2 };
} else {
Vector2f r1 = Vector2f_on_circle(root_radius, base1);
Vector2f r2 = Vector2f_on_circle(root_radius, base2);
p_tmp = new Vector2f[] { r1, b1, p1, o1, o2, p2, b2, r2 };
}
points.addAll(Arrays.asList(p_tmp));
}
path = Vector2fs_to_svgd(points.toArray(new Vector2f[points.size()]));
// String t = "translate(" + view_center[0] + ',' + view_center[1] + ')'
// g_attribs = {inkex.addNS('label','inkscape'):'Gear' + str( teeth ),
// 'transform':t }
// g = inkex.etree.SubElement(self.current_layer, 'g', g_attribs)
//
// style = { 'stroke': '#000000', 'fill': 'none' }
// gear_attribs = {'style':simplestyle.formatStyle(style), 'd':path}
// gear = inkex.etree.SubElement(g, inkex.addNS('path','svg'),
// gear_attribs)
}
@Override
public String toString() {
return path;
}
public static void main(String[] args) {
System.out.println(new Gears().toString());
}
}
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.logging.Logger;
/**
* <code>Vector2f</code> defines a Vector for a two float value vector.
*
* @author Mark Powell
* @author Joshua Slack
*/
public final class Vector2f implements Cloneable, java.io.Serializable {
static final long serialVersionUID = 1;
private static final Logger logger = Logger.getLogger(Vector2f.class.getName());
public static final Vector2f ZERO = new Vector2f(0f, 0f);
public static final Vector2f UNIT_XY = new Vector2f(1f, 1f);
/**
* the x value of the vector.
*/
public float x;
/**
* the y value of the vector.
*/
public float y;
/**
* Creates a Vector2f with the given initial x and y values.
*
* @param x
* The x value of this Vector2f.
* @param y
* The y value of this Vector2f.
*/
public Vector2f(float x, float y) {
this.x = x;
this.y = y;
}
/**
* Creates a Vector2f with x and y set to 0. Equivalent to Vector2f(0,0).
*/
public Vector2f() {
x = y = 0;
}
/**
* Creates a new Vector2f that contains the passed vector's information
*
* @param vector2f
* The vector to copy
*/
public Vector2f(Vector2f vector2f) {
this.x = vector2f.x;
this.y = vector2f.y;
}
/**
* set the x and y values of the vector
*
* @param x
* the x value of the vector.
* @param y
* the y value of the vector.
* @return this vector
*/
public Vector2f set(float x, float y) {
this.x = x;
this.y = y;
return this;
}
/**
* set the x and y values of the vector from another vector
*
* @param vec
* the vector to copy from
* @return this vector
*/
public Vector2f set(Vector2f vec) {
this.x = vec.x;
this.y = vec.y;
return this;
}
/**
* <code>add</code> adds a provided vector to this vector creating a
* resultant vector which is returned. If the provided vector is null, null
* is returned.
*
* @param vec
* the vector to add to this.
* @return the resultant vector.
*/
public Vector2f add(Vector2f vec) {
if (null == vec) {
logger.warning("Provided vector is null, null returned.");
return null;
}
return new Vector2f(x + vec.x, y + vec.y);
}
/**
* <code>addLocal</code> adds a provided vector to this vector internally,
* and returns a handle to this vector for easy chaining of calls. If the
* provided vector is null, null is returned.
*
* @param vec
* the vector to add to this vector.
* @return this
*/
public Vector2f addLocal(Vector2f vec) {
if (null == vec) {
logger.warning("Provided vector is null, null returned.");
return null;
}
x += vec.x;
y += vec.y;
return this;
}
/**
* <code>addLocal</code> adds the provided values to this vector
* internally, and returns a handle to this vector for easy chaining of
* calls.
*
* @param addX
* value to add to x
* @param addY
* value to add to y
* @return this
*/
public Vector2f addLocal(float addX, float addY) {
x += addX;
y += addY;
return this;
}
/**
* <code>add</code> adds this vector by <code>vec</code> and stores the
* result in <code>result</code>.
*
* @param vec
* The vector to add.
* @param result
* The vector to store the result in.
* @return The result vector, after adding.
*/
public Vector2f add(Vector2f vec, Vector2f result) {
if (null == vec) {
logger.warning("Provided vector is null, null returned.");
return null;
}
if (result == null)
result = new Vector2f();
result.x = x + vec.x;
result.y = y + vec.y;
return result;
}
/**
* <code>dot</code> calculates the dot product of this vector with a
* provided vector. If the provided vector is null, 0 is returned.
*
* @param vec
* the vector to dot with this vector.
* @return the resultant dot product of this vector and a given vector.
*/
public float dot(Vector2f vec) {
if (null == vec) {
logger.warning("Provided vector is null, 0 returned.");
return 0;
}
return x * vec.x + y * vec.y;
}
public float determinant(Vector2f v) {
return (x * v.y) - (y * v.x);
}
/**
* Sets this vector to the interpolation by changeAmnt from this to the
* finalVec this=(1-changeAmnt)*this + changeAmnt * finalVec
*
* @param finalVec
* The final vector to interpolate towards
* @param changeAmnt
* An amount between 0.0 - 1.0 representing a percentage change
* from this towards finalVec
*/
public Vector2f interpolateLocal(Vector2f finalVec, float changeAmnt) {
this.x = (1 - changeAmnt) * this.x + changeAmnt * finalVec.x;
this.y = (1 - changeAmnt) * this.y + changeAmnt * finalVec.y;
return this;
}
/**
* Sets this vector to the interpolation by changeAmnt from beginVec to
* finalVec this=(1-changeAmnt)*beginVec + changeAmnt * finalVec
*
* @param beginVec
* The begining vector (delta=0)
* @param finalVec
* The final vector to interpolate towards (delta=1)
* @param changeAmnt
* An amount between 0.0 - 1.0 representing a precentage change
* from beginVec towards finalVec
*/
public Vector2f interpolateLocal(Vector2f beginVec, Vector2f finalVec,
float changeAmnt) {
this.x = (1 - changeAmnt) * beginVec.x + changeAmnt * finalVec.x;
this.y = (1 - changeAmnt) * beginVec.y + changeAmnt * finalVec.y;
return this;
}
/**
* Check a vector... if it is null or its floats are NaN or infinite, return
* false. Else return true.
*
* @param vector
* the vector to check
* @return true or false as stated above.
*/
public static boolean isValidVector(Vector2f vector) {
if (vector == null) return false;
if (Float.isNaN(vector.x) ||
Float.isNaN(vector.y)) return false;
if (Float.isInfinite(vector.x) ||
Float.isInfinite(vector.y)) return false;
return true;
}
/**
* <code>length</code> calculates the magnitude of this vector.
*
* @return the length or magnitude of the vector.
*/
public float length() {
return FastMath.sqrt(lengthSquared());
}
/**
* <code>lengthSquared</code> calculates the squared value of the
* magnitude of the vector.
*
* @return the magnitude squared of the vector.
*/
public float lengthSquared() {
return x * x + y * y;
}
/**
* <code>distanceSquared</code> calculates the distance squared between
* this vector and vector v.
*
* @param v the second vector to determine the distance squared.
* @return the distance squared between the two vectors.
*/
public float distanceSquared(Vector2f v) {
double dx = x - v.x;
double dy = y - v.y;
return (float) (dx * dx + dy * dy);
}
/**
* <code>distanceSquared</code> calculates the distance squared between
* this vector and vector v.
*
* @param otherX The X coordinate of the v vector
* @param otherY The Y coordinate of the v vector
* @return the distance squared between the two vectors.
*/
public float distanceSquared(float otherX, float otherY) {
double dx = x - otherX;
double dy = y - otherY;
return (float) (dx * dx + dy * dy);
}
/**
* <code>distance</code> calculates the distance between this vector and
* vector v.
*
* @param v the second vector to determine the distance.
* @return the distance between the two vectors.
*/
public float distance(Vector2f v) {
return FastMath.sqrt(distanceSquared(v));
}
/**
* <code>mult</code> multiplies this vector by a scalar. The resultant
* vector is returned.
*
* @param scalar
* the value to multiply this vector by.
* @return the new vector.
*/
public Vector2f mult(float scalar) {
return new Vector2f(x * scalar, y * scalar);
}
/**
* <code>multLocal</code> multiplies this vector by a scalar internally,
* and returns a handle to this vector for easy chaining of calls.
*
* @param scalar
* the value to multiply this vector by.
* @return this
*/
public Vector2f multLocal(float scalar) {
x *= scalar;
y *= scalar;
return this;
}
/**
* <code>multLocal</code> multiplies a provided vector to this vector
* internally, and returns a handle to this vector for easy chaining of
* calls. If the provided vector is null, null is returned.
*
* @param vec
* the vector to mult to this vector.
* @return this
*/
public Vector2f multLocal(Vector2f vec) {
if (null == vec) {
logger.warning("Provided vector is null, null returned.");
return null;
}
x *= vec.x;
y *= vec.y;
return this;
}
/**
* Multiplies this Vector2f's x and y by the scalar and stores the result in
* product. The result is returned for chaining. Similar to
* product=this*scalar;
*
* @param scalar
* The scalar to multiply by.
* @param product
* The vector2f to store the result in.
* @return product, after multiplication.
*/
public Vector2f mult(float scalar, Vector2f product) {
if (null == product) {
product = new Vector2f();
}
product.x = x * scalar;
product.y = y * scalar;
return product;
}
/**
* <code>divide</code> divides the values of this vector by a scalar and
* returns the result. The values of this vector remain untouched.
*
* @param scalar
* the value to divide this vectors attributes by.
* @return the result <code>Vector</code>.
*/
public Vector2f divide(float scalar) {
return new Vector2f(x / scalar, y / scalar);
}
/**
* <code>divideLocal</code> divides this vector by a scalar internally,
* and returns a handle to this vector for easy chaining of calls. Dividing
* by zero will result in an exception.
*
* @param scalar
* the value to divides this vector by.
* @return this
*/
public Vector2f divideLocal(float scalar) {
x /= scalar;
y /= scalar;
return this;
}
/**
* <code>negate</code> returns the negative of this vector. All values are
* negated and set to a new vector.
*
* @return the negated vector.
*/
public Vector2f negate() {
return new Vector2f(-x, -y);
}
/**
* <code>negateLocal</code> negates the internal values of this vector.
*
* @return this.
*/
public Vector2f negateLocal() {
x = -x;
y = -y;
return this;
}
/**
* <code>subtract</code> subtracts the values of a given vector from those
* of this vector creating a new vector object. If the provided vector is
* null, an exception is thrown.
*
* @param vec
* the vector to subtract from this vector.
* @return the result vector.
*/
public Vector2f subtract(Vector2f vec) {
return subtract(vec, null);
}
/**
* <code>subtract</code> subtracts the values of a given vector from those
* of this vector storing the result in the given vector object. If the
* provided vector is null, an exception is thrown.
*
* @param vec
* the vector to subtract from this vector.
* @param store
* the vector to store the result in. It is safe for this to be
* the same as vec. If null, a new vector is created.
* @return the result vector.
*/
public Vector2f subtract(Vector2f vec, Vector2f store) {
if (store == null)
store = new Vector2f();
store.x = x - vec.x;
store.y = y - vec.y;
return store;
}
/**
* <code>subtract</code> subtracts the given x,y values from those of this
* vector creating a new vector object.
*
* @param valX
* value to subtract from x
* @param valY
* value to subtract from y
* @return this
*/
public Vector2f subtract(float valX, float valY) {
return new Vector2f(x - valX, y - valY);
}
/**
* <code>subtractLocal</code> subtracts a provided vector to this vector
* internally, and returns a handle to this vector for easy chaining of
* calls. If the provided vector is null, null is returned.
*
* @param vec
* the vector to subtract
* @return this
*/
public Vector2f subtractLocal(Vector2f vec) {
if (null == vec) {
logger.warning("Provided vector is null, null returned.");
return null;
}
x -= vec.x;
y -= vec.y;
return this;
}
/**
* <code>subtractLocal</code> subtracts the provided values from this
* vector internally, and returns a handle to this vector for easy chaining
* of calls.
*
* @param valX
* value to subtract from x
* @param valY
* value to subtract from y
* @return this
*/
public Vector2f subtractLocal(float valX, float valY) {
x -= valX;
y -= valY;
return this;
}
/**
* <code>normalize</code> returns the unit vector of this vector.
*
* @return unit vector of this vector.
*/
public Vector2f normalize() {
float length = length();
if (length != 0) {
return divide(length);
}
return divide(1);
}
/**
* <code>normalizeLocal</code> makes this vector into a unit vector of
* itself.
*
* @return this.
*/
public Vector2f normalizeLocal() {
float length = length();
if (length != 0) {
return divideLocal(length);
}
return divideLocal(1);
}
/**
* <code>smallestAngleBetween</code> returns (in radians) the minimum
* angle between two vectors. It is assumed that both this vector and the
* given vector are unit vectors (iow, normalized).
*
* @param otherVector
* a unit vector to find the angle against
* @return the angle in radians.
*/
public float smallestAngleBetween(Vector2f otherVector) {
float dotProduct = dot(otherVector);
float angle = FastMath.acos(dotProduct);
return angle;
}
/**
* <code>angleBetween</code> returns (in radians) the angle required to
* rotate a ray represented by this vector to lie colinear to a ray
* described by the given vector. It is assumed that both this vector and
* the given vector are unit vectors (iow, normalized).
*
* @param otherVector
* the "destination" unit vector
* @return the angle in radians.
*/
public float angleBetween(Vector2f otherVector) {
float angle = FastMath.atan2(otherVector.y, otherVector.x)
- FastMath.atan2(y, x);
return angle;
}
public float getX() {
return x;
}
public Vector2f setX(float x) {
this.x = x;
return this;
}
public float getY() {
return y;
}
public Vector2f setY(float y) {
this.y = y;
return this;
}
/**
* <code>getAngle</code> returns (in radians) the angle represented by
* this Vector2f as expressed by a conversion from rectangular coordinates (<code>x</code>,&nbsp;<code>y</code>)
* to polar coordinates (r,&nbsp;<i>theta</i>).
*
* @return the angle in radians. [-pi, pi)
*/
public float getAngle() {
return FastMath.atan2(y, x);
}
/**
* <code>zero</code> resets this vector's data to zero internally.
*/
public Vector2f zero() {
x = y = 0;
return this;
}
/**
* <code>hashCode</code> returns a unique code for this vector object
* based on it's values. If two vectors are logically equivalent, they will
* return the same hash code value.
*
* @return the hash code value of this vector.
*/
public int hashCode() {
int hash = 37;
hash += 37 * hash + Float.floatToIntBits(x);
hash += 37 * hash + Float.floatToIntBits(y);
return hash;
}
@Override
public Vector2f clone() {
try {
return (Vector2f) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError(); // can not happen
}
}
/**
* Saves this Vector2f into the given float[] object.
*
* @param floats
* The float[] to take this Vector2f. If null, a new float[2] is
* created.
* @return The array, with X, Y float values in that order
*/
public float[] toArray(float[] floats) {
if (floats == null) {
floats = new float[2];
}
floats[0] = x;
floats[1] = y;
return floats;
}
/**
* are these two vectors the same? they are is they both have the same x and
* y values.
*
* @param o
* the object to compare for equality
* @return true if they are equal
*/
public boolean equals(Object o) {
if (!(o instanceof Vector2f)) {
return false;
}
if (this == o) {
return true;
}
Vector2f comp = (Vector2f) o;
if (Float.compare(x, comp.x) != 0)
return false;
if (Float.compare(y, comp.y) != 0)
return false;
return true;
}
/**
* <code>toString</code> returns the string representation of this vector
* object. The format of the string is such: com.jme.math.Vector2f
* [X=XX.XXXX, Y=YY.YYYY]
*
* @return the string representation of this vector.
*/
public String toString() {
return "(" + x + ", " + y + ")";
}
/**
* Used with serialization. Not to be called manually.
*
* @param in
* ObjectInput
* @throws IOException
* @throws ClassNotFoundException
* @see java.io.Externalizable
*/
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
x = in.readFloat();
y = in.readFloat();
}
/**
* Used with serialization. Not to be called manually.
*
* @param out
* ObjectOutput
* @throws IOException
* @see java.io.Externalizable
*/
public void writeExternal(ObjectOutput out) throws IOException {
out.writeFloat(x);
out.writeFloat(y);
}
public void rotateAroundOrigin(float angle, boolean cw) {
if (cw)
angle = -angle;
float newX = FastMath.cos(angle) * x - FastMath.sin(angle) * y;
float newY = FastMath.sin(angle) * x + FastMath.cos(angle) * y;
x = newX;
y = newY;
}
}
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import java.io.IOException;
import java.util.logging.Logger;
/*
* -- Added *Local methods to cut down on object creation - JS
*/
/**
* <code>Vector3f</code> defines a Vector for a three float value tuple.
* <code>Vector3f</code> can represent any three dimensional value, such as a
* vertex, a normal, etc. Utility methods are also included to aid in
* mathematical calculations.
*
* @author Mark Powell
* @author Joshua Slack
*/
public final class Vector3f implements Cloneable, java.io.Serializable {
static final long serialVersionUID = 1;
private static final Logger logger = Logger.getLogger(Vector3f.class.getName());
public final static Vector3f ZERO = new Vector3f(0, 0, 0);
public final static Vector3f NAN = new Vector3f(Float.NaN, Float.NaN, Float.NaN);
public final static Vector3f UNIT_X = new Vector3f(1, 0, 0);
public final static Vector3f UNIT_Y = new Vector3f(0, 1, 0);
public final static Vector3f UNIT_Z = new Vector3f(0, 0, 1);
public final static Vector3f UNIT_XYZ = new Vector3f(1, 1, 1);
public final static Vector3f POSITIVE_INFINITY = new Vector3f(
Float.POSITIVE_INFINITY,
Float.POSITIVE_INFINITY,
Float.POSITIVE_INFINITY);
public final static Vector3f NEGATIVE_INFINITY = new Vector3f(
Float.NEGATIVE_INFINITY,
Float.NEGATIVE_INFINITY,
Float.NEGATIVE_INFINITY);
/**
* the x value of the vector.
*/
public float x;
/**
* the y value of the vector.
*/
public float y;
/**
* the z value of the vector.
*/
public float z;
/**
* Constructor instantiates a new <code>Vector3f</code> with default
* values of (0,0,0).
*
*/
public Vector3f() {
x = y = z = 0;
}
/**
* Constructor instantiates a new <code>Vector3f</code> with provides
* values.
*
* @param x
* the x value of the vector.
* @param y
* the y value of the vector.
* @param z
* the z value of the vector.
*/
public Vector3f(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
}
/**
* Constructor instantiates a new <code>Vector3f</code> that is a copy
* of the provided vector
* @param copy The Vector3f to copy
*/
public Vector3f(Vector3f copy) {
this.set(copy);
}
/**
* <code>set</code> sets the x,y,z values of the vector based on passed
* parameters.
*
* @param x
* the x value of the vector.
* @param y
* the y value of the vector.
* @param z
* the z value of the vector.
* @return this vector
*/
public Vector3f set(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
return this;
}
/**
* <code>set</code> sets the x,y,z values of the vector by copying the
* supplied vector.
*
* @param vect
* the vector to copy.
* @return this vector
*/
public Vector3f set(Vector3f vect) {
this.x = vect.x;
this.y = vect.y;
this.z = vect.z;
return this;
}
/**
*
* <code>add</code> adds a provided vector to this vector creating a
* resultant vector which is returned. If the provided vector is null, null
* is returned.
*
* @param vec
* the vector to add to this.
* @return the resultant vector.
*/
public Vector3f add(Vector3f vec) {
if (null == vec) {
logger.warning("Provided vector is null, null returned.");
return null;
}
return new Vector3f(x + vec.x, y + vec.y, z + vec.z);
}
/**
*
* <code>add</code> adds the values of a provided vector storing the
* values in the supplied vector.
*
* @param vec
* the vector to add to this
* @param result
* the vector to store the result in
* @return result returns the supplied result vector.
*/
public Vector3f add(Vector3f vec, Vector3f result) {
result.x = x + vec.x;
result.y = y + vec.y;
result.z = z + vec.z;
return result;
}
/**
* <code>addLocal</code> adds a provided vector to this vector internally,
* and returns a handle to this vector for easy chaining of calls. If the
* provided vector is null, null is returned.
*
* @param vec
* the vector to add to this vector.
* @return this
*/
public Vector3f addLocal(Vector3f vec) {
if (null == vec) {
logger.warning("Provided vector is null, null returned.");
return null;
}
x += vec.x;
y += vec.y;
z += vec.z;
return this;
}
/**
*
* <code>add</code> adds the provided values to this vector, creating a
* new vector that is then returned.
*
* @param addX
* the x value to add.
* @param addY
* the y value to add.
* @param addZ
* the z value to add.
* @return the result vector.
*/
public Vector3f add(float addX, float addY, float addZ) {
return new Vector3f(x + addX, y + addY, z + addZ);
}
/**
* <code>addLocal</code> adds the provided values to this vector
* internally, and returns a handle to this vector for easy chaining of
* calls.
*
* @param addX
* value to add to x
* @param addY
* value to add to y
* @param addZ
* value to add to z
* @return this
*/
public Vector3f addLocal(float addX, float addY, float addZ) {
x += addX;
y += addY;
z += addZ;
return this;
}
/**
*
* <code>scaleAdd</code> multiplies this vector by a scalar then adds the
* given Vector3f.
*
* @param scalar
* the value to multiply this vector by.
* @param add
* the value to add
*/
public Vector3f scaleAdd(float scalar, Vector3f add) {
x = x * scalar + add.x;
y = y * scalar + add.y;
z = z * scalar + add.z;
return this;
}
/**
*
* <code>scaleAdd</code> multiplies the given vector by a scalar then adds
* the given vector.
*
* @param scalar
* the value to multiply this vector by.
* @param mult
* the value to multiply the scalar by
* @param add
* the value to add
*/
public Vector3f scaleAdd(float scalar, Vector3f mult, Vector3f add) {
this.x = mult.x * scalar + add.x;
this.y = mult.y * scalar + add.y;
this.z = mult.z * scalar + add.z;
return this;
}
/**
*
* <code>dot</code> calculates the dot product of this vector with a
* provided vector. If the provided vector is null, 0 is returned.
*
* @param vec
* the vector to dot with this vector.
* @return the resultant dot product of this vector and a given vector.
*/
public float dot(Vector3f vec) {
if (null == vec) {
logger.warning("Provided vector is null, 0 returned.");
return 0;
}
return x * vec.x + y * vec.y + z * vec.z;
}
/**
* <code>cross</code> calculates the cross product of this vector with a
* parameter vector v.
*
* @param v
* the vector to take the cross product of with this.
* @return the cross product vector.
*/
public Vector3f cross(Vector3f v) {
return cross(v, null);
}
/**
* <code>cross</code> calculates the cross product of this vector with a
* parameter vector v. The result is stored in <code>result</code>
*
* @param v
* the vector to take the cross product of with this.
* @param result
* the vector to store the cross product result.
* @return result, after recieving the cross product vector.
*/
public Vector3f cross(Vector3f v,Vector3f result) {
return cross(v.x, v.y, v.z, result);
}
/**
* <code>cross</code> calculates the cross product of this vector with a
* parameter vector v. The result is stored in <code>result</code>
*
* @param otherX
* x component of the vector to take the cross product of with this.
* @param otherY
* y component of the vector to take the cross product of with this.
* @param otherZ
* z component of the vector to take the cross product of with this.
* @param result
* the vector to store the cross product result.
* @return result, after recieving the cross product vector.
*/
public Vector3f cross(float otherX, float otherY, float otherZ, Vector3f result) {
if (result == null) result = new Vector3f();
float resX = ((y * otherZ) - (z * otherY));
float resY = ((z * otherX) - (x * otherZ));
float resZ = ((x * otherY) - (y * otherX));
result.set(resX, resY, resZ);
return result;
}
/**
* <code>crossLocal</code> calculates the cross product of this vector
* with a parameter vector v.
*
* @param v
* the vector to take the cross product of with this.
* @return this.
*/
public Vector3f crossLocal(Vector3f v) {
return crossLocal(v.x, v.y, v.z);
}
/**
* <code>crossLocal</code> calculates the cross product of this vector
* with a parameter vector v.
*
* @param otherX
* x component of the vector to take the cross product of with this.
* @param otherY
* y component of the vector to take the cross product of with this.
* @param otherZ
* z component of the vector to take the cross product of with this.
* @return this.
*/
public Vector3f crossLocal(float otherX, float otherY, float otherZ) {
float tempx = ( y * otherZ ) - ( z * otherY );
float tempy = ( z * otherX ) - ( x * otherZ );
z = (x * otherY) - (y * otherX);
x = tempx;
y = tempy;
return this;
}
/**
* Projects this vector onto another vector
*
* @param other The vector to project this vector onto
* @return A new vector with the projection result
*/
public Vector3f project(Vector3f other){
float n = this.dot(other); // A . B
float d = other.lengthSquared(); // |B|^2
return new Vector3f(other).normalizeLocal().multLocal(n/d);
}
/**
* Projects this vector onto another vector, stores the result in this
* vector
*
* @param other The vector to project this vector onto
* @return This Vector3f, set to the projection result
*/
public Vector3f projectLocal(Vector3f other){
float n = this.dot(other); // A . B
float d = other.lengthSquared(); // |B|^2
return set(other).normalizeLocal().multLocal(n/d);
}
/**
* Returns true if this vector is a unit vector (length() ~= 1),
* returns false otherwise.
*
* @return true if this vector is a unit vector (length() ~= 1),
* or false otherwise.
*/
public boolean isUnitVector(){
float len = length();
return 0.99f < len && len < 1.01f;
}
/**
* <code>length</code> calculates the magnitude of this vector.
*
* @return the length or magnitude of the vector.
*/
public float length() {
return FastMath.sqrt(lengthSquared());
}
/**
* <code>lengthSquared</code> calculates the squared value of the
* magnitude of the vector.
*
* @return the magnitude squared of the vector.
*/
public float lengthSquared() {
return x * x + y * y + z * z;
}
/**
* <code>distanceSquared</code> calculates the distance squared between
* this vector and vector v.
*
* @param v the second vector to determine the distance squared.
* @return the distance squared between the two vectors.
*/
public float distanceSquared(Vector3f v) {
double dx = x - v.x;
double dy = y - v.y;
double dz = z - v.z;
return (float) (dx * dx + dy * dy + dz * dz);
}
/**
* <code>distance</code> calculates the distance between this vector and
* vector v.
*
* @param v the second vector to determine the distance.
* @return the distance between the two vectors.
*/
public float distance(Vector3f v) {
return FastMath.sqrt(distanceSquared(v));
}
/**
*
* <code>mult</code> multiplies this vector by a scalar. The resultant
* vector is returned.
*
* @param scalar
* the value to multiply this vector by.
* @return the new vector.
*/
public Vector3f mult(float scalar) {
return new Vector3f(x * scalar, y * scalar, z * scalar);
}
/**
*
* <code>mult</code> multiplies this vector by a scalar. The resultant
* vector is supplied as the second parameter and returned.
*
* @param scalar the scalar to multiply this vector by.
* @param product the product to store the result in.
* @return product
*/
public Vector3f mult(float scalar, Vector3f product) {
if (null == product) {
product = new Vector3f();
}
product.x = x * scalar;
product.y = y * scalar;
product.z = z * scalar;
return product;
}
/**
* <code>multLocal</code> multiplies this vector by a scalar internally,
* and returns a handle to this vector for easy chaining of calls.
*
* @param scalar
* the value to multiply this vector by.
* @return this
*/
public Vector3f multLocal(float scalar) {
x *= scalar;
y *= scalar;
z *= scalar;
return this;
}
/**
* <code>multLocal</code> multiplies a provided vector to this vector
* internally, and returns a handle to this vector for easy chaining of
* calls. If the provided vector is null, null is returned.
*
* @param vec
* the vector to mult to this vector.
* @return this
*/
public Vector3f multLocal(Vector3f vec) {
if (null == vec) {
logger.warning("Provided vector is null, null returned.");
return null;
}
x *= vec.x;
y *= vec.y;
z *= vec.z;
return this;
}
/**
* <code>multLocal</code> multiplies this vector by 3 scalars
* internally, and returns a handle to this vector for easy chaining of
* calls.
*
* @param x
* @param y
* @param z
* @return this
*/
public Vector3f multLocal(float x, float y, float z) {
this.x *= x;
this.y *= y;
this.z *= z;
return this;
}
/**
* <code>multLocal</code> multiplies a provided vector to this vector
* internally, and returns a handle to this vector for easy chaining of
* calls. If the provided vector is null, null is returned.
*
* @param vec
* the vector to mult to this vector.
* @return this
*/
public Vector3f mult(Vector3f vec) {
if (null == vec) {
logger.warning("Provided vector is null, null returned.");
return null;
}
return mult(vec, null);
}
/**
* <code>multLocal</code> multiplies a provided vector to this vector
* internally, and returns a handle to this vector for easy chaining of
* calls. If the provided vector is null, null is returned.
*
* @param vec
* the vector to mult to this vector.
* @param store result vector (null to create a new vector)
* @return this
*/
public Vector3f mult(Vector3f vec, Vector3f store) {
if (null == vec) {
logger.warning("Provided vector is null, null returned.");
return null;
}
if (store == null) store = new Vector3f();
return store.set(x * vec.x, y * vec.y, z * vec.z);
}
/**
* <code>divide</code> divides the values of this vector by a scalar and
* returns the result. The values of this vector remain untouched.
*
* @param scalar
* the value to divide this vectors attributes by.
* @return the result <code>Vector</code>.
*/
public Vector3f divide(float scalar) {
scalar = 1f/scalar;
return new Vector3f(x * scalar, y * scalar, z * scalar);
}
/**
* <code>divideLocal</code> divides this vector by a scalar internally,
* and returns a handle to this vector for easy chaining of calls. Dividing
* by zero will result in an exception.
*
* @param scalar
* the value to divides this vector by.
* @return this
*/
public Vector3f divideLocal(float scalar) {
scalar = 1f/scalar;
x *= scalar;
y *= scalar;
z *= scalar;
return this;
}
/**
* <code>divide</code> divides the values of this vector by a scalar and
* returns the result. The values of this vector remain untouched.
*
* @param scalar
* the value to divide this vectors attributes by.
* @return the result <code>Vector</code>.
*/
public Vector3f divide(Vector3f scalar) {
return new Vector3f(x / scalar.x, y / scalar.y, z / scalar.z);
}
/**
* <code>divideLocal</code> divides this vector by a scalar internally,
* and returns a handle to this vector for easy chaining of calls. Dividing
* by zero will result in an exception.
*
* @param scalar
* the value to divides this vector by.
* @return this
*/
public Vector3f divideLocal(Vector3f scalar) {
x /= scalar.x;
y /= scalar.y;
z /= scalar.z;
return this;
}
/**
*
* <code>negate</code> returns the negative of this vector. All values are
* negated and set to a new vector.
*
* @return the negated vector.
*/
public Vector3f negate() {
return new Vector3f(-x, -y, -z);
}
/**
*
* <code>negateLocal</code> negates the internal values of this vector.
*
* @return this.
*/
public Vector3f negateLocal() {
x = -x;
y = -y;
z = -z;
return this;
}
/**
*
* <code>subtract</code> subtracts the values of a given vector from those
* of this vector creating a new vector object. If the provided vector is
* null, null is returned.
*
* @param vec
* the vector to subtract from this vector.
* @return the result vector.
*/
public Vector3f subtract(Vector3f vec) {
return new Vector3f(x - vec.x, y - vec.y, z - vec.z);
}
/**
* <code>subtractLocal</code> subtracts a provided vector to this vector
* internally, and returns a handle to this vector for easy chaining of
* calls. If the provided vector is null, null is returned.
*
* @param vec
* the vector to subtract
* @return this
*/
public Vector3f subtractLocal(Vector3f vec) {
if (null == vec) {
logger.warning("Provided vector is null, null returned.");
return null;
}
x -= vec.x;
y -= vec.y;
z -= vec.z;
return this;
}
/**
*
* <code>subtract</code>
*
* @param vec
* the vector to subtract from this
* @param result
* the vector to store the result in
* @return result
*/
public Vector3f subtract(Vector3f vec, Vector3f result) {
if(result == null) {
result = new Vector3f();
}
result.x = x - vec.x;
result.y = y - vec.y;
result.z = z - vec.z;
return result;
}
/**
*
* <code>subtract</code> subtracts the provided values from this vector,
* creating a new vector that is then returned.
*
* @param subtractX
* the x value to subtract.
* @param subtractY
* the y value to subtract.
* @param subtractZ
* the z value to subtract.
* @return the result vector.
*/
public Vector3f subtract(float subtractX, float subtractY, float subtractZ) {
return new Vector3f(x - subtractX, y - subtractY, z - subtractZ);
}
/**
* <code>subtractLocal</code> subtracts the provided values from this vector
* internally, and returns a handle to this vector for easy chaining of
* calls.
*
* @param subtractX
* the x value to subtract.
* @param subtractY
* the y value to subtract.
* @param subtractZ
* the z value to subtract.
* @return this
*/
public Vector3f subtractLocal(float subtractX, float subtractY, float subtractZ) {
x -= subtractX;
y -= subtractY;
z -= subtractZ;
return this;
}
/**
* <code>normalize</code> returns the unit vector of this vector.
*
* @return unit vector of this vector.
*/
public Vector3f normalize() {
// float length = length();
// if (length != 0) {
// return divide(length);
// }
//
// return divide(1);
float length = x * x + y * y + z * z;
if (length != 1f && length != 0f){
length = 1.0f / FastMath.sqrt(length);
return new Vector3f(x * length, y * length, z * length);
}
return clone();
}
/**
* <code>normalizeLocal</code> makes this vector into a unit vector of
* itself.
*
* @return this.
*/
public Vector3f normalizeLocal() {
// NOTE: this implementation is more optimized
// than the old jme normalize as this method
// is commonly used.
float length = x * x + y * y + z * z;
if (length != 1f && length != 0f){
length = 1.0f / FastMath.sqrt(length);
x *= length;
y *= length;
z *= length;
}
return this;
}
/**
* <code>maxLocal</code> computes the maximum value for each
* component in this and <code>other</code> vector. The result is stored
* in this vector.
* @param other
*/
public Vector3f maxLocal(Vector3f other){
x = other.x > x ? other.x : x;
y = other.y > y ? other.y : y;
z = other.z > z ? other.z : z;
return this;
}
/**
* <code>minLocal</code> computes the minimum value for each
* component in this and <code>other</code> vector. The result is stored
* in this vector.
* @param other
*/
public Vector3f minLocal(Vector3f other){
x = other.x < x ? other.x : x;
y = other.y < y ? other.y : y;
z = other.z < z ? other.z : z;
return this;
}
/**
* <code>zero</code> resets this vector's data to zero internally.
*/
public Vector3f zero() {
x = y = z = 0;
return this;
}
/**
* <code>angleBetween</code> returns (in radians) the angle between two vectors.
* It is assumed that both this vector and the given vector are unit vectors (iow, normalized).
*
* @param otherVector a unit vector to find the angle against
* @return the angle in radians.
*/
public float angleBetween(Vector3f otherVector) {
float dotProduct = dot(otherVector);
float angle = FastMath.acos(dotProduct);
return angle;
}
/**
* Sets this vector to the interpolation by changeAmnt from this to the finalVec
* this=(1-changeAmnt)*this + changeAmnt * finalVec
* @param finalVec The final vector to interpolate towards
* @param changeAmnt An amount between 0.0 - 1.0 representing a precentage
* change from this towards finalVec
*/
public Vector3f interpolateLocal(Vector3f finalVec, float changeAmnt) {
this.x=(1-changeAmnt)*this.x + changeAmnt*finalVec.x;
this.y=(1-changeAmnt)*this.y + changeAmnt*finalVec.y;
this.z=(1-changeAmnt)*this.z + changeAmnt*finalVec.z;
return this;
}
/**
* Sets this vector to the interpolation by changeAmnt from beginVec to finalVec
* this=(1-changeAmnt)*beginVec + changeAmnt * finalVec
* @param beginVec the beging vector (changeAmnt=0)
* @param finalVec The final vector to interpolate towards
* @param changeAmnt An amount between 0.0 - 1.0 representing a precentage
* change from beginVec towards finalVec
*/
public Vector3f interpolateLocal(Vector3f beginVec,Vector3f finalVec, float changeAmnt) {
this.x=(1-changeAmnt)*beginVec.x + changeAmnt*finalVec.x;
this.y=(1-changeAmnt)*beginVec.y + changeAmnt*finalVec.y;
this.z=(1-changeAmnt)*beginVec.z + changeAmnt*finalVec.z;
return this;
}
/**
* Check a vector... if it is null or its floats are NaN or infinite,
* return false. Else return true.
* @param vector the vector to check
* @return true or false as stated above.
*/
public static boolean isValidVector(Vector3f vector) {
if (vector == null) return false;
if (Float.isNaN(vector.x) ||
Float.isNaN(vector.y) ||
Float.isNaN(vector.z)) return false;
if (Float.isInfinite(vector.x) ||
Float.isInfinite(vector.y) ||
Float.isInfinite(vector.z)) return false;
return true;
}
public static void generateOrthonormalBasis(Vector3f u, Vector3f v, Vector3f w) {
w.normalizeLocal();
generateComplementBasis(u, v, w);
}
public static void generateComplementBasis(Vector3f u, Vector3f v,
Vector3f w) {
float fInvLength;
if (FastMath.abs(w.x) >= FastMath.abs(w.y)) {
// w.x or w.z is the largest magnitude component, swap them
fInvLength = FastMath.invSqrt(w.x * w.x + w.z * w.z);
u.x = -w.z * fInvLength;
u.y = 0.0f;
u.z = +w.x * fInvLength;
v.x = w.y * u.z;
v.y = w.z * u.x - w.x * u.z;
v.z = -w.y * u.x;
} else {
// w.y or w.z is the largest magnitude component, swap them
fInvLength = FastMath.invSqrt(w.y * w.y + w.z * w.z);
u.x = 0.0f;
u.y = +w.z * fInvLength;
u.z = -w.y * fInvLength;
v.x = w.y * u.z - w.z * u.y;
v.y = -w.x * u.z;
v.z = w.x * u.y;
}
}
@Override
public Vector3f clone() {
try {
return (Vector3f) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError(); // can not happen
}
}
/**
* Saves this Vector3f into the given float[] object.
*
* @param floats
* The float[] to take this Vector3f. If null, a new float[3] is
* created.
* @return The array, with X, Y, Z float values in that order
*/
public float[] toArray(float[] floats) {
if (floats == null) {
floats = new float[3];
}
floats[0] = x;
floats[1] = y;
floats[2] = z;
return floats;
}
/**
* are these two vectors the same? they are is they both have the same x,y,
* and z values.
*
* @param o
* the object to compare for equality
* @return true if they are equal
*/
public boolean equals(Object o) {
if (!(o instanceof Vector3f)) { return false; }
if (this == o) { return true; }
Vector3f comp = (Vector3f) o;
if (Float.compare(x,comp.x) != 0) return false;
if (Float.compare(y,comp.y) != 0) return false;
if (Float.compare(z,comp.z) != 0) return false;
return true;
}
/**
* <code>hashCode</code> returns a unique code for this vector object based
* on it's values. If two vectors are logically equivalent, they will return
* the same hash code value.
* @return the hash code value of this vector.
*/
public int hashCode() {
int hash = 37;
hash += 37 * hash + Float.floatToIntBits(x);
hash += 37 * hash + Float.floatToIntBits(y);
hash += 37 * hash + Float.floatToIntBits(z);
return hash;
}
/**
* <code>toString</code> returns the string representation of this vector.
* The format is:
*
* org.jme.math.Vector3f [X=XX.XXXX, Y=YY.YYYY, Z=ZZ.ZZZZ]
*
* @return the string representation of this vector.
*/
public String toString() {
return "(" + x + ", " + y + ", " + z + ")";
}
public float getX() {
return x;
}
public Vector3f setX(float x) {
this.x = x;
return this;
}
public float getY() {
return y;
}
public Vector3f setY(float y) {
this.y = y;
return this;
}
public float getZ() {
return z;
}
public Vector3f setZ(float z) {
this.z = z;
return this;
}
/**
* @param index
* @return x value if index == 0, y value if index == 1 or z value if index ==
* 2
* @throws IllegalArgumentException
* if index is not one of 0, 1, 2.
*/
public float get(int index) {
switch (index) {
case 0:
return x;
case 1:
return y;
case 2:
return z;
}
throw new IllegalArgumentException("index must be either 0, 1 or 2");
}
/**
* @param index
* which field index in this vector to set.
* @param value
* to set to one of x, y or z.
* @throws IllegalArgumentException
* if index is not one of 0, 1, 2.
*/
public void set(int index, float value) {
switch (index) {
case 0:
x = value;
return;
case 1:
y = value;
return;
case 2:
z = value;
return;
}
throw new IllegalArgumentException("index must be either 0, 1 or 2");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment