![]() |
TAPs 0.7.7.3
|
00001 /****************************************************************************** 00002 TAPsElasticRodCD.cpp 00003 ******************************************************************************/ 00008 /****************************************************************************** 00009 SUKITTI PUNAK (08/21/2009) 00010 UPDATE (01/04/2011) 00011 ******************************************************************************/ 00012 #include "TAPsElasticRodCD.hpp" 00013 // Using Inclusion Model (i.e. definitions are included in declarations) 00014 // (this name.cpp is included in name.hpp) 00015 // Each friend is defined directly inside its declaration. 00016 00017 BEGIN_NAMESPACE_TAPs 00018 //============================================================================= 00019 //----------------------------------------------------------------------------- 00020 // Constructor 00021 template <typename T> 00022 ElasticRodCD<T>::ElasticRodCD () : 00023 m_BVHTree( NULL ), 00024 m_pIdxCurr( NULL ), 00025 m_pIdxNext( NULL ), 00026 m_pParameters( NULL ), 00027 m_pNodeList( NULL ) 00028 {} 00029 00030 //----------------------------------------------------------------------------- 00031 // Destructor 00032 template <typename T> 00033 ElasticRodCD<T>::~ElasticRodCD () 00034 { 00035 DeleteCD(); 00036 } 00037 00038 //----------------------------------------------------------------------------- 00039 // StrInfo 00040 template <typename T> 00041 std::string ElasticRodCD<T>::StrInfo () const 00042 { 00043 std::stringstream output; 00044 output << "Pointer: " << this << "\t" 00045 << "TAPs::ElasticRodCD<" 00046 << typeid(T).name() << "> Class:"; 00047 //------------------------------------------------- 00048 output << "" 00049 << "\n"; 00050 00051 return output.str(); 00052 } 00053 00054 //----------------------------------------------------------------------------- 00055 // Create collision detection process 00056 template <typename T> 00057 void ElasticRodCD<T>::CreateCD ( 00058 int * pIdxCurr, 00059 int * pIdxNext, 00060 ElasticRodParameters<T> * pParameters, 00061 SetOfElasticRodNodes * pNodeList 00062 ) 00063 { 00064 m_pIdxCurr = pIdxCurr; 00065 m_pIdxNext = pIdxNext; 00066 m_pParameters = pParameters; 00067 m_pNodeList = pNodeList; 00068 00069 #ifdef TAPs_ADVANCED_SELF_COLLISION_DETECTION 00070 InitSelfCDExtraData(); 00071 #endif//TAPs_ADVANCED_SELF_COLLISION_DETECTION 00072 00073 BuildBVHTree(); 00074 } 00075 00076 //----------------------------------------------------------------------------- 00077 // Delete collision detection process 00078 template <typename T> 00079 void ElasticRodCD<T>::DeleteCD () 00080 { 00081 #ifdef TAPs_ADVANCED_SELF_COLLISION_DETECTION 00082 DeleteSelfCDExtraData(); 00083 #endif//TAPs_ADVANCED_SELF_COLLISION_DETECTION 00084 00085 delete m_BVHTree; 00086 if ( m_BVHTree ) { 00087 m_BVHTree = NULL; 00088 } 00089 } 00090 00091 //----------------------------------------------------------------------------- 00092 // Reset 00093 template <typename T> 00094 void ElasticRodCD<T>::Reset () 00095 { 00096 #ifdef TAPs_ADVANCED_SELF_COLLISION_DETECTION 00097 ResetSelfCDExtraData(); 00098 #endif//TAPs_ADVANCED_SELF_COLLISION_DETECTION 00099 } 00100 00101 //----------------------------------------------------------------------------- 00102 // Build the BVH tree for the elastic rod 00103 template <typename T> 00104 void ElasticRodCD<T>::BuildBVHTree () 00105 { 00106 //---------------------------------------------------------------- 00107 Vector3<T> center; 00108 // / ------------------- 00109 // sphere radius = ( link's radius + link's half length 00110 // \ ------------------- 00111 T radius = m_pParameters->Radius + m_pParameters->LinkLength/2.0; 00112 //---------------------------------------------------------------- 00113 // Create Leaf Nodes 00114 int numOfLinks = m_pParameters->NumOfNodes - 1; 00115 BVHNode<T> **nodeList = new BVHNode<T> *[ numOfLinks ]; 00116 SetOfElasticRodNodes::iterator nextNode = m_pNodeList->begin(); 00117 SetOfElasticRodNodes::iterator currNode = nextNode++; 00118 00119 //* 00120 int numOfNodes = -1; 00121 for ( int i = 0; i < numOfLinks; ++i, ++currNode, ++nextNode ) { 00122 BVHNodeLeafElasticRodNode<T> * pBVNode = new BVHNodeLeafElasticRodNode<T>( 00123 TAPs::Enum::BVH_NODE_LEAF_SPHERE_TWO_ELASTIC_ROD_NODES, 00124 ++numOfNodes, // node id 00125 NULL // parent node 00126 ); 00127 pBVNode->SetPtrToPrimitive_1( &(*currNode) ); 00128 pBVNode->SetPtrToPrimitive_2( &(*nextNode) ); 00129 nodeList[i] = pBVNode; 00130 nodeList[i]->SetRadius( radius ); 00131 nodeList[i]->SetCenter( ( currNode->Centerline[*m_pIdxCurr].GetPosition() + nextNode->Centerline[*m_pIdxCurr].GetPosition() ) / 2.0 ); 00132 //nodeList[i]->SetCenter( Vector3<T>(0,0,0) ); 00133 00134 //std::cout << i << ": " << pBVNode->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr] << "\n"; 00135 } 00136 //*/ 00137 00138 //---------------------------------------------------------------- 00139 // Create Hierarchy Nodes 00140 m_BVHTree = BuildBVHTreeRecursively( numOfNodes+1, nodeList, numOfLinks ); 00141 00142 //std::cout << "*m_BVHTree: " << *m_BVHTree << "\n"; 00143 //std::cout << m_BVHTree->DisplayAllNodesAsString() << "\n"; 00144 } 00145 00146 //----------------------------------------------------------------------------- 00147 // Collision Detection and Response with an MBV (Multi-Bounding Volume) object 00148 template <typename T> 00149 bool ElasticRodCD<T>::CDRwith ( 00150 MultiBoundingVolume<T> * const pMBVObj, 00151 TransformationSupport<T> * const pTransform 00152 ) 00153 { 00154 bool bResult = false; 00155 00156 SetOfElasticRodNodes::iterator ERNodes = m_pNodeList->begin(); 00157 00158 //--------------------------------------------------------------- 00159 TransformationSupport<T> transform; 00160 //--------------------------------------------------------------- 00161 if ( pTransform ) { 00162 transform.RefToMatrixTransform() *= pTransform->GetMatrixTransform(); 00163 } 00164 //--------------------------------------------------------------- 00165 transform.RefToMatrixTransform() *= pMBVObj->GetTransform().GetMatrixTransform(); 00166 00167 // Check collision 00168 TransformationSupport<T> oldTrx( pMBVObj->GetTransform() ); // store the old transformation 00169 pMBVObj->GetTransform() = transform; // set to the new transformation 00170 bResult = this->GetBVHTree()->TestOverlapWithTillLeafNodes( pMBVObj ); // collision detection automatically uses the new transformation 00171 pMBVObj->GetTransform() = oldTrx; // restore the old transformation 00172 if ( !bResult ) return bResult; 00173 00174 // Collision response constants are scaled by the number of core simutation iterations. 00175 T timestep_sqrt = m_pParameters->TimeStep * m_pParameters->TimeStep; 00176 T Ksphere = m_pParameters->K_CDRwBV_Sphere / timestep_sqrt; 00177 T Kcylinder = m_pParameters->K_CDRwBV_Cylinder / timestep_sqrt; 00178 00179 TransformationSupport<T> savedTransform( transform ); 00180 00181 // Get the collided node lists and the collided BVs 00182 std::vector< BVsAndNodesList<T> > & cdDat = this->GetBVHTree()->GetListOfCollidedBoundingVolumesAndNodes(); 00183 00184 // Iterate all of the collided BVs 00185 std::vector< BVsAndNodesList<T> >::iterator it = cdDat.begin(); 00186 while ( it != cdDat.end() ) { 00187 BoundingVolume<T> * pBV = it->BV; 00188 assert( pBV != NULL ); 00189 transform = savedTransform; 00190 00191 //------------------------------------------------- 00192 transform.RefToMatrixTransform() *= pBV->GetTransform().GetMatrixTransform(); 00193 //------------------------------------------------- 00194 // Transform each vertex of the strand to the bounding volume coordinate 00195 //int iDeepestPoint = -1; 00196 //T tDeepestDistance = Math<T>::MAX; 00197 Vector3<T> vDirection; 00198 Vector3<T> translation( transform.GetTranslation() ); 00199 Matrix3x3<T> inversedRotMatrix( transform.GetMatrixRotation().GetInverse() ); 00200 //T distance; 00201 Vector3<T> U; // displacement vector 00202 std::vector< BVHNode<T> * >::iterator node = it->NodeList.begin(); 00203 00204 //T epsilon = m_pParameters->Radius * 0.05; // for collision response 00205 00206 switch ( pBV->GetType() ) { 00207 //--------------------------------------------- 00208 case TAPs::Enum::BOUNDING_CYLINDER: 00209 //--------------------------------------------- 00210 { 00211 // Test only points against the cylinder BV, NOT cylinders againt the BV. 00212 00213 T combinedRadius = m_pParameters->Radius + pBV->GetRadius() + m_pParameters->Offset_CD_BV_Cylinder; 00214 while ( node != it->NodeList.end() ) { 00215 BVHNodeLeafElasticRodNode<T> * Node = dynamic_cast<BVHNodeLeafElasticRodNode<T> *>( *node ); 00216 00217 // In the local coordinate of the bounding cylinder, 00218 // the cylinder axis is parallel to z-axis 00219 // where it is shifted by the cylinder center. 00220 // The cylinder has radius, height and center. 00221 // Its height is measured from -z and +z axis 00222 // where its center is situated between height/2 in -z and +z axis. 00223 Vector3<T> P1( Node->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].GetPosition() ); 00224 Vector3<T> P2( Node->GetPtrToPrimitive_2()->Centerline[*m_pIdxCurr].GetPosition() ); 00225 P1 -= translation; 00226 P1 = inversedRotMatrix * P1; 00227 P2 -= translation; 00228 P2 = inversedRotMatrix * P2; 00229 // Shift the location of point by the cylinder center 00230 // i.e. shift the cylinder to the origin (0,0,0) 00231 P1 -= pBV->GetCenter(); 00232 P2 -= pBV->GetCenter(); 00233 00234 // Now the cylinder is centered at the origin with its axis on the z-axis 00235 // where its height is from -height/2 to +height/2. 00236 // And the input point has been transformed into the cylinder coordinate. 00237 // The test can be performed. 00238 00239 // The 1st point 00240 if ( CGMath<T>::CD_CylinderAtOrigin_vs_Point( combinedRadius, pBV->GetHeight(), P1, U ) ) { 00241 bResult = true; 00242 // Now rotate it back by the rotation matrix (from the transform matrix). 00243 // REMARK: Translation (from the transform matrix) is NOT applied back, 00244 // because U represents a displacement vector from 00245 // the input point to the cylinder surface. 00246 // I.e., the strand point is always in the world coordinates. 00247 U = transform.GetMatrixRotation() * U; 00248 U *= Kcylinder * Node->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].GetMass(); 00249 Node->GetPtrToPrimitive_1()->ExternalForce += U; 00250 00251 //U *= 1.0; 00252 //Node->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].SetPosition( Node->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].GetPosition() + U ); 00253 00254 } 00255 00256 // The 2nd point 00257 // SKIPPED to avoid duplicating the replusive force 00258 //if ( CGMath<T>::CD_CylinderAtOrigin_vs_Sphere( pBV->GetRadius(), pBV->GetHeight(), P2, m_pParameters->Radius, U ) ) { 00259 // bResult = true; 00260 // // Now rotate it back by the rotation matrix (from the transform matrix). 00261 // // REMARK: Translation (from the transform matrix) is NOT applied back, 00262 // // because U represents a displacement vector from 00263 // // the input point to the cylinder surface. 00264 // // I.e., the strand point is always in the world coordinates. 00265 // U = transform.GetMatrixRotation() * U; 00266 // U *= Kcylinder; 00267 // Node->GetPtrToPrimitive_2()->ExternalForce += U; 00268 //} 00269 00270 ++node; 00271 } 00272 } 00273 break; 00274 // END: BOUNDING_CYLINDER 00275 00276 //--------------------------------------------- 00277 case TAPs::Enum::BOUNDING_SPHERE: 00278 //--------------------------------------------- 00279 { 00280 // Each sphere bounding volume has its own center location and transformation. 00281 // To get the world coordinate location of the sphere, the sphere center point 00282 // is transformed by the transformation. 00283 Vector3<T> Cs = ( (transform.RefToMatrixTransform() * Vector4<T>( pBV->GetCenter() )).GetVector3() ); 00284 T Rs = ( ( transform.RefToMatrixTransform() * Vector4<T>(Cs + Vector3<T>(0,0,pBV->GetRadius())) ).GetVector3() - Cs ).Length(); 00285 00286 T combinedRadius = m_pParameters->Radius + pBV->GetRadius() + m_pParameters->Offset_CD_BV_Sphere; 00287 while ( node != it->NodeList.end() ) { 00288 00289 BVHNodeLeafElasticRodNode<T> * Node = dynamic_cast<BVHNodeLeafElasticRodNode<T> *>( *node ); 00290 00291 T ratio; 00292 Vector3<T> projPt; 00293 CGMath<T>::FindProjectedPointOnALine( 00294 Cs, // sphere BV's center 00295 Node->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].GetPosition(), 00296 Node->GetPtrToPrimitive_2()->Centerline[*m_pIdxCurr].GetPosition(), 00297 ratio, 00298 projPt 00299 ); 00300 if ( 0 <= ratio && ratio <= 1 ) { 00301 U = projPt - Cs; 00302 if ( U.Length() < combinedRadius ) { 00303 bResult = true; 00304 // By force 00305 U *= Ksphere * Node->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].GetMass(); 00306 Node->GetPtrToPrimitive_1()->ExternalForce += U; 00307 // The 2nd point is skipped to avoid duplicating the repulsive force 00308 //Node->GetPtrToPrimitive_2()->ExternalForce += U; 00309 } 00310 } 00311 ++node; 00312 } 00313 } 00314 break; 00315 // END: BOUNDING_SPHERE 00316 00317 }//END: switch ( pBV->GetType() ) {...} 00318 ++it; // Next Bounding Volume 00319 } 00320 return bResult; 00321 } 00322 00323 //----------------------------------------------------------------------------- 00324 // Collision Detection and Response by selected segments with an MBV (Multi-Bounding Volume) object 00325 template <typename T> 00326 bool ElasticRodCD<T>::CDRbySegmentsWith ( 00327 std::vector<unsigned int> const * pSegments, 00328 MultiBoundingVolume<T> * const pMBVObj, 00329 TransformationSupport<T> * const pTransform 00330 ) 00331 { 00332 bool bResult = false; 00333 00334 SetOfElasticRodNodes::iterator ERNodes = m_pNodeList->begin(); 00335 00336 //--------------------------------------------------------------- 00337 TransformationSupport<T> transform; 00338 //--------------------------------------------------------------- 00339 if ( pTransform ) { 00340 transform.RefToMatrixTransform() *= pTransform->GetMatrixTransform(); 00341 } 00342 //--------------------------------------------------------------- 00343 transform.RefToMatrixTransform() *= pMBVObj->GetTransform().GetMatrixTransform(); 00344 00345 // Check collision 00346 TransformationSupport<T> oldTrx( pMBVObj->GetTransform() ); // store the old transformation 00347 pMBVObj->GetTransform() = transform; // set to the new transformation 00348 bResult = this->GetBVHTree()->TestOverlapWithTillLeafNodes( pMBVObj ); // collision detection automatically uses the new transformation 00349 pMBVObj->GetTransform() = oldTrx; // restore the old transformation 00350 if ( !bResult ) return bResult; 00351 00352 // Collision response constants are scaled by the number of core simutation iterations. 00353 T timestep_sqrt = m_pParameters->TimeStep * m_pParameters->TimeStep; 00354 T Ksphere = m_pParameters->K_CDRwBV_Sphere / timestep_sqrt; 00355 T Kcylinder = m_pParameters->K_CDRwBV_Cylinder / timestep_sqrt; 00356 00357 TransformationSupport<T> savedTransform( transform ); 00358 00359 // Get the collided node lists and the collided BVs 00360 std::vector< BVsAndNodesList<T> > & cdDat = this->GetBVHTree()->GetListOfCollidedBoundingVolumesAndNodes(); 00361 00362 // 00363 // Create skip/unskip status of all nodes 00364 // 00365 std::vector<bool> unskips( m_pNodeList->size() - 1, false ); 00366 if ( cdDat.size() > 0 ) { 00367 for ( unsigned int i = 0; i < pSegments->size() / 2; i+=2 ) { 00368 unsigned int start = (*pSegments)[i]; 00369 unsigned int end = (*pSegments)[i+1]; 00370 for ( unsigned int p = start; p <= end; ++p ) { 00371 unskips[p] = true; 00372 } 00373 } 00374 } 00375 00376 // Iterate all of the collided BVs 00377 std::vector< BVsAndNodesList<T> >::iterator it = cdDat.begin(); 00378 while ( it != cdDat.end() ) { 00379 BoundingVolume<T> * pBV = it->BV; 00380 assert( pBV != NULL ); 00381 transform = savedTransform; 00382 00383 //------------------------------------------------- 00384 transform.RefToMatrixTransform() *= pBV->GetTransform().GetMatrixTransform(); 00385 //------------------------------------------------- 00386 // Transform each vertex of the strand to the bounding volume coordinate 00387 //int iDeepestPoint = -1; 00388 //T tDeepestDistance = Math<T>::MAX; 00389 Vector3<T> vDirection; 00390 Vector3<T> translation( transform.GetTranslation() ); 00391 Matrix3x3<T> inversedRotMatrix( transform.GetMatrixRotation().GetInverse() ); 00392 //T distance; 00393 Vector3<T> U; // displacement vector 00394 std::vector< BVHNode<T> * >::iterator node = it->NodeList.begin(); 00395 00396 //T epsilon = m_pParameters->Radius * 0.05; // for collision response 00397 00398 switch ( pBV->GetType() ) { 00399 //--------------------------------------------- 00400 case TAPs::Enum::BOUNDING_CYLINDER: 00401 //--------------------------------------------- 00402 { 00403 // Test only points against the cylinder BV, NOT cylinders againt the BV. 00404 00405 T combinedRadius = m_pParameters->Radius + pBV->GetRadius() + m_pParameters->Offset_CD_BV_Cylinder; 00406 while ( node != it->NodeList.end() ) { 00407 if ( unskips[ (*node)->GetID() ] ) { 00408 BVHNodeLeafElasticRodNode<T> * Node = dynamic_cast<BVHNodeLeafElasticRodNode<T> *>( *node ); 00409 00410 // In the local coordinate of the bounding cylinder, 00411 // the cylinder axis is parallel to z-axis 00412 // where it is shifted by the cylinder center. 00413 // The cylinder has radius, height and center. 00414 // Its height is measured from -z and +z axis 00415 // where its center is situated between height/2 in -z and +z axis. 00416 Vector3<T> P1( Node->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].GetPosition() ); 00417 Vector3<T> P2( Node->GetPtrToPrimitive_2()->Centerline[*m_pIdxCurr].GetPosition() ); 00418 P1 -= translation; 00419 P1 = inversedRotMatrix * P1; 00420 P2 -= translation; 00421 P2 = inversedRotMatrix * P2; 00422 // Shift the location of point by the cylinder center 00423 // i.e. shift the cylinder to the origin (0,0,0) 00424 P1 -= pBV->GetCenter(); 00425 P2 -= pBV->GetCenter(); 00426 00427 // Now the cylinder is centered at the origin with its axis on the z-axis 00428 // where its height is from -height/2 to +height/2. 00429 // And the input point has been transformed into the cylinder coordinate. 00430 // The test can be performed. 00431 00432 // The 1st point 00433 if ( CGMath<T>::CD_CylinderAtOrigin_vs_Point( combinedRadius, pBV->GetHeight(), P1, U ) ) { 00434 bResult = true; 00435 // Now rotate it back by the rotation matrix (from the transform matrix). 00436 // REMARK: Translation (from the transform matrix) is NOT applied back, 00437 // because U represents a displacement vector from 00438 // the input point to the cylinder surface. 00439 // I.e., the strand point is always in the world coordinates. 00440 U = transform.GetMatrixRotation() * U; 00441 U *= Kcylinder * Node->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].GetMass(); 00442 Node->GetPtrToPrimitive_1()->ExternalForce += U; 00443 00444 //U *= 1.0; 00445 //Node->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].SetPosition( Node->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].GetPosition() + U ); 00446 00447 } 00448 00449 // The 2nd point 00450 // SKIPPED to avoid duplicating the replusive force 00451 //if ( CGMath<T>::CD_CylinderAtOrigin_vs_Sphere( pBV->GetRadius(), pBV->GetHeight(), P2, m_pParameters->Radius, U ) ) { 00452 // bResult = true; 00453 // // Now rotate it back by the rotation matrix (from the transform matrix). 00454 // // REMARK: Translation (from the transform matrix) is NOT applied back, 00455 // // because U represents a displacement vector from 00456 // // the input point to the cylinder surface. 00457 // // I.e., the strand point is always in the world coordinates. 00458 // U = transform.GetMatrixRotation() * U; 00459 // U *= Kcylinder; 00460 // Node->GetPtrToPrimitive_2()->ExternalForce += U; 00461 //} 00462 } 00463 ++node; 00464 } 00465 } 00466 break; 00467 // END: BOUNDING_CYLINDER 00468 00469 //--------------------------------------------- 00470 case TAPs::Enum::BOUNDING_SPHERE: 00471 //--------------------------------------------- 00472 { 00473 // Each sphere bounding volume has its own center location and transformation. 00474 // To get the world coordinate location of the sphere, the sphere center point 00475 // is transformed by the transformation. 00476 Vector3<T> Cs = ( (transform.RefToMatrixTransform() * Vector4<T>( pBV->GetCenter() )).GetVector3() ); 00477 T Rs = ( ( transform.RefToMatrixTransform() * Vector4<T>(Cs + Vector3<T>(0,0,pBV->GetRadius())) ).GetVector3() - Cs ).Length(); 00478 00479 T combinedRadius = m_pParameters->Radius + pBV->GetRadius() + m_pParameters->Offset_CD_BV_Sphere; 00480 while ( node != it->NodeList.end() ) { 00481 if ( unskips[ (*node)->GetID() ] ) { 00482 BVHNodeLeafElasticRodNode<T> * Node = dynamic_cast<BVHNodeLeafElasticRodNode<T> *>( *node ); 00483 00484 T ratio; 00485 Vector3<T> projPt; 00486 CGMath<T>::FindProjectedPointOnALine( 00487 Cs, // sphere BV's center 00488 Node->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].GetPosition(), 00489 Node->GetPtrToPrimitive_2()->Centerline[*m_pIdxCurr].GetPosition(), 00490 ratio, 00491 projPt 00492 ); 00493 if ( 0 <= ratio && ratio <= 1 ) { 00494 U = projPt - Cs; 00495 if ( U.Length() < combinedRadius ) { 00496 bResult = true; 00497 // By force 00498 U *= Ksphere * Node->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].GetMass(); 00499 Node->GetPtrToPrimitive_1()->ExternalForce += U; 00500 // The 2nd point is skipped to avoid duplicating the repulsive force 00501 //Node->GetPtrToPrimitive_2()->ExternalForce += U; 00502 } 00503 } 00504 } 00505 ++node; 00506 } 00507 } 00508 break; 00509 // END: BOUNDING_SPHERE 00510 00511 }//END: switch ( pBV->GetType() ) {...} 00512 ++it; // Next Bounding Volume 00513 } 00514 return bResult; 00515 } 00516 00517 //----------------------------------------------------------------------------- 00518 // Collision Detection and Response with an MBV (Multi-Bounding Volume) object 00519 template <typename T> 00520 bool ElasticRodCD<T>::CDRwithMBVforShaftLikeObject_wCheckWrappingLoops ( 00521 MultiBoundingVolume<T> * const pMBVObj, 00522 Vector3<T> * const pShaftStartPt, 00523 Vector3<T> * const pShaftEndPt, 00524 T const * pShaftRadiusOfInfluence, 00525 TransformationSupport<T> * const pTransform, 00526 T * pNumOfWrappingLoops, 00527 bool * isCCW 00528 //, std::vector<Loop> * pWrappingLoops //!< list of formed wrapping loops 00529 ) 00530 { 00531 bool result = CDRwith( pMBVObj, pTransform ); 00532 00533 // DEBUG 00534 //d_NodePositions.clear(); 00535 00536 if ( result ) 00537 { 00538 Vector3<T> lineStartPt, lineEndPt; 00539 Vector3<T> lineStartPt_world, lineEndPt_world; 00540 // Transform the shaft line by the extra transformation 00541 if ( pTransform ) { 00542 lineStartPt_world = (pTransform->GetMatrixTransform() * Vector4<T>(*pShaftStartPt)).GetVector3(); 00543 lineEndPt_world = (pTransform->GetMatrixTransform() * Vector4<T>(*pShaftEndPt)).GetVector3(); 00544 } 00545 else { 00546 lineStartPt_world = *pShaftStartPt; 00547 lineEndPt_world = *pShaftEndPt; 00548 } 00549 00550 // Transform the line start point to be at the origin 00551 // and the line end point to be at a positive z-value 00552 //lineEndPt -= lineStartPt; 00553 00554 Matrix4x4<T> rotMat = CGMath<T>::CreateRotationMatrix4x4FromVectorAtoVectorB( (lineEndPt_world-lineStartPt_world).GetUnit(), CGMath<T>::VectorZ ); 00555 Matrix4x4<T> transMat = Matrix4x4<T> ( 00556 1, 0, 0, -lineStartPt_world[0], 00557 0, 1, 0, -lineStartPt_world[1], 00558 0, 0, 1, -lineStartPt_world[2], 00559 0, 0, 0, 1 00560 ); 00561 00562 Matrix4x4<T> trx = rotMat * transMat; 00563 00564 // 360 degrees divided into 8 zones; each contain 45 degrees 00565 const int NUM_ZONES = 8; 00566 //static unsigned char zoneCounts[NUM_ZONES]; 00567 //memset( zoneCounts, 0, sizeof(unsigned char)*NUM_ZONES ); 00568 int prevZone = 0, currZone = 0; 00569 00570 T zStartPt = 0; // always equals to zero due to the transformation 00571 T zEndPt = (trx * lineEndPt_world).GetZ(); // always align with the z-axis due to the transformation 00572 00573 int count = 0; 00574 00575 // Check with all of elastic rod's nodes 00576 SetOfElasticRodNodes::iterator it = m_pNodeList->begin(); 00577 while ( it != m_pNodeList->end() ) { 00578 Vector3<T> nodePos = trx * it->Centerline[*m_pIdxCurr].GetPosition(); 00579 00580 // DEBUG 00581 //d_NodePositions.push_back( nodePos ); 00582 00583 T xAbsVal = fabs( nodePos[0] ); 00584 T yAbsVal = fabs( nodePos[1] ); 00585 int greaterThan45Degs = ( xAbsVal < yAbsVal ) ? 1 : 0; 00586 if ( nodePos[0] > 0 ) { 00587 if ( nodePos[1] > 0 ) currZone = 0 + greaterThan45Degs; // 0-90 degrees 00588 else currZone = 7 - greaterThan45Degs; // 270-360 degrees 00589 } 00590 else { 00591 if ( nodePos[1] > 0 ) currZone = 3 - greaterThan45Degs; // 90-180 degrees 00592 else currZone = 4 + greaterThan45Degs; // 180-270 degrees 00593 } 00594 if ( zStartPt <= nodePos[2] && nodePos[2] <= zEndPt ) { 00595 // Check that the xy distance does not over the shaft's radius of influence 00596 if ( sqrt( xAbsVal*xAbsVal + yAbsVal*yAbsVal ) <= *pShaftRadiusOfInfluence ) { 00597 if ( prevZone != currZone ) 00598 { 00599 //++zoneCounts[currZone]; 00600 00601 if ( currZone == 0 ) { 00602 if ( prevZone == NUM_ZONES-1 ) { 00603 ++count; 00604 } 00605 else { 00606 --count; 00607 } 00608 } 00609 else if ( currZone == NUM_ZONES-1 ) { 00610 if ( prevZone == 0 ) { 00611 --count; 00612 } 00613 else { 00614 ++count; 00615 } 00616 } 00617 else if ( currZone > prevZone ) { 00618 ++count; 00619 } 00620 else {//if ( currZone < prevZone ) { 00621 --count; 00622 } 00623 } 00624 } 00625 } 00626 prevZone = currZone; 00627 ++it; 00628 } 00629 00631 //int lowestVal = 1E3; 00632 //for ( int i = 0; i < NUM_ZONES; ++i ) { 00633 // if ( lowestVal > zoneCounts[i] ) lowestVal = zoneCounts[i]; 00634 // //std::cout << "zone " << i << ": " << (int)zoneCounts[i] << "\n"; 00635 //} 00636 //*pNumOfWrappingLoops = lowestVal; 00637 00638 // Check the number of loops and direction based on the count value 00639 if ( count <= 0 ) *isCCW = true; 00640 else *isCCW = false; 00641 T loops = static_cast<T>( abs(count) ) / NUM_ZONES; 00642 *pNumOfWrappingLoops = loops; 00643 00644 // DEBUG -- by drawing 00645 d_NumOfWrappingLoops = static_cast<int>( *pNumOfWrappingLoops ); 00646 d_ShaftSPt = trx * lineStartPt_world; 00647 d_ShaftEPt = trx * lineEndPt_world; 00648 } 00649 00650 return result; 00651 } 00652 00653 //----------------------------------------------------------------------------- 00654 // Collision Detection and Response by selected segments with an MBV (Multi-Bounding Volume) object 00655 template <typename T> 00656 bool ElasticRodCD<T>::CDRbySegmentsWithMBVforShaftLikeObject_wCheckWrappingLoops ( 00657 std::vector<unsigned int> const * pSegments, 00658 MultiBoundingVolume<T> * const pMBVObj, 00659 Vector3<T> * const pShaftStartPt, 00660 Vector3<T> * const pShaftEndPt, 00661 T const * pShaftRadiusOfInfluence, 00662 TransformationSupport<T> * const pTransform, 00663 T * pNumOfWrappingLoops, 00664 bool * isCCW 00665 //, std::vector<Loop> * pWrappingLoops //!< list of formed wrapping loops 00666 ) 00667 { 00668 bool result = CDRbySegmentsWith( pSegments, pMBVObj, pTransform ); 00669 00670 // DEBUG 00671 //d_NodePositions.clear(); 00672 00673 if ( result ) 00674 { 00675 Vector3<T> lineStartPt, lineEndPt; 00676 Vector3<T> lineStartPt_world, lineEndPt_world; 00677 // Transform the shaft line by the extra transformation 00678 if ( pTransform ) { 00679 lineStartPt_world = (pTransform->GetMatrixTransform() * Vector4<T>(*pShaftStartPt)).GetVector3(); 00680 lineEndPt_world = (pTransform->GetMatrixTransform() * Vector4<T>(*pShaftEndPt)).GetVector3(); 00681 } 00682 else { 00683 lineStartPt_world = *pShaftStartPt; 00684 lineEndPt_world = *pShaftEndPt; 00685 } 00686 00687 // Transform the line start point to be at the origin 00688 // and the line end point to be at a positive z-value 00689 //lineEndPt -= lineStartPt; 00690 00691 Matrix4x4<T> rotMat = CGMath<T>::CreateRotationMatrix4x4FromVectorAtoVectorB( (lineEndPt_world-lineStartPt_world).GetUnit(), CGMath<T>::VectorZ ); 00692 Matrix4x4<T> transMat = Matrix4x4<T> ( 00693 1, 0, 0, -lineStartPt_world[0], 00694 0, 1, 0, -lineStartPt_world[1], 00695 0, 0, 1, -lineStartPt_world[2], 00696 0, 0, 0, 1 00697 ); 00698 00699 Matrix4x4<T> trx = rotMat * transMat; 00700 00701 // 360 degrees divided into 8 zones; each contain 45 degrees 00702 const int NUM_ZONES = 8; 00703 //static unsigned char zoneCounts[NUM_ZONES]; 00704 //memset( zoneCounts, 0, sizeof(unsigned char)*NUM_ZONES ); 00705 int prevZone = 0, currZone = 0; 00706 00707 T zStartPt = 0; // always equals to zero due to the transformation 00708 T zEndPt = (trx * lineEndPt_world).GetZ(); // always align with the z-axis due to the transformation 00709 00710 int count = 0; 00711 00712 // 00713 // Create skip/unskip status of all nodes 00714 // 00715 std::vector<bool> unskips( m_pNodeList->size(), false ); 00716 for ( unsigned int i = 0; i < pSegments->size() / 2; i+=2 ) { 00717 unsigned int start = (*pSegments)[i]; 00718 unsigned int end = (*pSegments)[i+1]; 00719 for ( unsigned int p = start; p <= end; ++p ) { 00720 unskips[p] = true; 00721 } 00722 } 00723 00724 // Check with all of elastic rod's nodes 00725 SetOfElasticRodNodes::iterator it = m_pNodeList->begin(); 00726 int nodeID = 0; 00727 while ( it != m_pNodeList->end() ) { 00728 if ( unskips[ nodeID++ ] ) { 00729 Vector3<T> nodePos = trx * it->Centerline[*m_pIdxCurr].GetPosition(); 00730 00731 // DEBUG 00732 //d_NodePositions.push_back( nodePos ); 00733 00734 T xAbsVal = fabs( nodePos[0] ); 00735 T yAbsVal = fabs( nodePos[1] ); 00736 int greaterThan45Degs = ( xAbsVal < yAbsVal ) ? 1 : 0; 00737 if ( nodePos[0] > 0 ) { 00738 if ( nodePos[1] > 0 ) currZone = 0 + greaterThan45Degs; // 0-90 degrees 00739 else currZone = 7 - greaterThan45Degs; // 270-360 degrees 00740 } 00741 else { 00742 if ( nodePos[1] > 0 ) currZone = 3 - greaterThan45Degs; // 90-180 degrees 00743 else currZone = 4 + greaterThan45Degs; // 180-270 degrees 00744 } 00745 if ( zStartPt <= nodePos[2] && nodePos[2] <= zEndPt ) { 00746 // Check that the xy distance does not over the shaft's radius of influence 00747 if ( sqrt( xAbsVal*xAbsVal + yAbsVal*yAbsVal ) <= *pShaftRadiusOfInfluence ) { 00748 if ( prevZone != currZone ) 00749 { 00750 //++zoneCounts[currZone]; 00751 00752 if ( currZone == 0 ) { 00753 if ( prevZone == NUM_ZONES-1 ) { 00754 ++count; 00755 } 00756 else { 00757 --count; 00758 } 00759 } 00760 else if ( currZone == NUM_ZONES-1 ) { 00761 if ( prevZone == 0 ) { 00762 --count; 00763 } 00764 else { 00765 ++count; 00766 } 00767 } 00768 else if ( currZone > prevZone ) { 00769 ++count; 00770 } 00771 else {//if ( currZone < prevZone ) { 00772 --count; 00773 } 00774 } 00775 } 00776 } 00777 } 00778 prevZone = currZone; 00779 ++it; 00780 } 00781 00783 //int lowestVal = 1E3; 00784 //for ( int i = 0; i < NUM_ZONES; ++i ) { 00785 // if ( lowestVal > zoneCounts[i] ) lowestVal = zoneCounts[i]; 00786 // //std::cout << "zone " << i << ": " << (int)zoneCounts[i] << "\n"; 00787 //} 00788 //*pNumOfWrappingLoops = lowestVal; 00789 00790 // Check the number of loops and direction based on the count value 00791 if ( count <= 0 ) *isCCW = true; 00792 else *isCCW = false; 00793 T loops = static_cast<T>( abs(count) ) / NUM_ZONES; 00794 *pNumOfWrappingLoops = loops; 00795 00796 // DEBUG -- by drawing 00797 d_NumOfWrappingLoops = static_cast<int>( *pNumOfWrappingLoops ); 00798 d_ShaftSPt = trx * lineStartPt_world; 00799 d_ShaftEPt = trx * lineEndPt_world; 00800 } 00801 00802 return result; 00803 } 00804 00805 //----------------------------------------------------------------------------- 00806 // Collision Detection and Response with a HETriMeshOneModelMultiParts object 00807 template <typename T> 00808 bool ElasticRodCD<T>::CDRwith ( 00809 TAPs::OpenGL::HETriMeshOneModelMultiParts<T> * pObj, 00810 TransformationSupport<T> * const pTransform 00811 ) 00812 { 00813 bool bResult = false; 00814 00815 // IsCollide is for DEBUG 00816 SetOfElasticRodNodes::iterator it = m_pNodeList->begin(); 00817 while ( it != m_pNodeList->end() ) { 00818 it->IsCollide = false; 00819 ++it; 00820 } 00821 00822 TransformationSupport<T> transform; 00823 if ( pTransform ) { 00824 transform.RefToMatrixTransform() *= pTransform->RefToMatrixTransform(); 00825 } 00826 transform.RefToMatrixTransform() *= pObj->GetTransform().RefToMatrixTransform(); 00827 00828 // Collision Detection 00829 TransformationSupport<T> oldTrx( pObj->GetTransform() ); // store the old transformation 00830 pObj->GetTransform() = transform; // set to the new transformation 00831 bResult = GetBVHTree()->TestOverlapWithTillLeafNodes( pObj->GetBVHTree() ); // collision detection automatically uses the new transformation 00832 pObj->GetTransform() = oldTrx; // restore the old transformation 00833 if ( !bResult ) return bResult; 00834 00835 // Collision Response 00836 bResult = false; 00837 T Kc = m_pParameters->K_CDRwTriangle; 00838 00839 // The list of collided BV leaf nodes 00840 std::vector< BVHNode<T> * > & ER_BVNodes = GetBVHTree()->GetListOfCollidedNodes(); 00841 std::vector< BVHNode<T> * > & Obj_BVNodes = GetBVHTree()->GetListOfCollidedNodesThat(); 00842 std::vector< HEVertex<T> * const > vertexList; 00843 int noOfVertices; 00844 Matrix4x4<T> & TrxMat = transform.RefToMatrixTransform(); 00845 00846 for ( int i = 0; i < static_cast<int>( ER_BVNodes.size() ); ++i ) { 00847 BVHNodeLeafElasticRodNode<T> * NodeER = dynamic_cast< BVHNodeLeafElasticRodNode<T> * >( ER_BVNodes[i] ); 00848 HEFace<T> * Triangle = Obj_BVNodes[i]->GetAPrimitiveHalfEdgeFace(); 00849 vertexList = Triangle->GetPtrsToVerticesAndNumberOfVertices( noOfVertices ); 00850 Vector3<T> cylA( NodeER->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].GetPosition() ); 00851 Vector3<T> cylB( NodeER->GetPtrToPrimitive_2()->Centerline[*m_pIdxCurr].GetPosition() ); 00852 Vector3<T> posA( (TrxMat * Vector4<T>(vertexList[0]->GetPosition())).GetVector3() ); 00853 Vector3<T> posB( (TrxMat * Vector4<T>(vertexList[1]->GetPosition())).GetVector3() ); 00854 Vector3<T> posC( (TrxMat * Vector4<T>(vertexList[2]->GetPosition())).GetVector3() ); 00855 if ( TAPs::CGMath<T>::FindIntersectionCylinderTriangle( 00856 cylA, cylB, 00857 m_pParameters->Radius + m_pParameters->Offset_CD_Triangle, 00858 posA, posB, posC 00859 ) ) { 00860 Vector3<T> triCentroid( ( posA + posB + posC ) / 3.0 ); 00861 Vector3<T> N( Triangle->GetNormal() ); 00862 N.Normalized(); 00863 Vector3<T> projPt1, projPt2; 00864 TAPs::CGMath<T>::FindProjectedPointOnAPlane( cylA, posB, N, projPt1 ); 00865 TAPs::CGMath<T>::FindProjectedPointOnAPlane( cylB, posB, N, projPt2 ); 00866 Vector3<T> V1( cylA - projPt1 ); 00867 Vector3<T> V2( cylB - projPt2 ); 00868 //Vector3<T> V1( cylA - triCentroid ); 00869 //Vector3<T> V2( cylB - triCentroid ); 00870 T value = V1 * N; 00871 if ( value < 0.0 ) { 00872 if ( NodeER->GetPtrToPrimitive_1()->SimFlags.CheckSimulationConstraints( Enum::AddOn::IGNORE_CD_FORCE ) == false ) { 00873 NodeER->GetPtrToPrimitive_1()->ExternalForce -= value*Kc * N; // adjusted by force 00874 //NodeER->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].SetPosition( cylA - value * N ); // adjusted by position 00875 } 00876 } 00877 value = V2 * N; 00878 if ( value < 0.0 ) { 00879 if ( NodeER->GetPtrToPrimitive_2()->SimFlags.CheckSimulationConstraints( Enum::AddOn::IGNORE_CD_FORCE ) == false ) { 00880 NodeER->GetPtrToPrimitive_2()->ExternalForce -= value*Kc * N; // adjusted by force 00881 //NodeER->GetPtrToPrimitive_2()->Centerline[*m_pIdxCurr].SetPosition( cylB - value * N ); // adjusted by position 00882 } 00883 } 00884 bResult = true; 00885 // DEBUG 00886 NodeER->GetPtrToPrimitive_1()->IsCollide = true; 00887 NodeER->GetPtrToPrimitive_2()->IsCollide = true; 00888 } 00889 } 00890 return bResult; 00891 } 00892 00893 00894 //----------------------------------------------------------------------------- 00895 #ifdef TAPs_ADD_IMPLICIT_OBJECTS 00896 //----------------------------------------------------------------------------- 00897 // Collision Detection and Response with an implicit object 00898 template <typename T> 00899 bool ElasticRodCD<T>::CDRwithImplicitObject ( 00900 ImplicitObject<T> * const pImpObj 00901 ) 00902 { 00903 bool bResult = false; 00904 00905 #ifdef TAPs_SHOW_COLLISION_STATE 00906 pImpObj->IsCollided = false; 00907 #endif//TAPs_SHOW_COLLISION_STATE 00908 00909 switch ( pImpObj->GetShape() ) { 00910 case Enum::SPHERE: 00911 { 00912 bResult = GetBVHTree()->TestOverlapWithTillLeafNodes( pImpObj->GetBVHTree() ); 00913 ImplicitObject_Sphere<T> * pObj = dynamic_cast<ImplicitObject_Sphere<T> *>( pImpObj ); 00914 if ( bResult ) { 00915 CollisionResponseWithImplicitObject_Sphere( pObj ); 00916 } 00917 } 00918 break; 00919 case Enum::TORUS: 00920 { 00921 bResult = GetBVHTree()->TestOverlapWithTillLeafNodes( pImpObj->GetBVHTree() ); 00922 ImplicitObject_Torus<T> * pObj = dynamic_cast<ImplicitObject_Torus<T> *>( pImpObj ); 00923 if ( bResult ) { 00924 CollisionResponseWithImplicitObject_Torus( pObj ); 00925 } 00926 } 00927 break; 00928 } 00929 return bResult; 00930 } 00931 //----------------------------------------------------------------------------- 00932 #endif//TAPs_ADD_IMPLICIT_OBJECTS 00933 //----------------------------------------------------------------------------- 00934 00935 00936 //----------------------------------------------------------------------------- 00937 // This function assumes no intersections between immediate adjacent links. 00938 template <typename T> 00939 void ElasticRodCD<T>::CDRforSelfIntersections () 00940 { 00941 CheckSelfIntersectionsNextLevelRecursively( m_BVHTree->Root()->Child(0), m_BVHTree->Root()->Child(1) ); 00942 } 00943 00944 //----------------------------------------------------------------------------- 00945 // Build the BVH tree recursively (called by BuildBVHTree function) 00946 template <typename T> 00947 BVHTree<T> * ElasticRodCD<T>::BuildBVHTreeRecursively ( 00948 int startID, 00949 BVHNode<T> ** childNodeList, 00950 int numOfChildNodes 00951 ) 00952 { 00953 BVHNode<T> ** parentNodeList; 00954 if ( numOfChildNodes > 1 ) { 00955 int numOfParentNodes; 00956 if ( numOfChildNodes % 2 == 0 ) { 00957 numOfParentNodes = numOfChildNodes/2; 00958 parentNodeList = new BVHNode<T> *[ numOfParentNodes ]; 00959 for ( int i = 0, p = 0; i < numOfChildNodes; i+=2, ++p, ++startID ) { 00960 parentNodeList[p] = new BVHNode<T>( 00961 TAPs::Enum::BVH_NODE_BINARY_SPHERE, 00962 startID, NULL, NULL ); 00963 parentNodeList[p]->Child( 0, childNodeList[i] ); 00964 parentNodeList[p]->Child( 1, childNodeList[i+1] ); 00965 } 00966 } 00967 else { 00968 numOfParentNodes = numOfChildNodes/2 + 1; 00969 parentNodeList = new BVHNode<T> *[ numOfParentNodes ]; 00970 for ( int i = 0, p = 0; i < numOfChildNodes-1; i+=2, ++p, ++startID ) { 00971 parentNodeList[p] = new BVHNode<T>( 00972 TAPs::Enum::BVH_NODE_BINARY_SPHERE, 00973 startID, NULL, NULL ); 00974 parentNodeList[p]->Child( 0, childNodeList[i] ); 00975 parentNodeList[p]->Child( 1, childNodeList[i+1] ); 00976 } 00977 parentNodeList[numOfParentNodes-1] = childNodeList[numOfChildNodes-1]; 00978 } 00979 delete [] childNodeList; 00980 return BuildBVHTreeRecursively( startID, parentNodeList, numOfParentNodes ); 00981 } 00982 else { 00983 BVHTree<T> * tree = new BVHTree_BinarySphere<T>( m_DummyTransform, 00984 /*TAPs::Enum::BVH_TREE_BINARY_SPHERE,*/ startID, childNodeList[0] ); 00985 delete [] childNodeList; 00986 return tree; 00987 } 00988 } 00989 00990 //----------------------------------------------------------------------------- 00991 // Update the BVH tree 00992 template <typename T> 00993 void ElasticRodCD<T>::UpdateBVHTree () 00994 { 00995 if ( m_BVHTree->Root() ) UpdateBVHNodeRecursively( m_BVHTree->Root() ); 00996 } 00997 00998 //----------------------------------------------------------------------------- 00999 // Update the BVH nodes recursively 01000 template <typename T> 01001 void ElasticRodCD<T>::UpdateBVHNodeRecursively ( BVHNode<T> * node ) 01002 { 01003 if ( node->Child(0) ) { 01004 UpdateBVHNodeRecursively( node->Child(0) ); 01005 } 01006 if ( node->Child(1) ) { 01007 UpdateBVHNodeRecursively( node->Child(1) ); 01008 } 01009 //---------------------------------------------------------------- 01010 if ( node->Child(0) == NULL && node->Child(1) == NULL ) { 01011 int id = node->GetID(); 01012 BVHNodeLeafElasticRodNode<T> * pBVNode = dynamic_cast<BVHNodeLeafElasticRodNode<T> *>( node ); 01013 Vector3<T> const & pos1 = pBVNode->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].GetPosition(); 01014 Vector3<T> const & pos2 = pBVNode->GetPtrToPrimitive_2()->Centerline[*m_pIdxCurr].GetPosition(); 01015 pBVNode->SetRadius( (pos2-pos1).Length()/2.0 + m_pParameters->Radius ); 01016 pBVNode->SetCenter( (pos2+pos1) / 2.0 ); 01017 } 01018 else { 01019 node->Update(); 01020 } 01021 } 01022 01023 //----------------------------------------------------------------------------- 01024 // Check self intersection at next level recursively. 01025 // Assume a BVH node either has both children or none. 01026 template <typename T> 01027 void ElasticRodCD<T>::CheckSelfIntersectionsNextLevelRecursively ( BVHNode<T> * node1, BVHNode<T> * node2 ) 01028 { 01029 CheckSelfIntersectionsRecursively( node1, node2 ); 01030 if ( node1->IsNotLeaf() ) CheckSelfIntersectionsNextLevelRecursively( node1->Child(0), node1->Child(1) ); 01031 if ( node2->IsNotLeaf() ) CheckSelfIntersectionsNextLevelRecursively( node2->Child(0), node2->Child(1) ); 01032 } 01033 01034 //----------------------------------------------------------------------------- 01035 // Check self intersection recursively 01036 template <typename T> 01037 T ElasticRodCD<T>::CheckSelfIntersectionsRecursively ( BVHNode<T> * node1, BVHNode<T> * node2 ) 01038 { 01039 T LinkDiameter = 2.0 * m_pParameters->Radius + m_pParameters->Offset_CD_Self; 01040 T LinkStick = LinkDiameter * 1.1; 01041 01042 T ScaledLinkDiameter = LinkDiameter * m_pParameters->KselfCDR_ScaleDistance; 01043 01044 T scale = m_pParameters->KselfCDR / ( m_pParameters->TimeStep * m_pParameters->TimeStep ); 01045 T scaleStick = m_pParameters->KselfStick / ( m_pParameters->TimeStep * m_pParameters->TimeStep ); 01046 01047 // Skip this test and return the highest value if a node is a leaf node or they are siblings. 01048 if ( node1->IsLeaf() && node2->IsLeaf() && abs(node1->GetID()-node2->GetID()) == 1 ) { 01049 return DBL_MAX; 01050 } 01051 01052 // Test overlap between node1 and a group of nodes from node2 on 01053 T overlap = node1->TestOverlapSphereWithSphere_NoPrimitiveTests( node2 ); 01054 if ( overlap < DBL_MIN ) { 01055 if ( node2->IsLeaf() ) { // case: node2 is a leaf node 01056 if ( node1->IsNotLeaf() ) { 01057 /*overlap =*/ CheckSelfIntersectionsRecursively( node1->Child(0), node2 ); 01058 /*overlap =*/ CheckSelfIntersectionsRecursively( node1->Child(1), node2 ); 01059 } 01060 } 01061 else { // case: node2 is not a leaf node 01062 overlap = node1->TestOverlapSphereWithSphere_NoPrimitiveTests( node2->Child(0) ); 01063 if ( overlap < DBL_MIN ) { 01064 /*overlap =*/ CheckSelfIntersectionsRecursively( node1->Child(0), node2->Child(0) ); 01065 /*overlap =*/ CheckSelfIntersectionsRecursively( node1->Child(1), node2->Child(0) ); 01066 } 01067 overlap = node1->TestOverlapSphereWithSphere_NoPrimitiveTests( node2->Child(1) ); 01068 if ( overlap < DBL_MIN ) { 01069 /*overlap =*/ CheckSelfIntersectionsRecursively( node1->Child(0), node2->Child(1) ); 01070 /*overlap =*/ CheckSelfIntersectionsRecursively( node1->Child(1), node2->Child(1) ); 01071 } 01072 } 01073 } 01074 01075 // Both nodes are leaf nodes, then do collision response 01076 if ( node1->IsLeaf() && node2->IsLeaf() ) { 01077 01078 T distance; 01079 Vector3<T> U; 01080 BVHNodeLeafElasticRodNode<T> * Node1 = dynamic_cast<BVHNodeLeafElasticRodNode<T> *>( node1 ); 01081 BVHNodeLeafElasticRodNode<T> * Node2 = dynamic_cast<BVHNodeLeafElasticRodNode<T> *>( node2 ); 01082 01083 CGMath<T>::FindClosestDistanceBetweenTwoLineSegments( 01084 Node1->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].GetPosition(), Node1->GetPtrToPrimitive_2()->Centerline[*m_pIdxCurr].GetPosition(), 01085 Node2->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].GetPosition(), Node2->GetPtrToPrimitive_2()->Centerline[*m_pIdxCurr].GetPosition(), 01086 distance, U 01087 ); 01088 01089 // 01090 // If collide 01091 // 01092 if ( distance < ScaledLinkDiameter ) { 01093 U *= distance * scale / 2.0; 01094 Node1->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].SetForce( Node1->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].GetForce() - U * Node1->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].GetMass() ); 01095 Node1->GetPtrToPrimitive_2()->Centerline[*m_pIdxCurr].SetForce( Node1->GetPtrToPrimitive_2()->Centerline[*m_pIdxCurr].GetForce() - U * Node1->GetPtrToPrimitive_2()->Centerline[*m_pIdxCurr].GetMass() ); 01096 Node2->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].SetForce( Node2->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].GetForce() + U * Node2->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].GetMass() ); 01097 Node2->GetPtrToPrimitive_2()->Centerline[*m_pIdxCurr].SetForce( Node2->GetPtrToPrimitive_2()->Centerline[*m_pIdxCurr].GetForce() + U * Node2->GetPtrToPrimitive_2()->Centerline[*m_pIdxCurr].GetMass() ); 01098 01099 #ifdef TAPs_ADVANCED_SELF_COLLISION_DETECTION 01100 AddSelfCDExtraDataForALinkPair( node1->GetID(), node2->GetID() ); 01101 #endif//TAPs_ADVANCED_SELF_COLLISION_DETECTION 01102 } 01103 // Make them stick together 01104 else if ( distance < LinkStick ) { 01105 U *= (LinkDiameter - distance) * scaleStick / 2.0; 01106 Node1->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].SetForce( Node1->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].GetForce() - U * Node1->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].GetMass() ); 01107 Node1->GetPtrToPrimitive_2()->Centerline[*m_pIdxCurr].SetForce( Node1->GetPtrToPrimitive_2()->Centerline[*m_pIdxCurr].GetForce() - U * Node1->GetPtrToPrimitive_2()->Centerline[*m_pIdxCurr].GetMass() ); 01108 Node2->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].SetForce( Node2->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].GetForce() + U * Node2->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].GetMass() ); 01109 Node2->GetPtrToPrimitive_2()->Centerline[*m_pIdxCurr].SetForce( Node2->GetPtrToPrimitive_2()->Centerline[*m_pIdxCurr].GetForce() + U * Node2->GetPtrToPrimitive_2()->Centerline[*m_pIdxCurr].GetMass() ); 01110 01111 #ifdef TAPs_ADVANCED_SELF_COLLISION_DETECTION 01112 AddSelfCDExtraDataForALinkPair( node1->GetID(), node2->GetID() ); 01113 #endif//TAPs_ADVANCED_SELF_COLLISION_DETECTION 01114 } 01115 } 01116 return overlap; 01117 } 01118 01119 01120 01121 01122 //----------------------------------------------------------------------------- 01123 #ifdef TAPs_ADD_IMPLICIT_OBJECTS 01124 //----------------------------------------------------------------------------- 01125 // Collision response with an implicit sphere 01126 template <typename T> 01127 void ElasticRodCD<T>::CollisionResponseWithImplicitObject_Sphere ( ImplicitObject_Sphere<T> * const pImpObj ) 01128 { 01129 #ifdef TAPs_SHOW_COLLISION_STATE 01130 //pImpObj->IsCollided = false; 01131 #endif//TAPs_SHOW_COLLISION_STATE 01132 01133 Vector3<T> sphere_center( pImpObj->GetTransformedCenter() ); 01134 T sphere_radius = pImpObj->GetTransformedRadius(); 01135 01136 std::vector< BVHNode<T> * > & nodeERs = GetBVHTree()->GetListOfCollidedNodes(); 01137 T combinedRadius = m_pParameters->Radius + m_pParameters->Offset_CD_ImpObj_Sphere + sphere_radius; 01138 T distance, u; 01139 Vector3<T> Vd; 01140 BVHNodeLeafElasticRodNode<T> * nodeER; 01141 ElasticRodNode<T> * erNode_1; 01142 //ElasticRodNode<T> * erNode_2; 01143 01144 T scale = m_pParameters->K_CDRwImpObj_Sphere / (m_pParameters->TimeStep * m_pParameters->TimeStep); 01145 01146 // CDR suture's points against the implicit sphere 01147 for ( unsigned int i = 0; i < nodeERs.size(); ++i ) { 01148 nodeER = dynamic_cast<BVHNodeLeafElasticRodNode<T> *>( nodeERs[i] ); 01149 erNode_1 = nodeER->GetPtrToPrimitive_1(); 01150 //erNode_2 = nodeER->GetPtrToPrimitive_2(); 01151 01152 // Point 1 01153 Vd = erNode_1->Centerline[*m_pIdxCurr].GetPosition() - sphere_center; 01154 distance = Vd.Length(); 01155 u = combinedRadius - distance; 01156 if ( u > 0 ) { 01157 //erNode_1->ExternalForce += Vd * ( u / distance ) * m_pParameters->K_CDRwImpObj_Sphere; 01158 erNode_1->ExternalForce += u/distance * scale * erNode_1->Centerline[*m_pIdxCurr].GetMass() * Vd; 01159 #ifdef TAPs_SHOW_COLLISION_STATE 01160 pImpObj->IsCollided = true; 01161 #endif//TAPs_SHOW_COLLISION_STATE 01162 } 01163 // Make it sticky 01164 else if ( u > -m_pParameters->Radius ) { 01165 //Vector3<T> stickyDirection = Vd * (sphere_radius/distance); 01166 erNode_1->ExternalForce -= u/distance * scale * erNode_1->Centerline[*m_pIdxCurr].GetMass() * Vd; 01167 //erNode_1->ExternalForce = ( stickyDirection - Vd ) * 20; 01168 erNode_1->Centerline[*m_pIdxCurr].SetVelocity( 0, 0, 0 ); 01169 } 01170 01171 // SKIPPED to avoid duplicating the replusive force 01172 // Point 2 01173 //Vd = erNode_2->Centerline[*m_pIdxCurr].GetPosition() - sphere_center; 01174 //distance = Vd.Length(); 01175 //u = combinedRadius - distance; 01176 //if ( u > 0 ) { 01177 // erNode_2->ExternalForce += Vd * ( u / distance ) * m_pParameters->K_CDRwImpObj_Sphere; 01178 01179 // #ifdef TAPs_SHOW_COLLISION_STATE 01180 // pImpObj->IsCollided = true; 01181 // #endif//TAPs_SHOW_COLLISION_STATE 01182 //} 01183 } 01184 } 01185 01186 //----------------------------------------------------------------------------- 01187 // Collision response with an implicit torus 01188 template <typename T> 01189 void ElasticRodCD<T>::CollisionResponseWithImplicitObject_Torus ( ImplicitObject_Torus<T> * const pImpObj ) 01190 { 01191 Vector3<T> torus_direction( pImpObj->GetTransformedAxis() ); 01192 Vector3<T> torus_center( pImpObj->GetTransformedCenter() ); 01193 T torus_inner_radius, torus_outer_radius; 01194 pImpObj->GetTransformedRadii( torus_inner_radius, torus_outer_radius ); 01195 01196 std::vector< BVHNode<T> * > & nodeERs = GetBVHTree()->GetListOfCollidedNodes(); 01197 T combinedRadius = m_pParameters->Radius + m_pParameters->Offset_CD_ImpObj_Torus + torus_inner_radius; 01198 T inner_radius = torus_outer_radius - torus_inner_radius; 01199 T outer_radius = torus_outer_radius + torus_inner_radius; 01200 T length, distance, u; 01201 Vector3<T> P, Vd, ProjPt, MedianAxisPt, Force; 01202 BVHNodeLeafElasticRodNode<T> * nodeER; 01203 ElasticRodNode<T> * erNode_1; 01204 //ElasticRodNode<T> * erNode_2; 01205 01206 #ifdef TAPs_SHOW_COLLISION_STATE 01207 //pImpObj->IsCollided = false; 01208 #endif//TAPs_SHOW_COLLISION_STATE 01209 01210 T scale = m_pParameters->K_CDRwImpObj_Torus / (m_pParameters->TimeStep * m_pParameters->TimeStep); 01211 01212 // CDR suture's points against the implicit torus 01213 for ( unsigned int i = 0; i < nodeERs.size(); ++i ) { 01214 01215 nodeER = dynamic_cast<BVHNodeLeafElasticRodNode<T> *>( nodeERs[i] ); 01216 erNode_1 = nodeER->GetPtrToPrimitive_1(); 01217 //erNode_2 = nodeER->GetPtrToPrimitive_2(); 01218 01219 //std::cout << "combinedRadius: " << combinedRadius << "\n"; 01220 01221 // STEP: 01222 // 1) Project the test point on to the torus plane. 01223 // 2) Use the project point to find the point on the torus median axis. 01224 // 3) Find the distance from the test point to the median axis point. 01225 // 4) If the distance is less than the combined radius, then push the test point out of it. 01226 01227 // Point 1 01228 P = erNode_1->Centerline[*m_pIdxCurr].GetPosition(); 01229 CGMath<T>::FindProjectedPointOnAPlane( P, torus_center, torus_direction, ProjPt ); 01230 MedianAxisPt = (ProjPt - torus_center); 01231 length = MedianAxisPt.Length(); 01232 //if ( length > Math<T>::ZERO ) { 01233 if ( inner_radius <= length && length <= outer_radius ) { 01234 MedianAxisPt *= torus_outer_radius / length; 01235 MedianAxisPt += torus_center; 01236 Vd = P - MedianAxisPt; 01237 distance = Vd.Length(); 01238 u = combinedRadius - distance; 01239 if ( u > 0 ) { 01240 //erNode_1->ExternalForce += Vd * ( u / distance ) * m_pParameters->K_CDRwImpObj_Torus; 01241 erNode_1->ExternalForce += u/distance * scale * erNode_1->Centerline[*m_pIdxCurr].GetMass() * Vd; 01242 01243 #ifdef TAPs_SHOW_COLLISION_STATE 01244 pImpObj->IsCollided = true; 01245 #endif//TAPs_SHOW_COLLISION_STATE 01246 } 01247 // Make it sticky 01248 else if ( u > -m_pParameters->Radius ) { 01249 //Vector3<T> stickyDirection = Vd * (torus_inner_radius/distance); 01250 erNode_1->ExternalForce -= u/distance * scale * erNode_1->Centerline[*m_pIdxCurr].GetMass() * Vd; 01251 //erNode_1->ExternalForce = ( stickyDirection - Vd ) * 20; 01252 erNode_1->Centerline[*m_pIdxCurr].SetVelocity( 0, 0, 0 ); 01253 } 01254 } 01255 01256 // SKIPPED to avoid duplicating the replusive force 01257 // Point 2 01258 //P = erNode_2->Centerline[*m_pIdxCurr].GetPosition(); 01259 //CGMath<T>::FindProjectedPointOnAPlane( P, torus_center, torus_direction, ProjPt ); 01260 //MedianAxisPt = (ProjPt - torus_center); 01261 //length = MedianAxisPt.Length(); 01262 //if ( length > Math<T>::ZERO ) { 01263 // MedianAxisPt *= torus_outer_radius / length; 01264 // MedianAxisPt += torus_center; 01265 // Vd = P - MedianAxisPt; 01266 // distance = Vd.Length(); 01267 // u = combinedRadius - distance; 01268 // if ( u > 0 ) { 01269 // erNode_2->ExternalForce += Vd * ( u / distance ) * m_pParameters->K_CDRwImpObj_Torus; 01270 // #ifdef TAPs_SHOW_COLLISION_STATE 01271 // pImpObj->IsCollided = true; 01272 // #endif//TAPs_SHOW_COLLISION_STATE 01273 // } 01274 //} 01275 } 01276 } 01277 //----------------------------------------------------------------------------- 01278 #endif//TAPs_ADD_IMPLICIT_OBJECTS 01279 //----------------------------------------------------------------------------- 01280 01281 01282 01283 01284 //----------------------------------------------------------------------------- 01285 #ifdef TAPs_SIM_WITH_POSITION_BASED_DYNAMICS 01286 //----------------------------------------------------------------------------- 01287 // This function assumes no intersections between immediate adjacent links. 01288 template <typename T> 01289 void ElasticRodCD<T>::CDRforSelfIntersections_PBD () 01290 { 01291 CheckSelfIntersectionsNextLevelRecursively_PBD( m_BVHTree->Root()->Child(0), m_BVHTree->Root()->Child(1) ); 01292 } 01293 //----------------------------------------------------------------------------- 01294 // Update the BVH tree 01295 template <typename T> 01296 void ElasticRodCD<T>::UpdateBVHTree_PBD () 01297 { 01298 if ( m_BVHTree->Root() ) UpdateBVHNodeRecursively_PBD( m_BVHTree->Root() ); 01299 } 01300 //----------------------------------------------------------------------------- 01301 // Update the BVH nodes recursively 01302 template <typename T> 01303 void ElasticRodCD<T>::UpdateBVHNodeRecursively_PBD ( BVHNode<T> * node ) 01304 { 01305 if ( node->Child(0) ) { 01306 UpdateBVHNodeRecursively_PBD( node->Child(0) ); 01307 } 01308 if ( node->Child(1) ) { 01309 UpdateBVHNodeRecursively_PBD( node->Child(1) ); 01310 } 01311 //---------------------------------------------------------------- 01312 if ( node->Child(0) == NULL && node->Child(1) == NULL ) { 01313 int id = node->GetID(); 01314 BVHNodeLeafElasticRodNode<T> * pBVNode = dynamic_cast<BVHNodeLeafElasticRodNode<T> *>( node ); 01315 Vector3<T> const & pos1 = pBVNode->GetPtrToPrimitive_1()->Centerline[*m_pIdxNext].GetPosition(); 01316 Vector3<T> const & pos2 = pBVNode->GetPtrToPrimitive_2()->Centerline[*m_pIdxNext].GetPosition(); 01317 pBVNode->SetRadius( (pos2-pos1).Length()/2.0 + m_pParameters->Radius ); 01318 pBVNode->SetCenter( (pos2+pos1) / 2.0 ); 01319 } 01320 else { 01321 node->Update(); 01322 } 01323 } 01324 //----------------------------------------------------------------------------- 01325 // Check self intersection at next level recursively. 01326 // Assume a BVH node either has both children or none. 01327 template <typename T> 01328 void ElasticRodCD<T>::CheckSelfIntersectionsNextLevelRecursively_PBD ( BVHNode<T> * node1, BVHNode<T> * node2 ) 01329 { 01330 CheckSelfIntersectionsRecursively_PBD( node1, node2 ); 01331 if ( node1->IsNotLeaf() ) CheckSelfIntersectionsNextLevelRecursively_PBD( node1->Child(0), node1->Child(1) ); 01332 if ( node2->IsNotLeaf() ) CheckSelfIntersectionsNextLevelRecursively_PBD( node2->Child(0), node2->Child(1) ); 01333 } 01334 //----------------------------------------------------------------------------- 01335 // Check self intersection recursively 01336 template <typename T> 01337 T ElasticRodCD<T>::CheckSelfIntersectionsRecursively_PBD ( BVHNode<T> * node1, BVHNode<T> * node2 ) 01338 { 01339 T LinkDiameter = 2.0 * m_pParameters->Radius + m_pParameters->Offset_CD_Self; 01340 T ScaledLinkDiameter = LinkDiameter * m_pParameters->KselfCDR_ScaleDistance; 01341 01342 // Skip this test and return the highest value if a node is a leaf node or they are siblings. 01343 if ( node1->IsLeaf() && node2->IsLeaf() && abs(node1->GetID()-node2->GetID()) == 1 ) { 01344 return DBL_MAX; 01345 } 01346 01347 // Test overlap between node1 and a group of nodes from node2 on 01348 T overlap = node1->TestOverlapSphereWithSphere_NoPrimitiveTests( node2 ); 01349 if ( overlap < DBL_MIN ) { 01350 if ( node2->IsLeaf() ) { // case: node2 is a leaf node 01351 if ( node1->IsNotLeaf() ) { 01352 /*overlap =*/ CheckSelfIntersectionsRecursively_PBD( node1->Child(0), node2 ); 01353 /*overlap =*/ CheckSelfIntersectionsRecursively_PBD( node1->Child(1), node2 ); 01354 } 01355 } 01356 else { // case: node2 is not a leaf node 01357 overlap = node1->TestOverlapSphereWithSphere_NoPrimitiveTests( node2->Child(0) ); 01358 if ( overlap < DBL_MIN ) { 01359 /*overlap =*/ CheckSelfIntersectionsRecursively_PBD( node1->Child(0), node2->Child(0) ); 01360 /*overlap =*/ CheckSelfIntersectionsRecursively_PBD( node1->Child(1), node2->Child(0) ); 01361 } 01362 overlap = node1->TestOverlapSphereWithSphere_NoPrimitiveTests( node2->Child(1) ); 01363 if ( overlap < DBL_MIN ) { 01364 /*overlap =*/ CheckSelfIntersectionsRecursively_PBD( node1->Child(0), node2->Child(1) ); 01365 /*overlap =*/ CheckSelfIntersectionsRecursively_PBD( node1->Child(1), node2->Child(1) ); 01366 } 01367 } 01368 } 01369 01370 // Both nodes are leaf nodes, then do collision response 01371 if ( node1->IsLeaf() && node2->IsLeaf() ) { 01372 T distance; 01373 Vector3<T> U; 01374 //int i = node1->GetID(); 01375 //int j = node2->GetID(); 01376 BVHNodeLeafElasticRodNode<T> * Node1 = dynamic_cast<BVHNodeLeafElasticRodNode<T> *>( node1 ); 01377 BVHNodeLeafElasticRodNode<T> * Node2 = dynamic_cast<BVHNodeLeafElasticRodNode<T> *>( node2 ); 01378 01379 CGMath<T>::FindClosestDistanceBetweenTwoLineSegments( 01380 Node1->GetPtrToPrimitive_1()->Centerline[*m_pIdxNext].GetPosition(), Node1->GetPtrToPrimitive_2()->Centerline[*m_pIdxNext].GetPosition(), 01381 Node2->GetPtrToPrimitive_1()->Centerline[*m_pIdxNext].GetPosition(), Node2->GetPtrToPrimitive_2()->Centerline[*m_pIdxNext].GetPosition(), 01382 distance, U 01383 ); 01384 // If collide 01385 if ( distance < ScaledLinkDiameter ) { 01386 U *= distance * m_pParameters->KselfCDR; 01387 CollisionResponseByUpdatingGeometric_PBD( U, Node1, Node2 ); 01388 } 01389 } 01390 return overlap; 01391 } 01392 //----------------------------------------------------------------------------- 01393 // Collision response by geometrically updating the positions of collided segments 01394 template <typename T> 01395 void ElasticRodCD<T>::CollisionResponseByUpdatingGeometric_PBD ( 01396 Vector3<T> & displacementVector, 01397 BVHNodeLeafElasticRodNode<T> * Node1, 01398 BVHNodeLeafElasticRodNode<T> * Node2 01399 ) 01400 { 01401 //std::cout << "Node1: " << Node1 << "\n"; 01402 //std::cout << "Node2: " << Node2 << "\n"; 01403 Node1->GetPtrToPrimitive_1()->Centerline[*m_pIdxNext].SetPosition( Node1->GetPtrToPrimitive_1()->Centerline[*m_pIdxNext].GetPosition() - displacementVector ); 01404 Node1->GetPtrToPrimitive_2()->Centerline[*m_pIdxNext].SetPosition( Node1->GetPtrToPrimitive_2()->Centerline[*m_pIdxNext].GetPosition() - displacementVector ); 01405 Node2->GetPtrToPrimitive_1()->Centerline[*m_pIdxNext].SetPosition( Node2->GetPtrToPrimitive_1()->Centerline[*m_pIdxNext].GetPosition() + displacementVector ); 01406 Node2->GetPtrToPrimitive_2()->Centerline[*m_pIdxNext].SetPosition( Node2->GetPtrToPrimitive_2()->Centerline[*m_pIdxNext].GetPosition() + displacementVector ); 01407 } 01408 //----------------------------------------------------------------------------- 01409 #endif//TAPs_SIM_WITH_POSITION_BASED_DYNAMICS 01410 //----------------------------------------------------------------------------- 01411 01412 01413 01414 01415 //============================================================================= 01416 #ifdef TAPs_ADVANCED_SELF_COLLISION_DETECTION 01417 //----------------------------------------------------------------------------- 01418 template <typename T> 01419 void ElasticRodCD<T>::ResetSelfCDExtraData () 01420 { 01421 for ( int i = 0; i < m_pParameters->NumOfNodes-1; ++i ) { 01422 for ( int j = 0; j < m_pParameters->NumOfNodes-1; ++j ) { 01423 SelfCDExtraDataTrackStatus[i][j] = false; 01424 } 01425 } 01426 ListOfSelfCDExtraData.clear(); 01427 } 01428 //----------------------------------------------------------------------------- 01429 template <typename T> 01430 bool ElasticRodCD<T>::InitSelfCDExtraData () 01431 { 01432 SelfCDExtraDataTrackStatus = new bool*[m_pParameters->NumOfNodes-1]; 01433 if ( !SelfCDExtraDataTrackStatus ) return false; 01434 01435 for ( int i = 0; i < m_pParameters->NumOfNodes-1; ++i ) { 01436 SelfCDExtraDataTrackStatus[i] = new bool[m_pParameters->NumOfNodes-1]; 01437 if ( !SelfCDExtraDataTrackStatus[i] ) { 01438 return false; 01439 } 01440 } 01441 return true; 01442 } 01443 //----------------------------------------------------------------------------- 01444 template <typename T> 01445 void ElasticRodCD<T>::DeleteSelfCDExtraData () 01446 { 01447 for ( int i = 0; i < m_pParameters->NumOfNodes-1; ++i ) { 01448 delete [] SelfCDExtraDataTrackStatus[i]; 01449 } 01450 delete [] SelfCDExtraDataTrackStatus; 01451 } 01452 //----------------------------------------------------------------------------- 01453 template <typename T> 01454 void ElasticRodCD<T>::AddSelfCDExtraDataForALinkPair ( unsigned int id1, unsigned int id2 ) 01455 { 01456 unsigned int diff = id1 - id2; 01457 if ( diff > 1 || diff < -1 ) { 01458 if ( SelfCDExtraDataTrackStatus[id1][id2] == false ) { 01459 SelfCDExtraDataTrackStatus[id1][id2] = true; 01460 SelfCDExtraData<T> data( id1, id2, m_pParameters->Radius ); 01461 data.LinkCenter_A = ( (*m_pNodeList)[data.LinkID_A+1].Centerline[*m_pIdxCurr].GetPosition() + (*m_pNodeList)[data.LinkID_A].Centerline[*m_pIdxCurr].GetPosition() ) * T(0.5); 01462 data.LinkCenter_B = ( (*m_pNodeList)[data.LinkID_B+1].Centerline[*m_pIdxCurr].GetPosition() + (*m_pNodeList)[data.LinkID_B].Centerline[*m_pIdxCurr].GetPosition() ) * T(0.5); 01463 data.AverageCenter = ( data.LinkCenter_A + data.LinkCenter_B ) * T(0.5); 01464 ListOfSelfCDExtraData.push_back( data ); 01465 } 01466 } 01467 } 01468 //----------------------------------------------------------------------------- 01469 template <typename T> 01470 void ElasticRodCD<T>::UpdateSelfCDExtraData () 01471 { 01472 std::list< SelfCDExtraData<T> >::iterator it = ListOfSelfCDExtraData.begin(); 01473 std::list< SelfCDExtraData<T> >::iterator it_erase; 01474 while ( it != ListOfSelfCDExtraData.end() ) { 01475 it->LinkCenter_A = ( (*m_pNodeList)[it->LinkID_A+1].Centerline[*m_pIdxCurr].GetPosition() + (*m_pNodeList)[it->LinkID_A].Centerline[*m_pIdxCurr].GetPosition() ) * T(0.5); 01476 it->LinkCenter_B = ( (*m_pNodeList)[it->LinkID_B+1].Centerline[*m_pIdxCurr].GetPosition() + (*m_pNodeList)[it->LinkID_B].Centerline[*m_pIdxCurr].GetPosition() ) * T(0.5); 01477 it->AverageCenter = ( it->LinkCenter_A + it->LinkCenter_B ) * T(0.5); 01478 01479 T separateThreshold = it->AverageRadius * 20; 01480 T distance = ( it->LinkCenter_A - it->LinkCenter_B ).Length(); 01481 01482 //std::cout << "separateThreshold: " << separateThreshold << "\n"; 01483 //std::cout << "distance: " << distance << "\n"; 01484 01485 if ( distance > separateThreshold ) { 01486 it_erase = it; 01487 ++it; 01488 ListOfSelfCDExtraData.erase( it_erase ); 01489 } 01490 else { 01491 ++it; 01492 } 01493 } 01494 } 01496 //template <typename T> 01497 //void ElasticRodCD<T>::PreventMissedCDWithSelfCDExtraData () 01498 //{ 01499 // bool bRestore = false; 01500 // 01501 // std::list< SelfCDExtraData<T> >::iterator it = ListOfSelfCDExtraData.begin(); 01502 // while ( it != ListOfSelfCDExtraData.end() ) { 01503 // Vector3<T> NewLinkCenter_A = ( (*m_pNodeList)[it->LinkID_A+1].Centerline[*m_pIdxNext].GetPosition() + (*m_pNodeList)[it->LinkID_A].Centerline[*m_pIdxNext].GetPosition() ) * T(0.5); 01504 // Vector3<T> NewLinkCenter_B = ( (*m_pNodeList)[it->LinkID_B+1].Centerline[*m_pIdxNext].GetPosition() + (*m_pNodeList)[it->LinkID_B].Centerline[*m_pIdxNext].GetPosition() ) * T(0.5); 01505 // Vector3<T> NewAverageCenter = ( it->LinkCenter_A + it->LinkCenter_B ) * T(0.5); 01506 // 01507 // Vector3<T> V0 = it->LinkCenter_A - it->AverageCenter; 01508 // Vector3<T> V1 = NewLinkCenter_A - NewAverageCenter; 01509 // 01510 // T angle = V0.Normalized() * V1.Normalized(); 01511 // 01512 // std::cout << "angle: " << angle << "\n"; 01513 // 01514 // // If angle is greater than 90 degrees, then restore the previous position 01515 // if ( angle < T(0) ) { 01516 // bRestore = true; 01517 // //std::cout << "New value: " << (*m_pNodeList)[it->LinkID_A+1].Centerline[*m_pIdxCurr].GetPosition(); 01518 // //std::cout << "OLD value: " << (*m_pNodeList)[it->LinkID_A+1].Centerline[*m_pIdxNext].GetPosition(); 01519 // 01520 // //(*m_pNodeList)[it->LinkID_A+1].Centerline[*m_pIdxNext].SetPosition( (*m_pNodeList)[it->LinkID_A+1].Centerline[*m_pIdxCurr].GetPosition() ); 01521 // //(*m_pNodeList)[it->LinkID_A ].Centerline[*m_pIdxNext].SetPosition( (*m_pNodeList)[it->LinkID_A ].Centerline[*m_pIdxCurr].GetPosition() ); 01522 // //(*m_pNodeList)[it->LinkID_B+1].Centerline[*m_pIdxNext].SetPosition( (*m_pNodeList)[it->LinkID_B+1].Centerline[*m_pIdxCurr].GetPosition() ); 01523 // //(*m_pNodeList)[it->LinkID_B ].Centerline[*m_pIdxNext].SetPosition( (*m_pNodeList)[it->LinkID_B ].Centerline[*m_pIdxCurr].GetPosition() ); 01524 // } 01525 // 01526 // ++it; 01527 // } 01528 // 01529 // if ( bRestore ) { 01530 // 01531 // //std::list< SelfCDExtraData<T> >::iterator it = ListOfSelfCDExtraData.begin(); 01532 // //while ( it != ListOfSelfCDExtraData.end() ) { 01533 // // (*m_pNodeList)[it->LinkID_A+1].Centerline[*m_pIdxNext].SetPosition( (*m_pNodeList)[it->LinkID_A+1].Centerline[*m_pIdxCurr].GetPosition() ); 01534 // // (*m_pNodeList)[it->LinkID_A ].Centerline[*m_pIdxNext].SetPosition( (*m_pNodeList)[it->LinkID_A ].Centerline[*m_pIdxCurr].GetPosition() ); 01535 // // (*m_pNodeList)[it->LinkID_B+1].Centerline[*m_pIdxNext].SetPosition( (*m_pNodeList)[it->LinkID_B+1].Centerline[*m_pIdxCurr].GetPosition() ); 01536 // // (*m_pNodeList)[it->LinkID_B ].Centerline[*m_pIdxNext].SetPosition( (*m_pNodeList)[it->LinkID_B ].Centerline[*m_pIdxCurr].GetPosition() ); 01537 // // ++it; 01538 // //} 01539 // 01540 // //for ( unsigned int i = 0; i < (*m_pNodeList).size(); ++i ) { 01541 // // (*m_pNodeList)[i].Centerline[*m_pIdxNext].SetPosition( (*m_pNodeList)[i].Centerline[*m_pIdxCurr].GetPosition() ); 01542 // //} 01543 // } 01544 //} 01545 //----------------------------------------------------------------------------- 01546 template <typename T> 01547 void ElasticRodCD<T>::CheckAndRestoreWithSelfCDExtraData ( unsigned int nodeID ) 01548 { 01549 std::list< SelfCDExtraData<T> >::iterator it = ListOfSelfCDExtraData.begin(); 01550 while ( it != ListOfSelfCDExtraData.end() ) { 01551 01552 if ( 01553 it->LinkID_A == nodeID || it->LinkID_B == nodeID 01554 || 01555 it->LinkID_A+1 == nodeID || it->LinkID_B+1 == nodeID 01556 ) 01557 { 01558 Vector3<T> NewLinkCenter_A = ( (*m_pNodeList)[it->LinkID_A+1].Centerline[*m_pIdxNext].GetPosition() + (*m_pNodeList)[it->LinkID_A].Centerline[*m_pIdxNext].GetPosition() ) * T(0.5); 01559 Vector3<T> NewLinkCenter_B = ( (*m_pNodeList)[it->LinkID_B+1].Centerline[*m_pIdxNext].GetPosition() + (*m_pNodeList)[it->LinkID_B].Centerline[*m_pIdxNext].GetPosition() ) * T(0.5); 01560 Vector3<T> NewAverageCenter = ( it->LinkCenter_A + it->LinkCenter_B ) * T(0.5); 01561 01562 Vector3<T> V0 = it->LinkCenter_A - it->AverageCenter; 01563 Vector3<T> V1 = NewLinkCenter_A - NewAverageCenter; 01564 01565 T angle = V0.Normalized() * V1.Normalized(); 01566 01567 //std::cout << "angle: " << angle << "\n"; 01568 01569 //T angleThs = T(0); // 90 degrees 01570 //T angleThs = T(0.258819045); // 75 degrees 01571 //T angleThs = T(0.5); // 60 degrees 01572 T angleThs = T(0.707106781); // 45 degrees 01573 //T angleThs = T(0.866025403); // 30 degrees 01574 //T angleThs = T(0.965925826); // 15 degrees 01575 unsigned int offset = 4; // number of extra points on each direction 01576 01577 if ( angle < angleThs ) { 01578 //std::cout << "New value: " << (*m_pNodeList)[it->LinkID_A+1].Centerline[*m_pIdxCurr].GetPosition(); 01579 //std::cout << "OLD value: " << (*m_pNodeList)[it->LinkID_A+1].Centerline[*m_pIdxNext].GetPosition(); 01580 01581 (*m_pNodeList)[it->LinkID_A ].Orientation[*m_pIdxNext] = (*m_pNodeList)[it->LinkID_A ].Orientation[*m_pIdxCurr]; 01582 (*m_pNodeList)[it->LinkID_A+1].Orientation[*m_pIdxNext] = (*m_pNodeList)[it->LinkID_A+1].Orientation[*m_pIdxCurr]; 01583 (*m_pNodeList)[it->LinkID_B ].Orientation[*m_pIdxNext] = (*m_pNodeList)[it->LinkID_B ].Orientation[*m_pIdxCurr]; 01584 (*m_pNodeList)[it->LinkID_B+1].Orientation[*m_pIdxNext] = (*m_pNodeList)[it->LinkID_B+1].Orientation[*m_pIdxCurr]; 01585 01586 (*m_pNodeList)[it->LinkID_A ].Centerline[*m_pIdxNext].SetPosition( (*m_pNodeList)[it->LinkID_A ].Centerline[*m_pIdxCurr].GetPosition() ); 01587 (*m_pNodeList)[it->LinkID_A+1].Centerline[*m_pIdxNext].SetPosition( (*m_pNodeList)[it->LinkID_A+1].Centerline[*m_pIdxCurr].GetPosition() ); 01588 (*m_pNodeList)[it->LinkID_B ].Centerline[*m_pIdxNext].SetPosition( (*m_pNodeList)[it->LinkID_B ].Centerline[*m_pIdxCurr].GetPosition() ); 01589 (*m_pNodeList)[it->LinkID_B+1].Centerline[*m_pIdxNext].SetPosition( (*m_pNodeList)[it->LinkID_B+1].Centerline[*m_pIdxCurr].GetPosition() ); 01590 01591 (*m_pNodeList)[it->LinkID_A ].Centerline[*m_pIdxNext].SetVelocity( 0, 0, 0 ); 01592 (*m_pNodeList)[it->LinkID_A+1].Centerline[*m_pIdxNext].SetVelocity( 0, 0, 0 ); 01593 (*m_pNodeList)[it->LinkID_B ].Centerline[*m_pIdxNext].SetVelocity( 0, 0, 0 ); 01594 (*m_pNodeList)[it->LinkID_B+1].Centerline[*m_pIdxNext].SetVelocity( 0, 0, 0 ); 01595 01596 // A 01597 for ( unsigned int i = it->LinkID_A-offset; i < it->LinkID_A; ++i ) { 01598 if ( i >= 0 ) { 01599 (*m_pNodeList)[i].Centerline[*m_pIdxNext].SetPosition( (*m_pNodeList)[i].Centerline[*m_pIdxCurr].GetPosition() ); 01600 (*m_pNodeList)[i].Centerline[*m_pIdxNext].SetVelocity( 0, 0, 0 ); 01601 (*m_pNodeList)[i].Orientation[*m_pIdxNext] = (*m_pNodeList)[i].Orientation[*m_pIdxCurr]; 01602 } 01603 } 01604 for ( unsigned int i = it->LinkID_A+2; i <= it->LinkID_A+offset; ++i ) { 01605 if ( i < static_cast<unsigned int>( m_pParameters->NumOfNodes ) ) { 01606 (*m_pNodeList)[i].Centerline[*m_pIdxNext].SetPosition( (*m_pNodeList)[i].Centerline[*m_pIdxCurr].GetPosition() ); 01607 (*m_pNodeList)[i].Centerline[*m_pIdxNext].SetVelocity( 0, 0, 0 ); 01608 (*m_pNodeList)[i].Orientation[*m_pIdxNext] = (*m_pNodeList)[i].Orientation[*m_pIdxCurr]; 01609 } 01610 } 01611 // B 01612 for ( unsigned int i = it->LinkID_B-offset; i < it->LinkID_B; ++i ) { 01613 if ( i >= 0 ) { 01614 (*m_pNodeList)[i].Centerline[*m_pIdxNext].SetPosition( (*m_pNodeList)[i].Centerline[*m_pIdxCurr].GetPosition() ); 01615 (*m_pNodeList)[i].Centerline[*m_pIdxNext].SetVelocity( 0, 0, 0 ); 01616 (*m_pNodeList)[i].Orientation[*m_pIdxNext] = (*m_pNodeList)[i].Orientation[*m_pIdxCurr]; 01617 } 01618 } 01619 for ( unsigned int i = it->LinkID_B+2; i <= it->LinkID_B+offset; ++i ) { 01620 if ( i < static_cast<unsigned int>( m_pParameters->NumOfNodes ) ) { 01621 (*m_pNodeList)[i].Centerline[*m_pIdxNext].SetPosition( (*m_pNodeList)[i].Centerline[*m_pIdxCurr].GetPosition() ); 01622 (*m_pNodeList)[i].Centerline[*m_pIdxNext].SetVelocity( 0, 0, 0 ); 01623 (*m_pNodeList)[i].Orientation[*m_pIdxNext] = (*m_pNodeList)[i].Orientation[*m_pIdxCurr]; 01624 } 01625 } 01626 01627 } 01628 } 01629 ++it; 01630 } 01631 } 01632 //----------------------------------------------------------------------------- 01633 #endif//TAPs_ADVANCED_SELF_COLLISION_DETECTION 01634 //============================================================================= 01635 01636 01637 01638 01639 //----------------------------------------------------------------------------- 01640 01641 #if defined(__gl_h_) || defined(__GL_H__) 01642 //============================================================================= 01643 template <typename T> 01644 void ElasticRodCD<T>::Draw () const 01645 { 01646 if ( m_BVHTree ) { 01647 m_BVHTree->Draw(); 01648 } 01649 01650 /* 01651 // DEBUG -- Draw tool shaft line 01652 glPushMatrix(); 01653 glTranslatef( 0, 1, -1 ); 01654 01655 glPushAttrib( GL_ALL_ATTRIB_BITS ); 01656 //glDisable( GL_DEPTH_TEST ); 01657 glDisable( GL_LIGHTING ); 01658 glLineWidth( 5 ); 01659 glBegin( GL_LINES ); 01660 glColor3f( 1, 0, 0 ); 01661 glVertex3fv( d_ShaftSPt.GetDataFloat() ); 01662 glColor3f( 0, 1, 0 ); 01663 glVertex3fv( d_ShaftEPt.GetDataFloat() ); 01664 glEnd(); 01665 01666 // Draw number of wrapping loops as a set of points 01667 glPointSize( 10 ); 01668 glColor3f( 0, 1, 1 ); 01669 glBegin( GL_POINTS ); 01670 glColor3f( 0.5, 0.5, 0.5 ); 01671 glVertex3f( -0.5, 0.0, 0 ); 01672 glColor3f( 0, 1, 1 ); 01673 for ( int i = 0; i < d_NumOfWrappingLoops; ++i ) { 01674 glVertex3f( i*0.5, 0.0, 0 ); 01675 } 01676 glEnd(); 01677 01678 // Draw node positions 01679 glPointSize( 3 ); 01680 glColor3f( 0, 0, 1 ); 01681 glBegin( GL_LINE_STRIP ); 01682 for ( std::vector< Vector3<T> >::const_iterator it = d_NodePositions.begin(); it != d_NodePositions.end(); ++it ) { 01683 glVertex3fv( it->GetDataFloat() ); 01684 } 01685 glEnd(); 01686 01687 glPopAttrib(); 01688 glPopMatrix(); 01689 //*/ 01690 } 01691 01692 #ifdef TAPs_ADVANCED_SELF_COLLISION_DETECTION 01693 template <typename T> 01694 void ElasticRodCD<T>::DrawExtraSelfCDData () const 01695 { 01696 std::list< SelfCDExtraData<T> >::const_iterator it = ListOfSelfCDExtraData.begin(); 01697 while ( it != ListOfSelfCDExtraData.end() ) { 01698 it->Draw(); 01699 ++it; 01700 } 01701 } 01702 #endif//TAPs_ADVANCED_SELF_COLLISION_DETECTION 01703 01704 //============================================================================= 01705 #endif // #if defined(__gl_h_) || defined(__GL_H__) 01706 01707 //============================================================================= 01708 END_NAMESPACE_TAPs 01709 //----------------------------------------------------------------------------- 01710 //34567890123456789012345678901234567890123456789012345678901234567890123456789 01711 //--+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----