Home | History | Annotate | Download | only in math
      1 /*
      2  * Copyright (c) 2009-2010 jMonkeyEngine
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are
      7  * met:
      8  *
      9  * * Redistributions of source code must retain the above copyright
     10  *   notice, this list of conditions and the following disclaimer.
     11  *
     12  * * Redistributions in binary form must reproduce the above copyright
     13  *   notice, this list of conditions and the following disclaimer in the
     14  *   documentation and/or other materials provided with the distribution.
     15  *
     16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
     17  *   may be used to endorse or promote products derived from this software
     18  *   without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 package com.jme3.math;
     33 
     34 import java.util.Random;
     35 
     36 /**
     37  * <code>FastMath</code> provides 'fast' math approximations and float equivalents of Math
     38  * functions.  These are all used as static values and functions.
     39  *
     40  * @author Various
     41  * @version $Id: FastMath.java,v 1.45 2007/08/26 08:44:20 irrisor Exp $
     42  */
     43 final public class FastMath {
     44 
     45     private FastMath() {
     46     }
     47     /** A "close to zero" double epsilon value for use*/
     48     public static final double DBL_EPSILON = 2.220446049250313E-16d;
     49     /** A "close to zero" float epsilon value for use*/
     50     public static final float FLT_EPSILON = 1.1920928955078125E-7f;
     51     /** A "close to zero" float epsilon value for use*/
     52     public static final float ZERO_TOLERANCE = 0.0001f;
     53     public static final float ONE_THIRD = 1f / 3f;
     54     /** The value PI as a float. (180 degrees) */
     55     public static final float PI = (float) Math.PI;
     56     /** The value 2PI as a float. (360 degrees) */
     57     public static final float TWO_PI = 2.0f * PI;
     58     /** The value PI/2 as a float. (90 degrees) */
     59     public static final float HALF_PI = 0.5f * PI;
     60     /** The value PI/4 as a float. (45 degrees) */
     61     public static final float QUARTER_PI = 0.25f * PI;
     62     /** The value 1/PI as a float. */
     63     public static final float INV_PI = 1.0f / PI;
     64     /** The value 1/(2PI) as a float. */
     65     public static final float INV_TWO_PI = 1.0f / TWO_PI;
     66     /** A value to multiply a degree value by, to convert it to radians. */
     67     public static final float DEG_TO_RAD = PI / 180.0f;
     68     /** A value to multiply a radian value by, to convert it to degrees. */
     69     public static final float RAD_TO_DEG = 180.0f / PI;
     70     /** A precreated random object for random numbers. */
     71     public static final Random rand = new Random(System.currentTimeMillis());
     72 
     73     /**
     74      * Returns true if the number is a power of 2 (2,4,8,16...)
     75      *
     76      * A good implementation found on the Java boards. note: a number is a power
     77      * of two if and only if it is the smallest number with that number of
     78      * significant bits. Therefore, if you subtract 1, you know that the new
     79      * number will have fewer bits, so ANDing the original number with anything
     80      * less than it will give 0.
     81      *
     82      * @param number
     83      *            The number to test.
     84      * @return True if it is a power of two.
     85      */
     86     public static boolean isPowerOfTwo(int number) {
     87         return (number > 0) && (number & (number - 1)) == 0;
     88     }
     89 
     90     public static int nearestPowerOfTwo(int number) {
     91         return (int) Math.pow(2, Math.ceil(Math.log(number) / Math.log(2)));
     92     }
     93 
     94     /**
     95      * Linear interpolation from startValue to endValue by the given percent.
     96      * Basically: ((1 - percent) * startValue) + (percent * endValue)
     97      *
     98      * @param scale
     99      *            scale value to use. if 1, use endValue, if 0, use startValue.
    100      * @param startValue
    101      *            Begining value. 0% of f
    102      * @param endValue
    103      *            ending value. 100% of f
    104      * @return The interpolated value between startValue and endValue.
    105      */
    106     public static float interpolateLinear(float scale, float startValue, float endValue) {
    107         if (startValue == endValue) {
    108             return startValue;
    109         }
    110         if (scale <= 0f) {
    111             return startValue;
    112         }
    113         if (scale >= 1f) {
    114             return endValue;
    115         }
    116         return ((1f - scale) * startValue) + (scale * endValue);
    117     }
    118 
    119     /**
    120      * Linear interpolation from startValue to endValue by the given percent.
    121      * Basically: ((1 - percent) * startValue) + (percent * endValue)
    122      *
    123      * @param scale
    124      *            scale value to use. if 1, use endValue, if 0, use startValue.
    125      * @param startValue
    126      *            Begining value. 0% of f
    127      * @param endValue
    128      *            ending value. 100% of f
    129      * @param store a vector3f to store the result
    130      * @return The interpolated value between startValue and endValue.
    131      */
    132     public static Vector3f interpolateLinear(float scale, Vector3f startValue, Vector3f endValue, Vector3f store) {
    133         if (store == null) {
    134             store = new Vector3f();
    135         }
    136         store.x = interpolateLinear(scale, startValue.x, endValue.x);
    137         store.y = interpolateLinear(scale, startValue.y, endValue.y);
    138         store.z = interpolateLinear(scale, startValue.z, endValue.z);
    139         return store;
    140     }
    141 
    142     /**
    143      * Linear interpolation from startValue to endValue by the given percent.
    144      * Basically: ((1 - percent) * startValue) + (percent * endValue)
    145      *
    146      * @param scale
    147      *            scale value to use. if 1, use endValue, if 0, use startValue.
    148      * @param startValue
    149      *            Begining value. 0% of f
    150      * @param endValue
    151      *            ending value. 100% of f
    152      * @return The interpolated value between startValue and endValue.
    153      */
    154     public static Vector3f interpolateLinear(float scale, Vector3f startValue, Vector3f endValue) {
    155         return interpolateLinear(scale, startValue, endValue, null);
    156     }
    157 
    158     /**
    159      * Linear extrapolation from startValue to endValue by the given scale.
    160      * if scale is between 0 and 1 this method returns the same result as interpolateLinear
    161      * if the scale is over 1 the value is linearly extrapolated.
    162      * Note that the end value is the value for a scale of 1.
    163      * @param scale the scale for extrapolation
    164      * @param startValue the starting value (scale = 0)
    165      * @param endValue the end value (scale = 1)
    166      * @return an extrapolation for the given parameters
    167      */
    168     public static float extrapolateLinear(float scale, float startValue, float endValue) {
    169 //        if (scale <= 0f) {
    170 //            return startValue;
    171 //        }
    172         return ((1f - scale) * startValue) + (scale * endValue);
    173     }
    174 
    175     /**
    176      * Linear extrapolation from startValue to endValue by the given scale.
    177      * if scale is between 0 and 1 this method returns the same result as interpolateLinear
    178      * if the scale is over 1 the value is linearly extrapolated.
    179      * Note that the end value is the value for a scale of 1.
    180      * @param scale the scale for extrapolation
    181      * @param startValue the starting value (scale = 0)
    182      * @param endValue the end value (scale = 1)
    183      * @param store an initialized vector to store the return value
    184      * @return an extrapolation for the given parameters
    185      */
    186     public static Vector3f extrapolateLinear(float scale, Vector3f startValue, Vector3f endValue, Vector3f store) {
    187         if (store == null) {
    188             store = new Vector3f();
    189         }
    190 //        if (scale <= 1f) {
    191 //            return interpolateLinear(scale, startValue, endValue, store);
    192 //        }
    193         store.x = extrapolateLinear(scale, startValue.x, endValue.x);
    194         store.y = extrapolateLinear(scale, startValue.y, endValue.y);
    195         store.z = extrapolateLinear(scale, startValue.z, endValue.z);
    196         return store;
    197     }
    198 
    199     /**
    200      * Linear extrapolation from startValue to endValue by the given scale.
    201      * if scale is between 0 and 1 this method returns the same result as interpolateLinear
    202      * if the scale is over 1 the value is linearly extrapolated.
    203      * Note that the end value is the value for a scale of 1.
    204      * @param scale the scale for extrapolation
    205      * @param startValue the starting value (scale = 0)
    206      * @param endValue the end value (scale = 1)
    207      * @return an extrapolation for the given parameters
    208      */
    209     public static Vector3f extrapolateLinear(float scale, Vector3f startValue, Vector3f endValue) {
    210         return extrapolateLinear(scale, startValue, endValue, null);
    211     }
    212 
    213     /**Interpolate a spline between at least 4 control points following the Catmull-Rom equation.
    214      * here is the interpolation matrix
    215      * m = [ 0.0  1.0  0.0   0.0 ]
    216      *     [-T    0.0  T     0.0 ]
    217      *     [ 2T   T-3  3-2T  -T  ]
    218      *     [-T    2-T  T-2   T   ]
    219      * where T is the curve tension
    220      * the result is a value between p1 and p2, t=0 for p1, t=1 for p2
    221      * @param u value from 0 to 1
    222      * @param T The tension of the curve
    223      * @param p0 control point 0
    224      * @param p1 control point 1
    225      * @param p2 control point 2
    226      * @param p3 control point 3
    227      * @return catmull-Rom interpolation
    228      */
    229     public static float interpolateCatmullRom(float u, float T, float p0, float p1, float p2, float p3) {
    230         float c1, c2, c3, c4;
    231         c1 = p1;
    232         c2 = -1.0f * T * p0 + T * p2;
    233         c3 = 2 * T * p0 + (T - 3) * p1 + (3 - 2 * T) * p2 + -T * p3;
    234         c4 = -T * p0 + (2 - T) * p1 + (T - 2) * p2 + T * p3;
    235 
    236         return (float) (((c4 * u + c3) * u + c2) * u + c1);
    237     }
    238 
    239     /**Interpolate a spline between at least 4 control points following the Catmull-Rom equation.
    240      * here is the interpolation matrix
    241      * m = [ 0.0  1.0  0.0   0.0 ]
    242      *     [-T    0.0  T     0.0 ]
    243      *     [ 2T   T-3  3-2T  -T  ]
    244      *     [-T    2-T  T-2   T   ]
    245      * where T is the tension of the curve
    246      * the result is a value between p1 and p2, t=0 for p1, t=1 for p2
    247      * @param u value from 0 to 1
    248      * @param T The tension of the curve
    249      * @param p0 control point 0
    250      * @param p1 control point 1
    251      * @param p2 control point 2
    252      * @param p3 control point 3
    253      * @param store a Vector3f to store the result
    254      * @return catmull-Rom interpolation
    255      */
    256     public static Vector3f interpolateCatmullRom(float u, float T, Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3, Vector3f store) {
    257         if (store == null) {
    258             store = new Vector3f();
    259         }
    260         store.x = interpolateCatmullRom(u, T, p0.x, p1.x, p2.x, p3.x);
    261         store.y = interpolateCatmullRom(u, T, p0.y, p1.y, p2.y, p3.y);
    262         store.z = interpolateCatmullRom(u, T, p0.z, p1.z, p2.z, p3.z);
    263         return store;
    264     }
    265 
    266     /**Interpolate a spline between at least 4 control points following the Catmull-Rom equation.
    267      * here is the interpolation matrix
    268      * m = [ 0.0  1.0  0.0   0.0 ]
    269      *     [-T    0.0  T     0.0 ]
    270      *     [ 2T   T-3  3-2T  -T  ]
    271      *     [-T    2-T  T-2   T   ]
    272      * where T is the tension of the curve
    273      * the result is a value between p1 and p2, t=0 for p1, t=1 for p2
    274      * @param u value from 0 to 1
    275      * @param T The tension of the curve
    276      * @param p0 control point 0
    277      * @param p1 control point 1
    278      * @param p2 control point 2
    279      * @param p3 control point 3
    280      * @return catmull-Rom interpolation
    281      */
    282     public static Vector3f interpolateCatmullRom(float u, float T, Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3) {
    283         return interpolateCatmullRom(u, T, p0, p1, p2, p3, null);
    284     }
    285 
    286     /**Interpolate a spline between at least 4 control points following the Bezier equation.
    287      * here is the interpolation matrix
    288      * m = [ -1.0   3.0  -3.0    1.0 ]
    289      *     [  3.0  -6.0   3.0    0.0 ]
    290      *     [ -3.0   3.0   0.0    0.0 ]
    291      *     [  1.0   0.0   0.0    0.0 ]
    292      * where T is the curve tension
    293      * the result is a value between p1 and p3, t=0 for p1, t=1 for p3
    294      * @param u value from 0 to 1
    295      * @param p0 control point 0
    296      * @param p1 control point 1
    297      * @param p2 control point 2
    298      * @param p3 control point 3
    299      * @return Bezier interpolation
    300      */
    301     public static float interpolateBezier(float u, float p0, float p1, float p2, float p3) {
    302         float oneMinusU = 1.0f - u;
    303         float oneMinusU2 = oneMinusU * oneMinusU;
    304         float u2 = u * u;
    305         return p0 * oneMinusU2 * oneMinusU
    306                 + 3.0f * p1 * u * oneMinusU2
    307                 + 3.0f * p2 * u2 * oneMinusU
    308                 + p3 * u2 * u;
    309     }
    310 
    311     /**Interpolate a spline between at least 4 control points following the Bezier equation.
    312      * here is the interpolation matrix
    313      * m = [ -1.0   3.0  -3.0    1.0 ]
    314      *     [  3.0  -6.0   3.0    0.0 ]
    315      *     [ -3.0   3.0   0.0    0.0 ]
    316      *     [  1.0   0.0   0.0    0.0 ]
    317      * where T is the tension of the curve
    318      * the result is a value between p1 and p3, t=0 for p1, t=1 for p3
    319      * @param u value from 0 to 1
    320      * @param p0 control point 0
    321      * @param p1 control point 1
    322      * @param p2 control point 2
    323      * @param p3 control point 3
    324      * @param store a Vector3f to store the result
    325      * @return Bezier interpolation
    326      */
    327     public static Vector3f interpolateBezier(float u, Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3, Vector3f store) {
    328         if (store == null) {
    329             store = new Vector3f();
    330         }
    331         store.x = interpolateBezier(u, p0.x, p1.x, p2.x, p3.x);
    332         store.y = interpolateBezier(u, p0.y, p1.y, p2.y, p3.y);
    333         store.z = interpolateBezier(u, p0.z, p1.z, p2.z, p3.z);
    334         return store;
    335     }
    336 
    337     /**Interpolate a spline between at least 4 control points following the Bezier equation.
    338      * here is the interpolation matrix
    339      * m = [ -1.0   3.0  -3.0    1.0 ]
    340      *     [  3.0  -6.0   3.0    0.0 ]
    341      *     [ -3.0   3.0   0.0    0.0 ]
    342      *     [  1.0   0.0   0.0    0.0 ]
    343      * where T is the tension of the curve
    344      * the result is a value between p1 and p3, t=0 for p1, t=1 for p3
    345      * @param u value from 0 to 1
    346      * @param p0 control point 0
    347      * @param p1 control point 1
    348      * @param p2 control point 2
    349      * @param p3 control point 3
    350      * @return Bezier interpolation
    351      */
    352     public static Vector3f interpolateBezier(float u, Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3) {
    353         return interpolateBezier(u, p0, p1, p2, p3, null);
    354     }
    355 
    356     /**
    357      * Compute the lenght on a catmull rom spline between control point 1 and 2
    358      * @param p0 control point 0
    359      * @param p1 control point 1
    360      * @param p2 control point 2
    361      * @param p3 control point 3
    362      * @param startRange the starting range on the segment (use 0)
    363      * @param endRange the end range on the segment (use 1)
    364      * @param curveTension the curve tension
    365      * @return the length of the segment
    366      */
    367     public static float getCatmullRomP1toP2Length(Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3, float startRange, float endRange, float curveTension) {
    368 
    369         float epsilon = 0.001f;
    370         float middleValue = (startRange + endRange) * 0.5f;
    371         Vector3f start = p1.clone();
    372         if (startRange != 0) {
    373             FastMath.interpolateCatmullRom(startRange, curveTension, p0, p1, p2, p3, start);
    374         }
    375         Vector3f end = p2.clone();
    376         if (endRange != 1) {
    377             FastMath.interpolateCatmullRom(endRange, curveTension, p0, p1, p2, p3, end);
    378         }
    379         Vector3f middle = FastMath.interpolateCatmullRom(middleValue, curveTension, p0, p1, p2, p3);
    380         float l = end.subtract(start).length();
    381         float l1 = middle.subtract(start).length();
    382         float l2 = end.subtract(middle).length();
    383         float len = l1 + l2;
    384         if (l + epsilon < len) {
    385             l1 = getCatmullRomP1toP2Length(p0, p1, p2, p3, startRange, middleValue, curveTension);
    386             l2 = getCatmullRomP1toP2Length(p0, p1, p2, p3, middleValue, endRange, curveTension);
    387         }
    388         l = l1 + l2;
    389         return l;
    390     }
    391 
    392     /**
    393      * Compute the lenght on a bezier spline between control point 1 and 2
    394      * @param p0 control point 0
    395      * @param p1 control point 1
    396      * @param p2 control point 2
    397      * @param p3 control point 3
    398      * @return the length of the segment
    399      */
    400     public static float getBezierP1toP2Length(Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3) {
    401         float delta = 0.02f, t = 0.0f, result = 0.0f;
    402         Vector3f v1 = p0.clone(), v2 = new Vector3f();
    403         while (t <= 1.0f) {
    404             FastMath.interpolateBezier(t, p0, p1, p2, p3, v2);
    405             result += v1.subtractLocal(v2).length();
    406             v1.set(v2);
    407             t += delta;
    408         }
    409         return result;
    410     }
    411 
    412     /**
    413      * Returns the arc cosine of an angle given in radians.<br>
    414      * Special cases:
    415      * <ul><li>If fValue is smaller than -1, then the result is PI.
    416      * <li>If the argument is greater than 1, then the result is 0.</ul>
    417      * @param fValue The angle, in radians.
    418      * @return fValue's acos
    419      * @see java.lang.Math#acos(double)
    420      */
    421     public static float acos(float fValue) {
    422         if (-1.0f < fValue) {
    423             if (fValue < 1.0f) {
    424                 return (float) Math.acos(fValue);
    425             }
    426 
    427             return 0.0f;
    428         }
    429 
    430         return PI;
    431     }
    432 
    433     /**
    434      * Returns the arc sine of an angle given in radians.<br>
    435      * Special cases:
    436      * <ul><li>If fValue is smaller than -1, then the result is -HALF_PI.
    437      * <li>If the argument is greater than 1, then the result is HALF_PI.</ul>
    438      * @param fValue The angle, in radians.
    439      * @return fValue's asin
    440      * @see java.lang.Math#asin(double)
    441      */
    442     public static float asin(float fValue) {
    443         if (-1.0f < fValue) {
    444             if (fValue < 1.0f) {
    445                 return (float) Math.asin(fValue);
    446             }
    447 
    448             return HALF_PI;
    449         }
    450 
    451         return -HALF_PI;
    452     }
    453 
    454     /**
    455      * Returns the arc tangent of an angle given in radians.<br>
    456      * @param fValue The angle, in radians.
    457      * @return fValue's atan
    458      * @see java.lang.Math#atan(double)
    459      */
    460     public static float atan(float fValue) {
    461         return (float) Math.atan(fValue);
    462     }
    463 
    464     /**
    465      * A direct call to Math.atan2.
    466      * @param fY
    467      * @param fX
    468      * @return Math.atan2(fY,fX)
    469      * @see java.lang.Math#atan2(double, double)
    470      */
    471     public static float atan2(float fY, float fX) {
    472         return (float) Math.atan2(fY, fX);
    473     }
    474 
    475     /**
    476      * Rounds a fValue up.  A call to Math.ceil
    477      * @param fValue The value.
    478      * @return The fValue rounded up
    479      * @see java.lang.Math#ceil(double)
    480      */
    481     public static float ceil(float fValue) {
    482         return (float) Math.ceil(fValue);
    483     }
    484 
    485     /**
    486      * Fast Trig functions for x86. This forces the trig functiosn to stay
    487      * within the safe area on the x86 processor (-45 degrees to +45 degrees)
    488      * The results may be very slightly off from what the Math and StrictMath
    489      * trig functions give due to rounding in the angle reduction but it will be
    490      * very very close.
    491      *
    492      * note: code from wiki posting on java.net by jeffpk
    493      */
    494     public static float reduceSinAngle(float radians) {
    495         radians %= TWO_PI; // put us in -2PI to +2PI space
    496         if (Math.abs(radians) > PI) { // put us in -PI to +PI space
    497             radians = radians - (TWO_PI);
    498         }
    499         if (Math.abs(radians) > HALF_PI) {// put us in -PI/2 to +PI/2 space
    500             radians = PI - radians;
    501         }
    502 
    503         return radians;
    504     }
    505 
    506     /**
    507      * Returns sine of a value.
    508      *
    509      * note: code from wiki posting on java.net by jeffpk
    510      *
    511      * @param fValue
    512      *            The value to sine, in radians.
    513      * @return The sine of fValue.
    514      * @see java.lang.Math#sin(double)
    515      */
    516     public static float sin2(float fValue) {
    517         fValue = reduceSinAngle(fValue); // limits angle to between -PI/2 and +PI/2
    518         if (Math.abs(fValue) <= Math.PI / 4) {
    519             return (float) Math.sin(fValue);
    520         }
    521 
    522         return (float) Math.cos(Math.PI / 2 - fValue);
    523     }
    524 
    525     /**
    526      * Returns cos of a value.
    527      *
    528      * @param fValue
    529      *            The value to cosine, in radians.
    530      * @return The cosine of fValue.
    531      * @see java.lang.Math#cos(double)
    532      */
    533     public static float cos2(float fValue) {
    534         return sin2(fValue + HALF_PI);
    535     }
    536 
    537     public static float cos(float v) {
    538         return (float) Math.cos(v);
    539     }
    540 
    541     public static float sin(float v) {
    542         return (float) Math.sin(v);
    543     }
    544 
    545     /**
    546      * Returns E^fValue
    547      * @param fValue Value to raise to a power.
    548      * @return The value E^fValue
    549      * @see java.lang.Math#exp(double)
    550      */
    551     public static float exp(float fValue) {
    552         return (float) Math.exp(fValue);
    553     }
    554 
    555     /**
    556      * Returns Absolute value of a float.
    557      * @param fValue The value to abs.
    558      * @return The abs of the value.
    559      * @see java.lang.Math#abs(float)
    560      */
    561     public static float abs(float fValue) {
    562         if (fValue < 0) {
    563             return -fValue;
    564         }
    565         return fValue;
    566     }
    567 
    568     /**
    569      * Returns a number rounded down.
    570      * @param fValue The value to round
    571      * @return The given number rounded down
    572      * @see java.lang.Math#floor(double)
    573      */
    574     public static float floor(float fValue) {
    575         return (float) Math.floor(fValue);
    576     }
    577 
    578     /**
    579      * Returns 1/sqrt(fValue)
    580      * @param fValue The value to process.
    581      * @return 1/sqrt(fValue)
    582      * @see java.lang.Math#sqrt(double)
    583      */
    584     public static float invSqrt(float fValue) {
    585         return (float) (1.0f / Math.sqrt(fValue));
    586     }
    587 
    588     public static float fastInvSqrt(float x) {
    589         float xhalf = 0.5f * x;
    590         int i = Float.floatToIntBits(x); // get bits for floating value
    591         i = 0x5f375a86 - (i >> 1); // gives initial guess y0
    592         x = Float.intBitsToFloat(i); // convert bits back to float
    593         x = x * (1.5f - xhalf * x * x); // Newton step, repeating increases accuracy
    594         return x;
    595     }
    596 
    597     /**
    598      * Returns the log base E of a value.
    599      * @param fValue The value to log.
    600      * @return The log of fValue base E
    601      * @see java.lang.Math#log(double)
    602      */
    603     public static float log(float fValue) {
    604         return (float) Math.log(fValue);
    605     }
    606 
    607     /**
    608      * Returns the logarithm of value with given base, calculated as log(value)/log(base),
    609      * so that pow(base, return)==value (contributed by vear)
    610      * @param value The value to log.
    611      * @param base Base of logarithm.
    612      * @return The logarithm of value with given base
    613      */
    614     public static float log(float value, float base) {
    615         return (float) (Math.log(value) / Math.log(base));
    616     }
    617 
    618     /**
    619      * Returns a number raised to an exponent power.  fBase^fExponent
    620      * @param fBase The base value (IE 2)
    621      * @param fExponent The exponent value (IE 3)
    622      * @return base raised to exponent (IE 8)
    623      * @see java.lang.Math#pow(double, double)
    624      */
    625     public static float pow(float fBase, float fExponent) {
    626         return (float) Math.pow(fBase, fExponent);
    627     }
    628 
    629     /**
    630      * Returns the value squared.  fValue ^ 2
    631      * @param fValue The vaule to square.
    632      * @return The square of the given value.
    633      */
    634     public static float sqr(float fValue) {
    635         return fValue * fValue;
    636     }
    637 
    638     /**
    639      * Returns the square root of a given value.
    640      * @param fValue The value to sqrt.
    641      * @return The square root of the given value.
    642      * @see java.lang.Math#sqrt(double)
    643      */
    644     public static float sqrt(float fValue) {
    645         return (float) Math.sqrt(fValue);
    646     }
    647 
    648     /**
    649      * Returns the tangent of a value.  If USE_FAST_TRIG is enabled, an approximate value
    650      * is returned.  Otherwise, a direct value is used.
    651      * @param fValue The value to tangent, in radians.
    652      * @return The tangent of fValue.
    653      * @see java.lang.Math#tan(double)
    654      */
    655     public static float tan(float fValue) {
    656         return (float) Math.tan(fValue);
    657     }
    658 
    659     /**
    660      * Returns 1 if the number is positive, -1 if the number is negative, and 0 otherwise
    661      * @param iValue The integer to examine.
    662      * @return The integer's sign.
    663      */
    664     public static int sign(int iValue) {
    665         if (iValue > 0) {
    666             return 1;
    667         }
    668         if (iValue < 0) {
    669             return -1;
    670         }
    671         return 0;
    672     }
    673 
    674     /**
    675      * Returns 1 if the number is positive, -1 if the number is negative, and 0 otherwise
    676      * @param fValue The float to examine.
    677      * @return The float's sign.
    678      */
    679     public static float sign(float fValue) {
    680         return Math.signum(fValue);
    681     }
    682 
    683     /**
    684      * Given 3 points in a 2d plane, this function computes if the points going from A-B-C
    685      * are moving counter clock wise.
    686      * @param p0 Point 0.
    687      * @param p1 Point 1.
    688      * @param p2 Point 2.
    689      * @return 1 If they are CCW, -1 if they are not CCW, 0 if p2 is between p0 and p1.
    690      */
    691     public static int counterClockwise(Vector2f p0, Vector2f p1, Vector2f p2) {
    692         float dx1, dx2, dy1, dy2;
    693         dx1 = p1.x - p0.x;
    694         dy1 = p1.y - p0.y;
    695         dx2 = p2.x - p0.x;
    696         dy2 = p2.y - p0.y;
    697         if (dx1 * dy2 > dy1 * dx2) {
    698             return 1;
    699         }
    700         if (dx1 * dy2 < dy1 * dx2) {
    701             return -1;
    702         }
    703         if ((dx1 * dx2 < 0) || (dy1 * dy2 < 0)) {
    704             return -1;
    705         }
    706         if ((dx1 * dx1 + dy1 * dy1) < (dx2 * dx2 + dy2 * dy2)) {
    707             return 1;
    708         }
    709         return 0;
    710     }
    711 
    712     /**
    713      * Test if a point is inside a triangle.  1 if the point is on the ccw side,
    714      * -1 if the point is on the cw side, and 0 if it is on neither.
    715      * @param t0 First point of the triangle.
    716      * @param t1 Second point of the triangle.
    717      * @param t2 Third point of the triangle.
    718      * @param p The point to test.
    719      * @return Value 1 or -1 if inside triangle, 0 otherwise.
    720      */
    721     public static int pointInsideTriangle(Vector2f t0, Vector2f t1, Vector2f t2, Vector2f p) {
    722         int val1 = counterClockwise(t0, t1, p);
    723         if (val1 == 0) {
    724             return 1;
    725         }
    726         int val2 = counterClockwise(t1, t2, p);
    727         if (val2 == 0) {
    728             return 1;
    729         }
    730         if (val2 != val1) {
    731             return 0;
    732         }
    733         int val3 = counterClockwise(t2, t0, p);
    734         if (val3 == 0) {
    735             return 1;
    736         }
    737         if (val3 != val1) {
    738             return 0;
    739         }
    740         return val3;
    741     }
    742 
    743     /**
    744      * A method that computes normal for a triangle defined by three vertices.
    745      * @param v1 first vertex
    746      * @param v2 second vertex
    747      * @param v3 third vertex
    748      * @return a normal for the face
    749      */
    750     public static Vector3f computeNormal(Vector3f v1, Vector3f v2, Vector3f v3) {
    751         Vector3f a1 = v1.subtract(v2);
    752         Vector3f a2 = v3.subtract(v2);
    753         return a2.crossLocal(a1).normalizeLocal();
    754     }
    755 
    756     /**
    757      * Returns the determinant of a 4x4 matrix.
    758      */
    759     public static float determinant(double m00, double m01, double m02,
    760             double m03, double m10, double m11, double m12, double m13,
    761             double m20, double m21, double m22, double m23, double m30,
    762             double m31, double m32, double m33) {
    763 
    764         double det01 = m20 * m31 - m21 * m30;
    765         double det02 = m20 * m32 - m22 * m30;
    766         double det03 = m20 * m33 - m23 * m30;
    767         double det12 = m21 * m32 - m22 * m31;
    768         double det13 = m21 * m33 - m23 * m31;
    769         double det23 = m22 * m33 - m23 * m32;
    770         return (float) (m00 * (m11 * det23 - m12 * det13 + m13 * det12) - m01
    771                 * (m10 * det23 - m12 * det03 + m13 * det02) + m02
    772                 * (m10 * det13 - m11 * det03 + m13 * det01) - m03
    773                 * (m10 * det12 - m11 * det02 + m12 * det01));
    774     }
    775 
    776     /**
    777      * Returns a random float between 0 and 1.
    778      *
    779      * @return A random float between <tt>0.0f</tt> (inclusive) to
    780      *         <tt>1.0f</tt> (exclusive).
    781      */
    782     public static float nextRandomFloat() {
    783         return rand.nextFloat();
    784     }
    785 
    786     /**
    787      * Returns a random float between min and max.
    788      *
    789      * @return A random int between <tt>min</tt> (inclusive) to
    790      *         <tt>max</tt> (inclusive).
    791      */
    792     public static int nextRandomInt(int min, int max) {
    793         return (int) (nextRandomFloat() * (max - min + 1)) + min;
    794     }
    795 
    796     public static int nextRandomInt() {
    797         return rand.nextInt();
    798     }
    799 
    800     /**
    801      * Converts a point from Spherical coordinates to Cartesian (using positive
    802      * Y as up) and stores the results in the store var.
    803      */
    804     public static Vector3f sphericalToCartesian(Vector3f sphereCoords,
    805             Vector3f store) {
    806         store.y = sphereCoords.x * FastMath.sin(sphereCoords.z);
    807         float a = sphereCoords.x * FastMath.cos(sphereCoords.z);
    808         store.x = a * FastMath.cos(sphereCoords.y);
    809         store.z = a * FastMath.sin(sphereCoords.y);
    810 
    811         return store;
    812     }
    813 
    814     /**
    815      * Converts a point from Cartesian coordinates (using positive Y as up) to
    816      * Spherical and stores the results in the store var. (Radius, Azimuth,
    817      * Polar)
    818      */
    819     public static Vector3f cartesianToSpherical(Vector3f cartCoords,
    820             Vector3f store) {
    821         float x = cartCoords.x;
    822         if (x == 0) {
    823             x = FastMath.FLT_EPSILON;
    824         }
    825         store.x = FastMath.sqrt((x * x)
    826                 + (cartCoords.y * cartCoords.y)
    827                 + (cartCoords.z * cartCoords.z));
    828         store.y = FastMath.atan(cartCoords.z / x);
    829         if (x < 0) {
    830             store.y += FastMath.PI;
    831         }
    832         store.z = FastMath.asin(cartCoords.y / store.x);
    833         return store;
    834     }
    835 
    836     /**
    837      * Converts a point from Spherical coordinates to Cartesian (using positive
    838      * Z as up) and stores the results in the store var.
    839      */
    840     public static Vector3f sphericalToCartesianZ(Vector3f sphereCoords,
    841             Vector3f store) {
    842         store.z = sphereCoords.x * FastMath.sin(sphereCoords.z);
    843         float a = sphereCoords.x * FastMath.cos(sphereCoords.z);
    844         store.x = a * FastMath.cos(sphereCoords.y);
    845         store.y = a * FastMath.sin(sphereCoords.y);
    846 
    847         return store;
    848     }
    849 
    850     /**
    851      * Converts a point from Cartesian coordinates (using positive Z as up) to
    852      * Spherical and stores the results in the store var. (Radius, Azimuth,
    853      * Polar)
    854      */
    855     public static Vector3f cartesianZToSpherical(Vector3f cartCoords,
    856             Vector3f store) {
    857         float x = cartCoords.x;
    858         if (x == 0) {
    859             x = FastMath.FLT_EPSILON;
    860         }
    861         store.x = FastMath.sqrt((x * x)
    862                 + (cartCoords.y * cartCoords.y)
    863                 + (cartCoords.z * cartCoords.z));
    864         store.z = FastMath.atan(cartCoords.z / x);
    865         if (x < 0) {
    866             store.z += FastMath.PI;
    867         }
    868         store.y = FastMath.asin(cartCoords.y / store.x);
    869         return store;
    870     }
    871 
    872     /**
    873      * Takes an value and expresses it in terms of min to max.
    874      *
    875      * @param val -
    876      *            the angle to normalize (in radians)
    877      * @return the normalized angle (also in radians)
    878      */
    879     public static float normalize(float val, float min, float max) {
    880         if (Float.isInfinite(val) || Float.isNaN(val)) {
    881             return 0f;
    882         }
    883         float range = max - min;
    884         while (val > max) {
    885             val -= range;
    886         }
    887         while (val < min) {
    888             val += range;
    889         }
    890         return val;
    891     }
    892 
    893     /**
    894      * @param x
    895      *            the value whose sign is to be adjusted.
    896      * @param y
    897      *            the value whose sign is to be used.
    898      * @return x with its sign changed to match the sign of y.
    899      */
    900     public static float copysign(float x, float y) {
    901         if (y >= 0 && x <= -0) {
    902             return -x;
    903         } else if (y < 0 && x >= 0) {
    904             return -x;
    905         } else {
    906             return x;
    907         }
    908     }
    909 
    910     /**
    911      * Take a float input and clamp it between min and max.
    912      *
    913      * @param input
    914      * @param min
    915      * @param max
    916      * @return clamped input
    917      */
    918     public static float clamp(float input, float min, float max) {
    919         return (input < min) ? min : (input > max) ? max : input;
    920     }
    921 
    922     /**
    923      * Clamps the given float to be between 0 and 1.
    924      *
    925      * @param input
    926      * @return input clamped between 0 and 1.
    927      */
    928     public static float saturate(float input) {
    929         return clamp(input, 0f, 1f);
    930     }
    931 
    932     /**
    933      * Converts a single precision (32 bit) floating point value
    934      * into half precision (16 bit).
    935      *
    936      * <p>Source: <a href="http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf">
    937      * http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf</a><br><strong>broken link</strong>
    938      *
    939      * @param half The half floating point value as a short.
    940      * @return floating point value of the half.
    941      */
    942     public static float convertHalfToFloat(short half) {
    943         switch ((int) half) {
    944             case 0x0000:
    945                 return 0f;
    946             case 0x8000:
    947                 return -0f;
    948             case 0x7c00:
    949                 return Float.POSITIVE_INFINITY;
    950             case 0xfc00:
    951                 return Float.NEGATIVE_INFINITY;
    952             // TODO: Support for NaN?
    953             default:
    954                 return Float.intBitsToFloat(((half & 0x8000) << 16)
    955                         | (((half & 0x7c00) + 0x1C000) << 13)
    956                         | ((half & 0x03FF) << 13));
    957         }
    958     }
    959 
    960     public static short convertFloatToHalf(float flt) {
    961         if (Float.isNaN(flt)) {
    962             throw new UnsupportedOperationException("NaN to half conversion not supported!");
    963         } else if (flt == Float.POSITIVE_INFINITY) {
    964             return (short) 0x7c00;
    965         } else if (flt == Float.NEGATIVE_INFINITY) {
    966             return (short) 0xfc00;
    967         } else if (flt == 0f) {
    968             return (short) 0x0000;
    969         } else if (flt == -0f) {
    970             return (short) 0x8000;
    971         } else if (flt > 65504f) {
    972             // max value supported by half float
    973             return 0x7bff;
    974         } else if (flt < -65504f) {
    975             return (short) (0x7bff | 0x8000);
    976         } else if (flt > 0f && flt < 5.96046E-8f) {
    977             return 0x0001;
    978         } else if (flt < 0f && flt > -5.96046E-8f) {
    979             return (short) 0x8001;
    980         }
    981 
    982         int f = Float.floatToIntBits(flt);
    983         return (short) (((f >> 16) & 0x8000)
    984                 | ((((f & 0x7f800000) - 0x38000000) >> 13) & 0x7c00)
    985                 | ((f >> 13) & 0x03ff));
    986     }
    987 }
    988