TAPs 0.7.7.3
TAPsElasticRodCD.cpp
Go to the documentation of this file.
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----+----
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines