MathUtil.h

00001 // ----------------------------------------------------------------------------
00002 //
00003 // tagGame - Example code from the book:
00004 //
00005 //           Artficial Intelligence for Computer Games: An Introduction
00006 //           by John David Funge
00007 //
00008 //           www.ai4games.org
00009 //
00010 // Source code distributed under the Copyright (c) 2003-2007, John David Funge
00011 // Original author: John David Funge (www.jfunge.com)
00012 //
00013 // Licensed under the Academic Free License version 3.0 
00014 // (for details see LICENSE.txt in this directory).
00015 //
00016 // ----------------------------------------------------------------------------
00017 
00018 #ifndef TG_MATH_H
00019 #define TG_MATH_H
00020 
00021 #include "Util.h"
00022 
00023 #include <cmath>
00024 
00025 // Not defined on all supported architectures.
00026 #ifndef M_PI
00027 #   define M_PI         3.14159265358979323846
00028 #endif
00029 #ifndef M_PI_2
00030 #   define M_PI_2       1.57079632679489661923
00031 #endif
00032 
00033 namespace tagGame
00034 {
00035    // Re-define this to float if you don't need doubles.
00036    typedef double Real;
00037 
00038    Real const Inf = HUGE_VAL;
00039 
00041    class MathUtil
00042    {
00043    public:
00044 
00046       inline static bool isAlmostEq(Real const x, Real const y);
00047 
00049       inline static bool isAlmostZero(Real const x);
00050 
00052       inline static int round(Real const x);
00053 
00055       inline static int sgn(Real const x);
00056 
00058       inline static Real radToDeg(Real const t);
00059 
00061       inline static Real degToRad(Real const t);
00062 
00064       inline static Real clamp(Real const x, Real lower, Real upper);
00065 
00069       inline static Real angleClamp(Real const t);
00070 
00072       inline static Real uniform01();
00073 
00075       inline static int uniform(int n);
00076 
00079       inline static Real normal(Real const mean = Real(0), Real const std = Real(1));
00080 
00085       inline static Real normalAngle(Real const mean = Real(0), Real const std = Real(70));
00086 
00087    protected:
00088    private:
00089    };
00090 
00091    // TODO: make this relative
00092    bool MathUtil::isAlmostEq(Real const x, Real const y)
00093    {
00094       Real const eps = 0.00001;
00095    
00096       return (fabs(x - y) <= eps) || (x == Inf && y == Inf);
00097    }
00098    
00099    bool MathUtil::isAlmostZero(Real const x)
00100    {
00101       return isAlmostEq(x, Real(0));
00102    }
00103    
00104    int MathUtil::round(Real const x)
00105    {
00106       return int(x + 0.5);
00107    }
00108    
00109    int MathUtil::sgn(Real const x)
00110    {
00111       return x < 0 ? -1 : 1;
00112    }
00113    
00114    Real MathUtil::radToDeg(Real const x)
00115    {
00116       return x * Real(180) / M_PI;
00117    }
00118    
00119    Real MathUtil::degToRad(Real const x)
00120    {
00121       return x * M_PI / Real(180);
00122    }
00123    
00124    Real MathUtil::uniform01()
00125    {
00126       // TODO: use a better random number generator.
00127       return Real(rand())/Real(RAND_MAX);
00128    }
00129    
00130    int MathUtil::uniform(int n)
00131    {
00132       TG_ASSERT_MSG(n <= RAND_MAX, "n: " + Util::itos(n) + " must be <= RAND_MAX: " + Util::itos(RAND_MAX));
00133       // TODO: use a better random number generator.
00134       return rand() % n;
00135    }
00136    
00137    Real MathUtil::clamp(Real x, Real lower, Real upper)
00138    {
00139       TG_ASSERT(lower <= upper);
00140    
00141       return x < lower ? lower : (upper < x ? upper : x);
00142    }
00143    
00144    Real MathUtil::angleClamp(Real const t)
00145    {
00146       // The test for exact equality with -360 is a small technicality.  If it weren't
00147       // there, then all angles would be clamped into the open range (-180,180), instead
00148       // of the desired half-open range [-180, 180).
00149       Real const x(t == Real(-360) ? t : Real(sgn(t)) * fmod(fabs(t), Real(360)));
00150       TG_ASSERT(Real(-360) <= x && x < Real(360));
00151       return x < Real(-180) ? x + Real(360) : (x >= Real(180) ? x - Real(360) : x);
00152    }
00153    
00154    Real MathUtil::normalAngle(Real const mean, Real const std)
00155    {
00156       return angleClamp(normal(mean, std));
00157    }
00158 
00159    // draw number from a normal random distribution
00160    Real MathUtil::normal(Real const mean, Real const std)
00161    {
00162       // For an explanation of the theory behind this code see:
00163       // Eric W. Weisstein. "Box-Muller Transformation." From MathWorld--A Wolfram Web Resource.
00164       // http://mathworld.wolfram.com/Box-MullerTransformation.html
00165 
00166       static bool validCache(false);
00167       static Real rho(0);
00168       static Real r1(0);
00169       // Real const pi(3.14159265358979323846);
00170 
00171       if (!validCache)
00172       {
00173          Real const r0(uniform01());
00174          r1 = uniform01();
00175          rho = sqrt(-Real(2) * log(Real(1) - r0));
00176          validCache = true;
00177 
00178          return rho * cos(Real(2) * M_PI * r1) * std + mean;
00179       }
00180       else
00181       {
00182          validCache = false;
00183       }
00184       return rho * sin(Real(2) * M_PI * r1) * std + mean;
00185    }
00186 }
00187 
00188 #endif

Generated on Sat Mar 31 22:30:54 2007 for tagGame by  doxygen 1.5.1