"L. Spiro Engine"

F:/My Projects/LSEngine/Modules/LSMathLib/Src/Line/LSMLineSeg3Base.h

00001 
00017 #ifndef __LSM_LINESEG3BASE_H__
00018 #define __LSM_LINESEG3BASE_H__
00019 
00020 #include "../LSMMathLib.h"
00021 
00022 namespace lsm {
00023 
00030         template <typename _tType, typename _tVec3Type>
00031         class CLineSeg3Base {
00032                 // All is public.  This class has no secrets.
00033         public :
00034                 // == Various constructors.
00035                 LSE_INLINE LSE_CALLCTOR                 CLineSeg3Base() {
00036                 }
00037                 LSE_INLINE LSE_CALLCTOR                 CLineSeg3Base( const CLineSeg3Base<_tType, _tVec3Type> &_lsbLine ) {
00038                         (*this) = _lsbLine;
00039                 }
00040                 LSE_INLINE LSE_CALLCTOR                 CLineSeg3Base( const _tVec3Type &_vStart, const _tVec3Type &_vEnd ) {
00041                         p = _vStart;
00042                         q = _vEnd;
00043                 }
00044 
00045 
00046                 // == Functions.
00056                 _tVec3Type LSE_FCALL                    ClosestPointOnLineSegToPoint( const _tVec3Type &_vPoint, _tType &_tT ) const {
00057                         _tVec3Type vAb = q - p;
00058                         // Project C onto AB but deferring divide.
00059                         _tT = vAb.Dot( _vPoint - p );
00060                         if ( _tT <= static_cast<_tType>(0.0) ) {
00061                                 // Beyond point A.  Return the starting point of the segment.
00062                                 _tT = static_cast<_tType>(0.0);
00063                                 return p;
00064                         }
00065                         else {
00066                                 _tType fDenom = vAb.LenSq();
00067                                 if ( _tT >= fDenom ) {
00068                                         // Beyond point B.  Return the end of the segment.
00069                                         _tT = static_cast<_tType>(1.0);
00070                                         return q;
00071                                 }
00072                                 // Somewhere in the middle.  Return it the normal way (with the deferred divide here).
00073                                 _tT /= fDenom;
00074                                 return p + (vAb * _tT);
00075                         }
00076                 }
00077 
00084                 _tType LSE_FCALL                                SqDistToPoint( const _tVec3Type &_vPoint ) const {
00085                         _tVec3Type vAb = q - p;
00086                         _tVec3Type vAc = _vPoint - p;
00087                         
00088 
00089                         _tType fE = vAb.Dot( vAc );
00090                         if ( fE <= static_cast<_tType>(0.0) ) { return vAc.LenSq(); }
00091                         _tType fF = vAb.LenSq();
00092                         _tVec3Type vBc = _vPoint - q;
00093                         if ( fE >= fF ) { return vBc.LenSq(); }
00094 
00095                         return vAc.LenSq() - fE * fE / fF;
00096                 }
00097 
00112                 _tType LSE_FCALL                                ClosestPointOnLineSegToLineSeg( const CLineSeg3Base<_tType, _tVec3Type> &_lsbLine, _tType &_tS, _tType &_tT,
00113                         _tType &_tRealS, _tType &_tRealT, _tVec3Type &_v0, _tVec3Type &_v1 ) const {
00114                         _tVec3Type vD1 = q - p;
00115                         _tVec3Type vD2 = _lsbLine.q - _lsbLine.p;
00116                         _tVec3Type vR = p - _lsbLine.p;
00117                         _tType fA = vD1.LenSq();
00118                         _tType fE = vD2.LenSq();
00119                         _tType fF = vD2.Dot( vR );
00120 
00121                         // If both segments degenerate to a point.
00122                         if ( fA <= static_cast<_tType>(LSM_REAL_EPSILON) && fE <= static_cast<_tType>(LSM_REAL_EPSILON) ) {
00123                                 _tT = _tS = static_cast<_tType>(0.0);
00124                                 // No valid value for _tRealS and _tRealT.
00125                                 _tRealS = _tRealT = static_cast<_tType>(LSM_INFINITY);
00126                                 _v0 = p;
00127                                 _v1 = _lsbLine.p;
00128                                 return vR.LenSq();
00129                         }
00130                         // If this segment degenerates into a point.
00131                         if ( fA <= static_cast<_tType>(LSM_REAL_EPSILON) ) {
00132                                 _tS = static_cast<_tType>(0.0);
00133                                 // No valid value for _tRealS and _tRealT.
00134                                 _tRealS = _tRealT = static_cast<_tType>(LSM_INFINITY);
00135                                 _tT = CMathLib::Clamp( fF / fE, static_cast<_tType>(0.0), static_cast<_tType>(1.0) );
00136                         }
00137                         else {
00138                                 _tType fC = vD1.Dot( vR );
00139                                 // If the other segment degenerates into a point.
00140                                 if ( fE <= static_cast<_tType>(LSM_REAL_EPSILON) ) {
00141                                         _tT = static_cast<_tType>(0.0);
00142                                         // No valid value for _tRealS and _tRealT.
00143                                         _tRealS = _tRealT = static_cast<_tType>(LSM_INFINITY);
00144                                         _tS = CMathLib::Clamp( -fC / fA, static_cast<_tType>(0.0), static_cast<_tType>(1.0) );
00145                                 }
00146                                 else {
00147                                         // Neither are degenerate.  This is most cases.
00148                                         _tType fB = vD1.Dot( vD2 );
00149                                         _tType fDenom = fA * fE - fB * fB;
00150 
00151                                         // If not parallel.
00152                                         if ( fDenom != static_cast<_tType>(0.0) ) {
00153                                                 _tRealS = (fB * fF - fC * fE) / fDenom;
00154                                                 _tS = CMathLib::Clamp( _tRealS, static_cast<_tType>(0.0), static_cast<_tType>(1.0) );
00155                                         }
00156                                         // Otherwise pick an arbitrary point (0 here).
00157                                         else {
00158                                                 _tRealS = _tS = static_cast<_tType>(0.0);
00159                                         }
00160 
00161                                         _tT = _tRealT = (fB * _tS + fF) / fE;
00162 
00163                                         // If _tT is in the range [0,1] then we are done.  Otherwise
00164                                         //      adjusting T requires updating S also.
00165                                         if ( _tT < static_cast<_tType>(0.0) ) {
00166                                                 _tT = static_cast<_tType>(0.0);
00167                                                 _tS = CMathLib::Clamp( -fC / fA, static_cast<_tType>(0.0), static_cast<_tType>(1.0) );
00168                                         }
00169                                         else if ( _tT > static_cast<_tType>(1.0) ) {
00170                                                 _tT = static_cast<_tType>(1.0);
00171                                                 _tS = CMathLib::Clamp( (fB - fC) / fA, static_cast<_tType>(0.0), static_cast<_tType>(1.0) );
00172                                         }
00173 
00174                                 }
00175                         }
00176 
00177                         _v0 = p + vD1 * _tS;
00178                         _v1 = _lsbLine.p + vD2 * _tT;
00179                         _tType fDist = (_v1 - _v0).LenSq();
00180                         // If there was a degenerate situation, _tRealS/_tRealT will only be valid in the case where the line segments actually
00181                         //      intersect.  In a degenerate situation, one or both of the line segments is treated as a point, so they cannot
00182                         //      be calculated except if the degenerate point is on the valid line segment, or both degenerate points are the same.
00183                         if ( _tRealS == static_cast<_tType>(LSM_INFINITY) && fDist <= static_cast<_tType>(LSM_REAL_EPSILON) ) {
00184                                 _tRealS = _tS;
00185                                 _tRealT = _tT;
00186                         }
00187                         return fDist;
00188                 }
00189                 
00195                 _tType LSE_FCALL                                Len() const {
00196                         return (p - q).Len();
00197                 }
00198 
00204                 _tType LSE_FCALL                                LenSq() const {
00205                         return (p - q).LenSq();
00206                 }
00207 
00208 
00209                 // == Members.
00213                 _tVec3Type                                              p;
00214 
00218                 _tVec3Type                                              q;
00219         };
00220 
00221 }       // namespace lsm
00222 
00223 #endif  // __LSM_LINESEG3BASE_H__
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator