gfx_math.hh

Go to the documentation of this file.
00001 /*
00014  * LEGAL:   COPYRIGHT (C) 2004 JIM E. BROOKS
00015  *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
00016  *          OF THE GNU GENERAL PUBLIC LICENSE VERSION 2 (GPL 2).
00017  *****************************************************************************/
00018 
00019 #ifndef GFX_MATH_HH
00020 #define GFX_MATH_HH 1
00021 
00022 namespace gfx {
00023 
00027 
00028 // A NaN never equals anything -- not even another NaN.
00029 // C99 isfinite() is true if neither NaN nor infinity.
00030 //#define IFNAN(N) (!((N)==(N))) // (compiler might optimize this incorrectly)
00031 #if __GNUC__  &&  defined(__USE_ISOC99)
00032 #define IF_NAN(N) (UX(!isfinite(N)))
00033 #else
00034 // Tested on gcc 3.4.3 x86.
00035 //template<typename FP> bool IFNAN( volatile FP& n ) { return !(n==n); }
00036 INLINE bool IF_NAN( volatile fp n ) { return !(n==n); }
00037 #endif
00038 
00042 
00043 // fpx is used in trig functions since they're used in matrix functions
00044 // which need to maintain precision.
00045 
00046 // 180' = PI
00047 // 360' = PI * 2
00048 const fpx PI    = 3.14159265358979323846L;   // L for long double
00049 const fpx PI2   = 6.28318530717958647692L;   // pi * 2.0
00050 const fpx PI_90 = 1.57079632679489661926L;   // pi / 2.0 [equivalent to 90']
00051 
00052 // Turn a float type into a distinct type
00053 // to ensure a degree/radian aren't confused.
00054 #if SPEED
00057 DECLARE_DISTINCT_TYPE( Radian, fp )
00060 DECLARE_DISTINCT_TYPE( Degree, fp )
00061 #else
00062 DECLARE_DISTINCT_TYPE( Radian, fpx )
00063 DECLARE_DISTINCT_TYPE( Degree, fpx )
00064 #endif
00065 
00066 const Radian RADIAN_180 = gfx::PI;   // 180' in radians (half circle)
00067 const Radian RADIAN_360 = gfx::PI2;  // 360' in radians (full circle)
00068 
00069 // Compare degrees/radians while ignoring sign.
00070 #define IF_DEG_GT( DEG1, DEG2 ) (ABS(DEG1) > ABS(DEG2))
00071 #define IF_DEG_LT( DEG1, DEG2 ) (ABS(DEG1) < ABS(DEG2))
00072 #define IF_RAD_GT( RAD1, RAD2 ) (ABS(RAD1) > ABS(RAD2))
00073 #define IF_RAD_LT( RAD1, RAD2 ) (ABS(RAD1) < ABS(RAD2))
00074 
00082 template<typename FP>
00083 pair<FP,FP>
00084 SinCos( const Radian rad )
00085 {
00086 #if defined(__GNUC__) && defined(CPU_X86)
00087     pair<FP,FP> si_co;
00088     asm("fsincos" : "=t" (si_co.second), "=u" (si_co.first) : "0" (rad));
00089     return si_co;
00090 #elif defined(__GNUC__) && _GLIBCXX_HAVE_SINCOS
00091     pair<double,double> si_co;  // must be specific in this case
00092     sincos( rad, &si_co.first, &si_co.second );  // GNU extension
00093     return make_pair<FP,FP>( si_co.first, si_co.second );
00094 #else
00095     pair<FP,FP> si_co;
00096     si_co.first  = sin( rad );
00097     si_co.second = cos( rad );
00098     return si_co;
00099 #endif
00100 }
00101 
00105 INLINE Degree
00106 TruncateDeg( Degree deg )
00107 {
00108     if ( EX(deg < 360.0) )
00109         return deg;
00110     else
00111         return deg - 360.0;
00112 }
00113 
00118 INTERN const fpx degRadRatio = (1.0 / 360.0) * (gfx::PI2);
00119 #define DEG2RAD( DEG ) ((DEG) * (degRadRatio))
00120 
00121 INLINE Radian
00122 Deg2Rad( Degree deg )
00123 {
00124     return DEG2RAD( deg );
00125     //return deg / 360.0 * (2.0 * gfx::PI); // x87 FDIV is slower than FMUL
00126 }
00127 
00132 INTERN const fpx radDegRatio = (1.0 / gfx::PI2) * 360.0;
00133 #define RAD2DEG( RAD ) ((RAD) * (radDegRatio))
00134 
00135 INLINE Degree
00136 Rad2Deg( Radian rad )
00137 {
00138     return RAD2DEG( rad );
00139     //return rad / (2.0 * gfx::PI) * 360.0; // x87 FDIV is slower than FMUL
00140 }
00141 
00145 INLINE fpx
00146 Sin( Degree deg )
00147 {
00148     return sin( Deg2Rad( deg ) );
00149 }
00150 
00154 INLINE fpx
00155 Cos( Degree deg )
00156 {
00157     return cos( Deg2Rad( deg ) );
00158 }
00159 
00163 
00164 } // namespace gfx
00165 
00166 #include "gfx_math_matrix.hh"
00167 
00168 namespace gfx {
00169 
00173 
00177 INLINE fp
00178 Distance( const Vector2& v )
00179 {
00180     return sqrtf( v.x * v.x
00181                 + v.y * v.y );
00182 }
00183 
00184 INLINE fp
00185 Distance( const Vector3& v )
00186 {
00187     return sqrtf( v.x * v.x
00188                 + v.y * v.y
00189                 + v.z * v.z );
00190 }
00191 
00195 template<typename VECTOR3A,typename VECTOR3B>
00196 fp
00197 Distance( const VECTOR3A& v1, const VECTOR3B& v2 )
00198 {
00199     const fp dx = v2.x - v1.x;
00200     const fp dy = v2.y - v1.y;
00201     const fp dz = v2.z - v1.z;
00202     return sqrtf( dx * dx
00203                 + dy * dy
00204                 + dz * dz );
00205 }
00206 
00213 INLINE fpx
00214 DistanceSquared( const Vector3& v1, const Vector3& v2 )
00215 {
00216     fpx xd = v2.x - v1.x;  // extra precision
00217     fpx yd = v2.y - v1.y;
00218     fpx zd = v2.z - v1.z;
00219     return xd*xd + yd*yd + zd*zd;
00220 }
00221 
00222 // Distance^2 between two matrixs.
00223 // Don't pass different kinds of matrixs (eg Eye origin is negative but Dyna is positive).
00224 template<typename MATRIX1, typename MATRIX2>
00225 fpx
00226 DistanceSquaredMatrix( const MATRIX1& m1, const MATRIX2& m2 )
00227 {
00228     Vector3 v1( m1[Ox], m1[Oy], m1[Oz] );
00229     Vector3 v2( m2[Ox], m2[Oy], m2[Oz] );
00230     return DistanceSquared( v1, v2 );
00231 }
00232 
00237 INLINE Vector3
00238 Normalize( const Vector3& v )
00239 {
00240     fp dist = Distance( v );
00241     return Vector3( v.x / dist,
00242                     v.y / dist,
00243                     v.z / dist );
00244 }
00245 
00250 INLINE fp
00251 NormalizeCoord( uint axis, const Vector3& v )
00252 {
00253     fp dist = Distance( v );
00254          if ( axis == XX ) return v.x / dist;
00255     else if ( axis == YY ) return v.y / dist;
00256     else                   return v.z / dist;
00257 }
00258 
00264 INLINE Vector3
00265 CrossProduct( const Vector3& v0, // origin of v1 and v2
00266               const Vector3& v1,
00267               const Vector3& v2 )
00268 {
00269     const fp xd1 = v1.x - v0.x;
00270     const fp yd1 = v1.y - v0.y;
00271     const fp zd1 = v1.z - v0.z;
00272     const fp xd2 = v2.x - v0.x;
00273     const fp yd2 = v2.y - v0.y;
00274     const fp zd2 = v2.z - v0.z;
00275     return Vector3( yd1 * zd2 - yd2 * zd1,    // x: y*z
00276                     zd1 * xd2 - zd2 * xd1,    // y: z*x
00277                     xd1 * yd2 - xd2 * yd1 );  // z: x*y
00278 }
00279 
00285 INLINE fp
00286 DotProduct2( const Vector2& v1, const Vector2& v2 )
00287 {
00288     return v1.x * v2.x
00289          + v1.y * v2.y;
00290 }
00291 
00292 template<typename VECTOR3A,typename VECTOR3B>
00293 fp
00294 DotProduct3( const VECTOR3A& v1, const VECTOR3B& v2 )
00295 {
00296     return v1.x * v2.x
00297          + v1.y * v2.y
00298          + v1.z * v2.z;
00299 }
00300 
00301 // Extended-precision.
00302 template<typename VECTOR3A,typename VECTOR3B>
00303 fpx
00304 DotProduct3_fpx( const VECTOR3A& v1, const VECTOR3B& v2 )
00305 {
00306     return fpx(v1.x) * fpx(v2.x)
00307          + fpx(v1.y) * fpx(v2.y)
00308          + fpx(v1.z) * fpx(v2.z);
00309 }
00310 
00314 INLINE Radian
00315 Angle2( const Vector2& u, const Vector2& v )  // Angle2/3() differ in DotProduct2/3()
00316 {
00317     // Dot product formula indirectly provides the angle.
00318     // angle = arccos( DotProduct(u,v) / Distance(u) * Distance(v) )
00319     fp uv = Distance(u) * Distance(v);
00320     if ( ABS(uv) < 0.1 ) return 0.0;  // prevent NaN and div by 0
00321     fp theta = DotProduct2(u,v) / uv;
00322     theta = Clamp( theta, -1.0, 1.0 ); // acos() won't tolerate 1.00000001
00323 
00324     fp rad = acos( theta );
00325 ASSERT(errno == 0);  // if acos() failed
00326     return rad;
00327 }
00328 
00329 template<typename VECTOR>
00330 Radian
00331 Angle3( const VECTOR& u, const VECTOR& v )
00332 {
00333     // Dot product formula indirectly provides the angle.
00334     // angle = arccos( DotProduct(u,v) / Distance(u) * Distance(v) )
00335     fp uv = Distance(u) * Distance(v);
00336     if ( ABS(uv) < 0.1 ) return 0.0;  // prevent NaN and div by 0
00337     fp theta = DotProduct3(u,v) / uv;
00338     theta = Clamp( theta, -1.0, 1.0 ); // acos() won't tolerate 1.00000001
00339 
00340     fp rad = acos( theta );
00341 ASSERT(errno == 0);  // if acos() failed
00342     return rad;
00343 }
00344 
00355 INLINE Vector3
00356 Interpolate( const Vector3& v1, const Vector3& v2, const fp fraction )
00357 {
00358 ASSERT( fraction >= 0.0 && fraction <= 1.0 );
00359     return Vector3( v1 + ((v2-v1) * fraction) );
00360 }
00361 
00365 template<typename T>
00366 T
00367 Midpoint( T x1, T x2 )
00368 {
00369 //  return x1 + (x2 - x1) / 2;
00370     return (x1 + x2) / 2;  // faster
00371 }
00372 
00373 INLINE Vector3
00374 Midpoint( const Vector3& v1, const Vector3& v2 )
00375 {
00376     return Vector3( Midpoint(v1.x, v2.x),
00377                     Midpoint(v1.y, v2.y),
00378                     Midpoint(v1.z, v2.z) );
00379 }
00380 
00384 
00388 template<typename T>
00389 T
00390 SQUARE( T x )
00391 {
00392     return x * x;
00393 }
00394 
00398 template<typename T>
00399 T
00400 AVG( T x, T y )
00401 {
00402     return (x + y) / 2;
00403 }
00404 
00408 template<typename T>
00409 T
00410 Range( T val, T lo, T hi )
00411 {
00412     if ( val < lo ) return lo;
00413     if ( val > hi ) return hi;
00414     return val;
00415 }
00416 
00420 template<typename T>
00421 T
00422 IfInRange( T a0, T a1, T b0, T b1 )
00423 {
00424     // Prove the reverse: test if out-of-range.
00425          if ( a0 > b1 )
00426         return false;
00427     else if ( a1 < b0 )
00428         return false;
00429     else if ( b0 > a1 )
00430         return false;
00431     else if ( b1 < a0 )
00432         return false;
00433     else
00434         return true;  // within range
00435 }
00436 
00440 INLINE fp
00441 Remap( fp value, fp rangeOld, fp rangeNew )
00442 {
00443     return value / rangeOld * rangeNew;
00444 }
00445 
00450 INLINE fp
00451 Truncate( fp val, fp interval )
00452 {
00453     float integral;  // float, not fp, as address is passed to modff()
00454     modff( val/interval, &integral );
00455     return integral*interval;
00456 }
00457 
00458 } // namespace gfx
00459 
00460 #endif // GFX_MATH_HH
Palomino 3D Engine documents generated by doxygen 1.5.3 on Fri Nov 23 11:26:10 2007