Home | History | Annotate | Download | only in common
      1 /*******************************************************************************
      2  * Copyright (c) 2013, Daniel Murphy
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without modification,
      6  * are permitted provided that the following conditions are met:
      7  * 	* Redistributions of source code must retain the above copyright notice,
      8  * 	  this list of conditions and the following disclaimer.
      9  * 	* Redistributions in binary form must reproduce the above copyright notice,
     10  * 	  this list of conditions and the following disclaimer in the documentation
     11  * 	  and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
     14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     16  * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
     17  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     18  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     19  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     20  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     21  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     22  * POSSIBILITY OF SUCH DAMAGE.
     23  ******************************************************************************/
     24 /*
     25  * JBox2D - A Java Port of Erin Catto's Box2D
     26  *
     27  * JBox2D homepage: http://jbox2d.sourceforge.net/
     28  * Box2D homepage: http://www.box2d.org
     29  *
     30  * This software is provided 'as-is', without any express or implied
     31  * warranty.  In no event will the authors be held liable for any damages
     32  * arising from the use of this software.
     33  *
     34  * Permission is granted to anyone to use this software for any purpose,
     35  * including commercial applications, and to alter it and redistribute it
     36  * freely, subject to the following restrictions:
     37  *
     38  * 1. The origin of this software must not be misrepresented; you must not
     39  * claim that you wrote the original software. If you use this software
     40  * in a product, an acknowledgment in the product documentation would be
     41  * appreciated but is not required.
     42  * 2. Altered source versions must be plainly marked as such, and must not be
     43  * misrepresented as being the original software.
     44  * 3. This notice may not be removed or altered from any source distribution.
     45  */
     46 
     47 package org.jbox2d.common;
     48 
     49 import java.util.Random;
     50 
     51 /**
     52  * A few math methods that don't fit very well anywhere else.
     53  */
     54 public class MathUtils extends PlatformMathUtils {
     55   public static final float PI = (float) Math.PI;
     56   public static final float TWOPI = (float) (Math.PI * 2);
     57   public static final float INV_PI = 1f / PI;
     58   public static final float HALF_PI = PI / 2;
     59   public static final float QUARTER_PI = PI / 4;
     60   public static final float THREE_HALVES_PI = TWOPI - HALF_PI;
     61 
     62   /**
     63    * Degrees to radians conversion factor
     64    */
     65   public static final float DEG2RAD = PI / 180;
     66 
     67   /**
     68    * Radians to degrees conversion factor
     69    */
     70   public static final float RAD2DEG = 180 / PI;
     71 
     72   public static final float[] sinLUT = new float[Settings.SINCOS_LUT_LENGTH];
     73 
     74   static {
     75     for (int i = 0; i < Settings.SINCOS_LUT_LENGTH; i++) {
     76       sinLUT[i] = (float) Math.sin(i * Settings.SINCOS_LUT_PRECISION);
     77     }
     78   }
     79 
     80   public static final float sin(float x) {
     81     if (Settings.SINCOS_LUT_ENABLED) {
     82       return sinLUT(x);
     83     } else {
     84       return (float) StrictMath.sin(x);
     85     }
     86   }
     87 
     88   public static final float sinLUT(float x) {
     89     x %= TWOPI;
     90 
     91     if (x < 0) {
     92       x += TWOPI;
     93     }
     94 
     95     if (Settings.SINCOS_LUT_LERP) {
     96 
     97       x /= Settings.SINCOS_LUT_PRECISION;
     98 
     99       final int index = (int) x;
    100 
    101       if (index != 0) {
    102         x %= index;
    103       }
    104 
    105       // the next index is 0
    106       if (index == Settings.SINCOS_LUT_LENGTH - 1) {
    107         return ((1 - x) * sinLUT[index] + x * sinLUT[0]);
    108       } else {
    109         return ((1 - x) * sinLUT[index] + x * sinLUT[index + 1]);
    110       }
    111 
    112     } else {
    113       return sinLUT[MathUtils.round(x / Settings.SINCOS_LUT_PRECISION) % Settings.SINCOS_LUT_LENGTH];
    114     }
    115   }
    116 
    117   public static final float cos(float x) {
    118     if (Settings.SINCOS_LUT_ENABLED) {
    119       return sinLUT(HALF_PI - x);
    120     } else {
    121       return (float) StrictMath.cos(x);
    122     }
    123   }
    124 
    125   public static final float abs(final float x) {
    126     if (Settings.FAST_ABS) {
    127       return x > 0 ? x : -x;
    128     } else {
    129       return StrictMath.abs(x);
    130     }
    131   }
    132 
    133   public static final float fastAbs(final float x) {
    134     return x > 0 ? x : -x;
    135   }
    136 
    137   public static final int abs(int x) {
    138     int y = x >> 31;
    139     return (x ^ y) - y;
    140   }
    141 
    142   public static final int floor(final float x) {
    143     if (Settings.FAST_FLOOR) {
    144       return fastFloor(x);
    145     } else {
    146       return (int) StrictMath.floor(x);
    147     }
    148   }
    149 
    150   public static final int fastFloor(final float x) {
    151     int y = (int) x;
    152     if (x < y) {
    153       return y - 1;
    154     }
    155     return y;
    156   }
    157 
    158   public static final int ceil(final float x) {
    159     if (Settings.FAST_CEIL) {
    160       return fastCeil(x);
    161     } else {
    162       return (int) StrictMath.ceil(x);
    163     }
    164   }
    165 
    166   public static final int fastCeil(final float x) {
    167     int y = (int) x;
    168     if (x > y) {
    169       return y + 1;
    170     }
    171     return y;
    172   }
    173 
    174   public static final int round(final float x) {
    175     if (Settings.FAST_ROUND) {
    176       return floor(x + .5f);
    177     } else {
    178       return StrictMath.round(x);
    179     }
    180   }
    181 
    182   /**
    183    * Rounds up the value to the nearest higher power^2 value.
    184    *
    185    * @param x
    186    * @return power^2 value
    187    */
    188   public static final int ceilPowerOf2(int x) {
    189     int pow2 = 1;
    190     while (pow2 < x) {
    191       pow2 <<= 1;
    192     }
    193     return pow2;
    194   }
    195 
    196   public final static float max(final float a, final float b) {
    197     return a > b ? a : b;
    198   }
    199 
    200   public final static int max(final int a, final int b) {
    201     return a > b ? a : b;
    202   }
    203 
    204   public final static float min(final float a, final float b) {
    205     return a < b ? a : b;
    206   }
    207 
    208   public final static int min(final int a, final int b) {
    209     return a < b ? a : b;
    210   }
    211 
    212   public final static float map(final float val, final float fromMin, final float fromMax,
    213       final float toMin, final float toMax) {
    214     final float mult = (val - fromMin) / (fromMax - fromMin);
    215     final float res = toMin + mult * (toMax - toMin);
    216     return res;
    217   }
    218 
    219   /** Returns the closest value to 'a' that is in between 'low' and 'high' */
    220   public final static float clamp(final float a, final float low, final float high) {
    221     return max(low, min(a, high));
    222   }
    223 
    224   public final static Vec2 clamp(final Vec2 a, final Vec2 low, final Vec2 high) {
    225     final Vec2 min = new Vec2();
    226     min.x = a.x < high.x ? a.x : high.x;
    227     min.y = a.y < high.y ? a.y : high.y;
    228     min.x = low.x > min.x ? low.x : min.x;
    229     min.y = low.y > min.y ? low.y : min.y;
    230     return min;
    231   }
    232 
    233   public final static void clampToOut(final Vec2 a, final Vec2 low, final Vec2 high, final Vec2 dest) {
    234     dest.x = a.x < high.x ? a.x : high.x;
    235     dest.y = a.y < high.y ? a.y : high.y;
    236     dest.x = low.x > dest.x ? low.x : dest.x;
    237     dest.y = low.y > dest.y ? low.y : dest.y;
    238   }
    239 
    240   /**
    241    * Next Largest Power of 2: Given a binary integer value x, the next largest power of 2 can be
    242    * computed by a SWAR algorithm that recursively "folds" the upper bits into the lower bits. This
    243    * process yields a bit vector with the same most significant 1 as x, but all 1's below it. Adding
    244    * 1 to that value yields the next largest power of 2.
    245    */
    246   public final static int nextPowerOfTwo(int x) {
    247     x |= x >> 1;
    248     x |= x >> 2;
    249     x |= x >> 4;
    250     x |= x >> 8;
    251     x |= x >> 16;
    252     return x + 1;
    253   }
    254 
    255   public final static boolean isPowerOfTwo(final int x) {
    256     return x > 0 && (x & x - 1) == 0;
    257   }
    258 
    259   public static final float pow(float a, float b) {
    260     if (Settings.FAST_POW) {
    261       return fastPow(a, b);
    262     } else {
    263       return (float) StrictMath.pow(a, b);
    264     }
    265   }
    266 
    267   public static final float atan2(final float y, final float x) {
    268     if (Settings.FAST_ATAN2) {
    269       return fastAtan2(y, x);
    270     } else {
    271       return (float) StrictMath.atan2(y, x);
    272     }
    273   }
    274 
    275   public static final float fastAtan2(float y, float x) {
    276     if (x == 0.0f) {
    277       if (y > 0.0f) return HALF_PI;
    278       if (y == 0.0f) return 0.0f;
    279       return -HALF_PI;
    280     }
    281     float atan;
    282     final float z = y / x;
    283     if (abs(z) < 1.0f) {
    284       atan = z / (1.0f + 0.28f * z * z);
    285       if (x < 0.0f) {
    286         if (y < 0.0f) return atan - PI;
    287         return atan + PI;
    288       }
    289     } else {
    290       atan = HALF_PI - z / (z * z + 0.28f);
    291       if (y < 0.0f) return atan - PI;
    292     }
    293     return atan;
    294   }
    295 
    296   public static final float reduceAngle(float theta) {
    297     theta %= TWOPI;
    298     if (abs(theta) > PI) {
    299       theta = theta - TWOPI;
    300     }
    301     if (abs(theta) > HALF_PI) {
    302       theta = PI - theta;
    303     }
    304     return theta;
    305   }
    306 
    307   public static final float randomFloat(float argLow, float argHigh) {
    308     return (float) Math.random() * (argHigh - argLow) + argLow;
    309   }
    310 
    311   public static final float randomFloat(Random r, float argLow, float argHigh) {
    312     return r.nextFloat() * (argHigh - argLow) + argLow;
    313   }
    314 
    315   public static final float sqrt(float x) {
    316     return (float) StrictMath.sqrt(x);
    317   }
    318 
    319   public final static float distanceSquared(Vec2 v1, Vec2 v2) {
    320     float dx = (v1.x - v2.x);
    321     float dy = (v1.y - v2.y);
    322     return dx * dx + dy * dy;
    323   }
    324 
    325   public final static float distance(Vec2 v1, Vec2 v2) {
    326     return sqrt(distanceSquared(v1, v2));
    327   }
    328 }