Wm4Distance.cpp

Go to the documentation of this file.
00001 // Wild Magic Source Code
00002 // David Eberly
00003 // http://www.geometrictools.com
00004 // Copyright (c) 1998-2007
00005 //
00006 // This library is free software; you can redistribute it and/or modify it
00007 // under the terms of the GNU Lesser General Public License as published by
00008 // the Free Software Foundation; either version 2.1 of the License, or (at
00009 // your option) any later version.  The license is available for reading at
00010 // either of the locations:
00011 //     http://www.gnu.org/copyleft/lgpl.html
00012 //     http://www.geometrictools.com/License/WildMagicLicense.pdf
00013 // The license applies to versions 0 through 4 of Wild Magic.
00014 //
00015 // Version: 4.0.0 (2006/06/28)
00016 
00017 #include "Wm4FoundationPCH.h"
00018 #include "Wm4Distance.h"
00019 
00020 namespace Wm4
00021 {
00022 //----------------------------------------------------------------------------
00023 template <class Real, class TVector>
00024 Distance<Real,TVector>::Distance ()
00025 {
00026     MaximumIterations = 8;
00027     ZeroThreshold = Math<Real>::ZERO_TOLERANCE;
00028     SetDifferenceStep((Real)1e-03);
00029 
00030     m_fContactTime = Math<Real>::MAX_REAL;
00031     m_bHasMultipleClosestPoints0 = false;
00032     m_bHasMultipleClosestPoints1 = false;
00033 }
00034 //----------------------------------------------------------------------------
00035 template <class Real, class TVector>
00036 Distance<Real,TVector>::~Distance ()
00037 {
00038 }
00039 //----------------------------------------------------------------------------
00040 template <class Real, class TVector>
00041 Real Distance<Real,TVector>::GetDifferenceStep () const
00042 {
00043     return m_fDifferenceStep;
00044 }
00045 //----------------------------------------------------------------------------
00046 template <class Real, class TVector>
00047 Real Distance<Real,TVector>::GetContactTime () const
00048 {
00049     return m_fContactTime;
00050 }
00051 //----------------------------------------------------------------------------
00052 template <class Real, class TVector>
00053 const TVector& Distance<Real,TVector>::GetClosestPoint0 () const
00054 {
00055     return m_kClosestPoint0;
00056 }
00057 //----------------------------------------------------------------------------
00058 template <class Real, class TVector>
00059 const TVector& Distance<Real,TVector>::GetClosestPoint1 () const
00060 {
00061     return m_kClosestPoint1;
00062 }
00063 //----------------------------------------------------------------------------
00064 template <class Real, class TVector>
00065 bool Distance<Real,TVector>::HasMultipleClosestPoints0 () const
00066 {
00067     return m_bHasMultipleClosestPoints0;
00068 }
00069 //----------------------------------------------------------------------------
00070 template <class Real, class TVector>
00071 bool Distance<Real,TVector>::HasMultipleClosestPoints1 () const
00072 {
00073     return m_bHasMultipleClosestPoints1;
00074 }
00075 //----------------------------------------------------------------------------
00076 template <class Real, class TVector>
00077 void Distance<Real,TVector>::SetDifferenceStep (Real fDifferenceStep)
00078 {
00079     assert(fDifferenceStep > (Real)0.0);
00080     if (fDifferenceStep > (Real)0.0)
00081     {
00082         m_fDifferenceStep = fDifferenceStep;
00083     }
00084     else
00085     {
00086         m_fDifferenceStep = (Real)1e-03;
00087     }
00088 
00089     m_fInvTwoDifferenceStep = ((Real)0.5)/m_fDifferenceStep;
00090 }
00091 //----------------------------------------------------------------------------
00092 template <class Real, class TVector>
00093 Real Distance<Real,TVector>::GetDerivative (Real fT,
00094     const TVector& rkVelocity0, const TVector& rkVelocity1)
00095 {
00096     // Use a finite difference approximation:  f'(t) = (f(t+h)-f(t-h))/(2*h)
00097     Real fFp = Get(fT+m_fDifferenceStep,rkVelocity0,rkVelocity1);
00098     Real fFm = Get(fT-m_fDifferenceStep,rkVelocity0,rkVelocity1);
00099     Real fDFApprox = m_fInvTwoDifferenceStep*(fFp-fFm);
00100     return fDFApprox;
00101 }
00102 //----------------------------------------------------------------------------
00103 template <class Real, class TVector>
00104 Real Distance<Real,TVector>::GetDerivativeSquared (Real fT,
00105     const TVector& rkVelocity0, const TVector& rkVelocity1)
00106 {
00107     // A derived class should override this only if there is a faster method
00108     // to compute the derivative of the squared distance for the specific
00109     // class.
00110     Real fDistance = Get(fT,rkVelocity0,rkVelocity1);
00111     Real fDerivative = GetDerivative(fT,rkVelocity0,rkVelocity1);
00112     return ((Real)2.0)*fDistance*fDerivative;
00113 }
00114 //----------------------------------------------------------------------------
00115 template <class Real, class TVector>
00116 Real Distance<Real,TVector>::Get (Real fTMin, Real fTMax,
00117     const TVector& rkVelocity0, const TVector& rkVelocity1)
00118 {
00119     // The assumption is that distance f(t) is a convex function.  If
00120     // f'(tmin) >= 0, then the minimum occurs at tmin.  If f'(tmax) <= 0,
00121     // then the minimum occurs at tmax.  Otherwise, f'(0) < 0 and
00122     // f'(tmax) > 0 and the minimum occurs at some t in (tmin,tmax).
00123 
00124     Real fT0 = fTMin;
00125     Real fF0 = Get(fT0,rkVelocity0,rkVelocity1);
00126     if (fF0 <= ZeroThreshold)
00127     {
00128         // The distance is effectively zero.  The objects are initially in
00129         // contact.
00130         m_fContactTime = fT0;
00131         return (Real)0.0;
00132     }
00133     Real fDF0 = GetDerivative(fT0,rkVelocity0,rkVelocity1);
00134     if (fDF0 >= (Real)0.0)
00135     {
00136         // The distance is increasing on [0,tmax].
00137         m_fContactTime = fT0;
00138         return fF0;
00139     }
00140 
00141     Real fT1 = fTMax;
00142     Real fF1 = Get(fT1,rkVelocity0,rkVelocity1);
00143     if (fF1 <= ZeroThreshold)
00144     {
00145         // The distance is effectively zero.
00146         m_fContactTime = fT1;
00147         return (Real)0.0;
00148     }
00149     Real fDF1 = GetDerivative(fT1,rkVelocity0,rkVelocity1);
00150     if (fDF1 <= (Real)0.0)
00151     {
00152         // The distance is decreasing on [0,tmax].
00153         m_fContactTime = fT1;
00154         return fF1;
00155     }
00156 
00157     // Start the process with Newton's method for computing a time when the
00158     // distance is zero.  During this process we will switch to a numerical
00159     // minimizer if we decide that the distance cannot be zero.
00160     int i;
00161     for (i = 0; i < MaximumIterations; i++)
00162     {
00163         // compute the next Newton's iterate
00164         Real fT = fT0 - fF0/fDF0;
00165         if (fT >= fTMax)
00166         {
00167             // The convexity of the graph guarantees that when this condition
00168             // happens, the distance is always positive.  Switch to a
00169             // numerical minimizer.
00170             break;
00171         }
00172 
00173         Real fF = Get(fT,rkVelocity0,rkVelocity1);
00174         if (fF <= ZeroThreshold)
00175         {
00176             // The distance is effectively zero.
00177             m_fContactTime = fT;
00178             return (Real)0.0;
00179         }
00180 
00181         Real fDF = GetDerivative(fT,rkVelocity0,rkVelocity1);
00182         if (fDF >= (Real)0.0)
00183         {
00184             // The convexity of the graph guarantees that when this condition
00185             // happens, the distance is always positive.  Switch to a
00186             // numerical minimizer.
00187             break;
00188         }
00189 
00190         fT0 = fT;
00191         fF0 = fF;
00192         fDF0 = fDF;
00193     }
00194 
00195     if (i == MaximumIterations)
00196     {
00197         // Failed to converge within desired number of iterations.  To
00198         // reach here, the derivative values were always negative, so report
00199         // the distance at the last time.
00200         m_fContactTime = fT0;
00201         return fF0;
00202     }
00203 
00204     // The distance is always positive.  Use bisection to find the root of
00205     // the derivative function.
00206     Real fTm = fT0;
00207     for (i = 0; i < MaximumIterations; i++)
00208     {
00209         fTm = ((Real)0.5)*(fT0 + fT1);
00210         Real fDFm = GetDerivative(fTm,rkVelocity0,rkVelocity1);
00211         Real fProduct = fDFm*fDF0;
00212         if (fProduct < -ZeroThreshold)
00213         {
00214             fT1 = fTm;
00215             fDF1 = fDFm;
00216         }
00217         else if (fProduct > ZeroThreshold)
00218         {
00219             fT0 = fTm;
00220             fDF0 = fDFm;
00221         }
00222         else
00223         {
00224             break;
00225         }
00226     }
00227 
00228     // This is the time at which the minimum occurs and is not the contact
00229     // time.  Store it anyway for debugging purposes.
00230     m_fContactTime = fTm;
00231     Real fFm = Get(fTm,rkVelocity0,rkVelocity1);
00232     return fFm;
00233 }
00234 //----------------------------------------------------------------------------
00235 template <class Real, class TVector>
00236 Real Distance<Real,TVector>::GetSquared (Real fTMin, Real fTMax,
00237     const TVector& rkVelocity0, const TVector& rkVelocity1)
00238 {
00239     // The assumption is that distance f(t) is a convex function.  If
00240     // f'(tmin) >= 0, then the minimum occurs at tmin.  If f'(tmax) <= 0,
00241     // then the minimum occurs at tmax.  Otherwise, f'(0) < 0 and
00242     // f'(tmax) > 0 and the minimum occurs at some t in (tmin,tmax).
00243 
00244     Real fT0 = fTMin;
00245     Real fF0 = GetSquared(fT0,rkVelocity0,rkVelocity1);
00246     if (fF0 <= ZeroThreshold)
00247     {
00248         // The distance is effectively zero.  The objects are initially in
00249         // contact.
00250         m_fContactTime = fT0;
00251         return (Real)0.0;
00252     }
00253     Real fDF0 = GetDerivativeSquared(fT0,rkVelocity0,rkVelocity1);
00254     if (fDF0 >= (Real)0.0)
00255     {
00256         // The distance is increasing on [0,tmax].
00257         m_fContactTime = fT0;
00258         return fF0;
00259     }
00260 
00261     Real fT1 = fTMax;
00262     Real fF1 = GetSquared(fT1,rkVelocity0,rkVelocity1);
00263     if (fF1 <= ZeroThreshold)
00264     {
00265         // The distance is effectively zero.
00266         m_fContactTime = fT1;
00267         return (Real)0.0;
00268     }
00269     Real fDF1 = GetDerivativeSquared(fT1,rkVelocity0,rkVelocity1);
00270     if (fDF1 <= (Real)0.0)
00271     {
00272         // The distance is decreasing on [0,tmax].
00273         m_fContactTime = fT1;
00274         return fF1;
00275     }
00276 
00277     // Start the process with Newton's method for computing a time when the
00278     // distance is zero.  During this process we will switch to a numerical
00279     // minimizer if we decide that the distance cannot be zero.
00280     int i;
00281     for (i = 0; i < MaximumIterations; i++)
00282     {
00283         // compute the next Newton's iterate
00284         Real fT = fT0 - fF0/fDF0;
00285         if (fT >= fTMax)
00286         {
00287             // The convexity of the graph guarantees that when this condition
00288             // happens, the distance is always positive.  Switch to a
00289             // numerical minimizer.
00290             break;
00291         }
00292 
00293         Real fF = GetSquared(fT,rkVelocity0,rkVelocity1);
00294         if (fF <= ZeroThreshold)
00295         {
00296             // The distance is effectively zero.
00297             m_fContactTime = fT;
00298             return (Real)0.0;
00299         }
00300 
00301         Real fDF = GetDerivativeSquared(fT,rkVelocity0,rkVelocity1);
00302         if (fDF >= (Real)0.0)
00303         {
00304             // The convexity of the graph guarantees that when this condition
00305             // happens, the distance is always positive.  Switch to a
00306             // numerical minimizer.
00307             break;
00308         }
00309 
00310         fT0 = fT;
00311         fF0 = fF;
00312         fDF0 = fDF;
00313     }
00314 
00315     if (i == MaximumIterations)
00316     {
00317         // Failed to converge within desired number of iterations.  To
00318         // reach here, the derivative values were always negative, so report
00319         // the distance at the last time.
00320         m_fContactTime = fT0;
00321         return fF0;
00322     }
00323 
00324     // The distance is always positive.  Use bisection to find the root of
00325     // the derivative function.
00326     Real fTm = fT0;
00327     for (i = 0; i < MaximumIterations; i++)
00328     {
00329         fTm = ((Real)0.5)*(fT0 + fT1);
00330         Real fDFm = GetDerivativeSquared(fTm,rkVelocity0,rkVelocity1);
00331         Real fProduct = fDFm*fDF0;
00332         if (fProduct < -ZeroThreshold)
00333         {
00334             fT1 = fTm;
00335             fDF1 = fDFm;
00336         }
00337         else if (fProduct > ZeroThreshold)
00338         {
00339             fT0 = fTm;
00340             fDF0 = fDFm;
00341         }
00342         else
00343         {
00344             break;
00345         }
00346     }
00347 
00348     // This is the time at which the minimum occurs and is not the contact
00349     // time.  Store it anyway for debugging purposes.
00350     m_fContactTime = fTm;
00351     Real fFm = GetSquared(fTm,rkVelocity0,rkVelocity1);
00352     return fFm;
00353 }
00354 //----------------------------------------------------------------------------
00355 
00356 //----------------------------------------------------------------------------
00357 // explicit instantiation
00358 //----------------------------------------------------------------------------
00359 template class Distance<float,Vector2f>;
00360 template class Distance<float,Vector3f>;
00361 
00362 template class Distance<double,Vector2d>;
00363 template class Distance<double,Vector3d>;
00364 //----------------------------------------------------------------------------
00365 }

Generated on Wed Nov 23 19:01:03 2011 for FreeCAD by  doxygen 1.6.1