"L. Spiro Engine"
|
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__