![]() |
TAPs 0.7.7.3
|
00001 /****************************************************************************** 00002 TAPsElasticRodKR.cpp 00003 ******************************************************************************/ 00008 /****************************************************************************** 00009 SUKITTI PUNAK (08/31/2009) 00010 UPDATE (03/23/2011) 00011 ******************************************************************************/ 00012 #include "TAPsElasticRodKR.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 00021 // Constructor 00022 template <typename T> 00023 ElasticRodKR<T>::ElasticRodKR () 00024 : m_pIdxCurr( 0 ) 00025 , m_pIdxNext( 0 ) 00026 , m_pParameters( NULL ) 00027 , m_pNodeList( NULL ) 00028 , m_BVHTree( NULL ) 00029 00030 , m_pListOfLockedKnots( NULL ) 00031 , m_iMinPtIdThatIsInRecordedKnots( -1 ) 00032 , m_iMaxPtIdThatIsInRecordedKnots( -1 ) 00033 00034 , m_ucMaxNumKnotsAllowed( 0 ) 00035 , m_ucKnotCount( 0 ) 00036 , m_uiCounterThreshold( 0 ) 00037 , m_uiCounterForFixingKnot( 0 ) 00038 , m_tWaitTime( 0 ) 00039 , m_puiLengthThresholds( NULL ) 00040 { 00041 m_pOGLUsefulObj = new OpenGL::OpenGLUsefulObj<T>( GLU_FILL, 8, 8, Vector4<T>( 0, 1, 0, 1 ) ); 00042 } 00043 00044 // Destructor 00045 template <typename T> 00046 ElasticRodKR<T>::~ElasticRodKR () 00047 { 00048 if ( m_pOGLUsefulObj ) delete m_pOGLUsefulObj; 00049 DeleteKR(); 00050 } 00051 00052 // StrInfo 00053 template <typename T> 00054 std::string ElasticRodKR<T>::StrInfo () const 00055 { 00056 std::stringstream output; 00057 output << "Pointer: " << this << "\t" 00058 << "TAPs::ElasticRodKR<" 00059 << typeid(T).name() << "> Class:"; 00060 //------------------------------------------------- 00061 output << "" 00062 << "\n"; 00063 00064 return output.str(); 00065 } 00066 00067 // Create collision detection process 00068 template <typename T> 00069 void ElasticRodKR<T>::CreateKR ( 00070 int * pIdxCurr, 00071 int * pIdxNext, 00072 ElasticRodParameters<T> * pParameters, 00073 SetOfElasticRodNodes * pNodeList, 00074 BVHTree<T> * bvhTree, 00075 unsigned char numOfNotAllowed 00076 ) 00077 { 00078 m_pIdxCurr = pIdxCurr; 00079 m_pIdxNext = pIdxNext; 00080 m_pParameters = pParameters; 00081 m_pNodeList = pNodeList; 00082 m_BVHTree = bvhTree; 00083 00084 // Initialize this KR 00085 Init( numOfNotAllowed ); 00086 } 00087 00088 // Delete collision detection process 00089 template <typename T> 00090 void ElasticRodKR<T>::DeleteKR () 00091 { 00092 DeleteData(); 00093 } 00094 00095 // Build the BVH tree for the elastic rod 00096 //template <typename T> 00097 //void ElasticRodKR<T>::BuildBVHTree () 00098 //{} 00099 00100 00101 // Find projection direction from the set of three points 00102 template <typename T> 00103 Vector3<T> ElasticRodKR<T>::GetProjDirection () const 00104 { 00105 return TAPs::CGMath<T>::NormalOfTriangle( 00106 m_NodesForProjPoints[0]->Centerline[*m_pIdxCurr].GetPosition(), 00107 m_NodesForProjPoints[1]->Centerline[*m_pIdxCurr].GetPosition(), 00108 m_NodesForProjPoints[2]->Centerline[*m_pIdxCurr].GetPosition() 00109 ); 00110 } 00111 00112 00113 // Create the knot control's data 00114 template <typename T> 00115 void ElasticRodKR<T>::CreateData ( unsigned char numKnotAllowed ) 00116 { 00117 // Set the three points for finding projection direction 00118 int i = 1; 00119 SetOfElasticRodNodes::iterator node = m_pNodeList->begin(); 00120 m_NodesForProjPoints[0] = &(*node); // the fist point 00121 for ( ; i < m_pParameters->NumOfNodes/2; ++i ) ++node; 00122 m_NodesForProjPoints[1] = &(*node); // the middle point 00123 for ( ; i < m_pParameters->NumOfNodes; ++i ) ++node; 00124 m_NodesForProjPoints[2] = &(*node); // the last point 00125 00126 m_iKnotStartPt = m_iKnotEndPt = -1; 00127 m_iMaxCrossingPairs = (m_pParameters->NumOfNodes-1)/2; 00128 m_iNumCrossingPairs = 0; 00129 m_iaCrossingCounters = new int[ m_pParameters->NumOfNodes-1 ]; 00130 m_iaDowkerNotation = new int[ m_iMaxCrossingPairs ]; 00131 00132 m_ucMaxNumKnotsAllowed = numKnotAllowed; 00133 m_pListOfLockedKnots = new IC_LockedKnot[ m_ucMaxNumKnotsAllowed ]; 00134 m_puiLengthThresholds = new unsigned int[ m_ucMaxNumKnotsAllowed ]; 00135 { 00136 m_tWaitTime = 2.0;//5.0; // set wait time 00137 m_uiCounterThreshold = 10;//25; // act as a timer for fixing the current knot 00138 m_uiMinLengthThreshold = 0; // start at zero 00139 m_puiLengthThresholds[0] = 20;//10; // length threshold for half knot -- basic knot 00140 // extra length threshold for double knot will be added by m_puiLengthThresholds[0]/2 00141 m_puiLengthThresholds[1] = 12;//8; // extra length threshold for double knot 00142 // i.e. for double knot the length threshold is 18 (of half knot) + 8 00143 00144 // The rest of the threshold lengths 00145 for ( int i = 2; i < m_ucMaxNumKnotsAllowed; ++i ) { 00146 m_puiLengthThresholds[i] = 8; 00147 } 00148 } 00149 00150 Reset(); 00151 } 00152 00153 00154 // Delete the knot control's data 00155 template <typename T> 00156 void ElasticRodKR<T>::DeleteData () 00157 { 00158 if ( m_iaCrossingCounters ) { 00159 delete [] m_iaCrossingCounters; 00160 m_iaCrossingCounters = NULL; 00161 } 00162 if ( m_iaDowkerNotation ) { 00163 delete [] m_iaDowkerNotation; 00164 m_iaDowkerNotation = NULL; 00165 } 00166 00167 if ( m_pListOfLockedKnots ) { 00168 delete [] m_pListOfLockedKnots; 00169 m_pListOfLockedKnots = NULL; 00170 } 00171 00172 if ( m_puiLengthThresholds ) { 00173 delete [] m_puiLengthThresholds; 00174 m_puiLengthThresholds = NULL; 00175 } 00176 } 00177 00178 00179 // Initialize this knot control 00180 template <typename T> 00181 void ElasticRodKR<T>::Init ( unsigned char numKnotAllowed ) 00182 { 00183 DeleteData(); 00184 CreateData( numKnotAllowed ); 00185 } 00186 00187 00188 // Reset this knot control 00189 template <typename T> 00190 void ElasticRodKR<T>::Reset () 00191 { 00192 m_ucKnotCount = 0; 00193 for ( int i = 0; i < m_ucMaxNumKnotsAllowed; ++i ) { 00194 m_pListOfLockedKnots[i].Reset(); 00195 00196 } 00197 m_uiCounterForFixingKnot = 0; // reset counter 00198 m_uiMinLengthThreshold = 0; // reset min length threshold 00199 ResetElapsedTime(); 00200 m_uiLengthAccumulateTarget = m_puiLengthThresholds[0]; // reset accumulated target length 00201 m_ucTrackingKnot = Data::DatabaseDowkerNotation::UNDEFINED; // reset tracker 00202 00203 #ifdef TAPs_ADD_ANIMATED_KNOTS 00204 m_ListOfAnimatedKnot.clear(); 00205 //DoneAnimatingKnot(); 00206 #endif//TAPs_ADD_ANIMATED_KNOTS 00207 00208 m_iMinPtIdThatIsInRecordedKnots = -1; 00209 m_iMaxPtIdThatIsInRecordedKnots = -1; 00210 } 00211 00212 00213 template <typename T> 00214 void ElasticRodKR<T>::GetCurrentTrackingKnot_StartAndEndLinkIDs ( 00215 int & startLink, 00216 int & endLink 00217 ) 00218 { 00219 if ( m_ucTrackingKnot == Data::DatabaseDowkerNotation::UNDEFINED ) { 00220 startLink = endLink = -1; 00221 } 00222 else { 00223 startLink = m_KnotLinkStartTempRecord; 00224 endLink = m_KnotLinkEndTempRecord; 00225 } 00226 } 00227 00228 00229 template <typename T> 00230 int ElasticRodKR<T>::ConverseDowkerNotationToKnotName ( std::string * knotName ) 00231 { 00232 // Find the knot that match with the Dowker notation 00233 int knotID = Data::DatabaseDowkerNotation::FindKnotOfDowkerNotation( m_iNumCrossingPairs, m_iaDowkerNotation, knotName ); 00234 00235 // Include the Dowker notation in the return string 00236 if ( knotName ) { 00237 if ( knotID >= 0 ) { 00238 *knotName = Data::DatabaseDowkerNotation::GetStrEntry( knotID ); 00239 } 00240 else { 00241 *knotName = "n/a"; 00242 } 00243 } 00244 return knotID; // return -1 if not found, otherwise return the knotID 00245 } 00246 00247 00248 // Check if a part of the elastic rod forms the surgeon knot 00249 template <typename T> 00250 std::string ElasticRodKR<T>::CheckSurgeonsKnot () 00251 { 00252 std::string str = ""; 00253 static std::string name; 00254 00255 // 00256 // DEBUG -- For checking knot lock thresholds 00257 // 00258 //std::stringstream ss; 00259 //ss << "Knot_Fixing_Threshold (" << m_uiCounterThreshold << "): " << m_uiCounterForFixingKnot; 00260 //ss << " Knot_Waiting_Time_Threshold (" << m_tWaitTime << "): " << m_tAccTime << " "; 00261 //str += ss.str(); 00262 00263 // Recognize the knot 00264 //* 00265 if ( m_ucTrackingKnot == Data::DatabaseDowkerNotation::UNDEFINED ) { 00266 00267 CheckSelfCrossingForKnotRecognition( GetProjDirection() ); 00268 int start = GetKnotStartPt(); 00269 int end = GetKnotEndPt(); 00270 00271 // Check if a new knot is being formed 00272 m_ucTrackingKnot = ConverseDowkerNotationToKnotName( &name ); 00273 00274 // Initially record the knot length (start and end) 00275 if ( m_ucTrackingKnot != Data::DatabaseDowkerNotation::UNDEFINED ) { 00276 m_KnotLinkStartTempRecord = start; 00277 m_KnotLinkEndTempRecord = end; 00278 } 00279 00280 // Recognize the knot -- Total Knots is One 00281 if ( m_ucKnotCount == 1 ) { 00282 str += GetNameOfKnot( 0, false ); // 2nd parameter: true with (-)/(+) for direction 00283 str += " Knot"; 00284 //str = "One Knot"; 00285 } 00286 00287 // Recognize the knot -- Total Knots is Two 00288 else if ( m_ucKnotCount == 2 ) { 00289 //----------------------------------- 00290 // Check Surgeon's Knot (NEG-then-POS or POS-then-NEG) 00291 if ( 00292 // neg double then pos half equals surgeon's knot 00293 ( m_pListOfLockedKnots[0].ID == Data::DatabaseDowkerNotation::DOUBLE_NEG 00294 && m_pListOfLockedKnots[1].ID == Data::DatabaseDowkerNotation::HALF_POS ) 00295 || 00296 // pos double then neg half equals surgeon's knot 00297 ( m_pListOfLockedKnots[0].ID == Data::DatabaseDowkerNotation::DOUBLE_POS 00298 && m_pListOfLockedKnots[1].ID == Data::DatabaseDowkerNotation::HALF_NEG ) 00299 ) { 00300 str += "Surgeon's Knot"; 00301 } 00302 //----------------------------------- 00303 // Check Surgeon's Knot (NEG-then-NEG or POS-then-POS) 00304 else if ( 00305 // neg double then pos half equals surgeon's knot 00306 ( m_pListOfLockedKnots[0].ID == Data::DatabaseDowkerNotation::DOUBLE_NEG 00307 && m_pListOfLockedKnots[1].ID == Data::DatabaseDowkerNotation::HALF_NEG ) 00308 || 00309 // pos double then neg half equals surgeon's knot 00310 ( m_pListOfLockedKnots[0].ID == Data::DatabaseDowkerNotation::DOUBLE_POS 00311 && m_pListOfLockedKnots[1].ID == Data::DatabaseDowkerNotation::HALF_POS ) 00312 ) { 00313 str += "Granny Double Knot"; 00314 } 00315 //----------------------------------- 00316 // Check Square Knot (NEG-then-POS or POS-then-NEG) 00317 else if ( 00318 // neg half then pos half equals square knot 00319 ( m_pListOfLockedKnots[0].ID == Data::DatabaseDowkerNotation::HALF_NEG 00320 && m_pListOfLockedKnots[1].ID == Data::DatabaseDowkerNotation::HALF_POS ) 00321 || 00322 // pos half then neg half equals square knot 00323 ( m_pListOfLockedKnots[0].ID == Data::DatabaseDowkerNotation::HALF_POS 00324 && m_pListOfLockedKnots[1].ID == Data::DatabaseDowkerNotation::HALF_NEG ) 00325 ) { 00326 str += "Square Knot"; 00327 } 00328 //----------------------------------- 00329 // Check Square Knot (NEG-then-NEG or POS-then-POS) 00330 else if ( 00331 // neg half then pos half equals square knot 00332 ( m_pListOfLockedKnots[0].ID == Data::DatabaseDowkerNotation::HALF_NEG 00333 && m_pListOfLockedKnots[1].ID == Data::DatabaseDowkerNotation::HALF_NEG ) 00334 || 00335 // pos half then neg half equals square knot 00336 ( m_pListOfLockedKnots[0].ID == Data::DatabaseDowkerNotation::HALF_POS 00337 && m_pListOfLockedKnots[1].ID == Data::DatabaseDowkerNotation::HALF_POS ) 00338 ) { 00339 str += "Granny Knot"; 00340 } 00341 //----------------------------------- 00342 // Unrecognized Knot Combination 00343 else { 00344 char s[16]; 00345 str += _itoa( m_ucKnotCount, s, 10 ); 00346 str += " knot combination: "; 00347 00348 //* 00349 #ifdef TAPs_STRAND_DEBUG 00350 for ( int i = 0; i < m_ucKnotCount; ++i ) { 00351 str += GetNameOfKnot( i, true ); // 2nd parameter: true with (-)/(+) for direction 00352 if ( i < m_ucKnotCount-1 ) str += ", "; 00353 } 00354 #endif//TAPs_STRAND_DEBUG 00355 //*/ 00356 str += GetStrNameForKnotCombination(); 00357 } 00358 } 00359 00360 // Recognize the knot -- Total Knots is Three 00361 else if ( m_ucKnotCount == 3 ) { 00362 //----------------------------------- 00363 // Check Surgeon's Knot (NEG-then-POS-then-NEG or POS-then-NEG-then-POS) 00364 if ( 00365 // neg double then pos half equals surgeon's knot 00366 ( m_pListOfLockedKnots[0].ID == Data::DatabaseDowkerNotation::DOUBLE_NEG 00367 && m_pListOfLockedKnots[1].ID == Data::DatabaseDowkerNotation::HALF_POS 00368 && m_pListOfLockedKnots[2].ID == Data::DatabaseDowkerNotation::HALF_NEG ) 00369 || 00370 // pos double then neg half equals surgeon's knot 00371 ( m_pListOfLockedKnots[0].ID == Data::DatabaseDowkerNotation::DOUBLE_POS 00372 && m_pListOfLockedKnots[1].ID == Data::DatabaseDowkerNotation::HALF_NEG 00373 && m_pListOfLockedKnots[2].ID == Data::DatabaseDowkerNotation::HALF_POS ) 00374 ) { 00375 str += "Square Surgeon's Knot"; 00376 } 00377 //----------------------------------- 00378 // Check Surgeon's Knot (NEG-then-NEG-then-NEG or POS-then-POS-then-POS) 00379 else if ( 00380 // neg double then pos half equals surgeon's knot 00381 ( m_pListOfLockedKnots[0].ID == Data::DatabaseDowkerNotation::DOUBLE_NEG 00382 && m_pListOfLockedKnots[1].ID == Data::DatabaseDowkerNotation::HALF_NEG 00383 && m_pListOfLockedKnots[2].ID == Data::DatabaseDowkerNotation::HALF_NEG ) 00384 || 00385 // pos double then neg half equals surgeon's knot 00386 ( m_pListOfLockedKnots[0].ID == Data::DatabaseDowkerNotation::DOUBLE_POS 00387 && m_pListOfLockedKnots[1].ID == Data::DatabaseDowkerNotation::HALF_POS 00388 && m_pListOfLockedKnots[2].ID == Data::DatabaseDowkerNotation::HALF_POS ) 00389 ) { 00390 str += "Granny Granny Double Knot"; 00391 } 00392 //----------------------------------- 00393 // Check Square's Knot (NEG-then-POS-then-NEG or POS-then-NEG-then-POS) 00394 else if ( 00395 // neg double then pos half equals surgeon's knot 00396 ( m_pListOfLockedKnots[0].ID == Data::DatabaseDowkerNotation::HALF_NEG 00397 && m_pListOfLockedKnots[1].ID == Data::DatabaseDowkerNotation::HALF_POS 00398 && m_pListOfLockedKnots[2].ID == Data::DatabaseDowkerNotation::HALF_NEG ) 00399 || 00400 // pos double then neg half equals surgeon's knot 00401 ( m_pListOfLockedKnots[0].ID == Data::DatabaseDowkerNotation::HALF_POS 00402 && m_pListOfLockedKnots[1].ID == Data::DatabaseDowkerNotation::HALF_NEG 00403 && m_pListOfLockedKnots[2].ID == Data::DatabaseDowkerNotation::HALF_POS ) 00404 ) { 00405 str += "Square Square Knot"; 00406 } 00407 //----------------------------------- 00408 // Check Square's Knot (NEG-then-NEG-then-NEG or POS-then-POS-then-POS) 00409 else if ( 00410 // neg double then pos half equals surgeon's knot 00411 ( m_pListOfLockedKnots[0].ID == Data::DatabaseDowkerNotation::HALF_NEG 00412 && m_pListOfLockedKnots[1].ID == Data::DatabaseDowkerNotation::HALF_NEG 00413 && m_pListOfLockedKnots[2].ID == Data::DatabaseDowkerNotation::HALF_NEG ) 00414 || 00415 // pos double then neg half equals surgeon's knot 00416 ( m_pListOfLockedKnots[0].ID == Data::DatabaseDowkerNotation::HALF_POS 00417 && m_pListOfLockedKnots[1].ID == Data::DatabaseDowkerNotation::HALF_POS 00418 && m_pListOfLockedKnots[2].ID == Data::DatabaseDowkerNotation::HALF_POS ) 00419 ) { 00420 str += "Granny Granny Knot"; 00421 } 00422 //----------------------------------- 00423 // Unrecognized Knot Combination 00424 else { 00425 char s[16]; 00426 str += _itoa( m_ucKnotCount, s, 10 ); 00427 str += " knot combination: "; 00428 00429 //* 00430 #ifdef TAPs_STRAND_DEBUG 00431 for ( int i = 0; i < m_ucKnotCount; ++i ) { 00432 str += GetNameOfKnot( i, true ); // 2nd parameter: true with (-)/(+) for direction 00433 if ( i < m_ucKnotCount-1 ) str += ", "; 00434 } 00435 #endif//TAPs_STRAND_DEBUG 00436 //*/ 00437 str += GetStrNameForKnotCombination(); 00438 } 00439 } 00440 00441 // Recognize the knot -- Total Knots is greater than three 00442 else { 00443 char s[16]; 00444 str += _itoa( m_ucKnotCount, s, 10 ); 00445 str += " knot combination: "; 00446 00447 //* 00448 #ifdef TAPs_STRAND_DEBUG 00449 for ( int i = 0; i < m_ucKnotCount; ++i ) { 00450 str += GetNameOfKnot( i, true ); // 2nd parameter: true with (-)/(+) for direction 00451 if ( i < m_ucKnotCount-1 ) str += ", "; 00452 } 00453 #endif//TAPs_STRAND_DEBUG 00454 //*/ 00455 str += GetStrNameForKnotCombination(); 00456 } 00457 } 00458 //*/ 00459 00460 // Track the current knot 00461 else { 00462 CheckSelfCrossingForKnotRecognition( GetProjDirection() ); 00463 int start = GetKnotStartPt(); 00464 int end = GetKnotEndPt(); 00465 00466 // Keep the new knot length 00467 if ( start > 0 || end > 0 ) { 00468 m_KnotLinkStartTempRecord = start; 00469 m_KnotLinkEndTempRecord = end; 00470 } 00471 00472 //------------------------------------------------- 00473 // Change tracking knot -- for a more complex knot 00474 00475 // Current tracked knot is a half knot 00476 if ( m_ucTrackingKnot == Data::DatabaseDowkerNotation::HALF_NEG 00477 || m_ucTrackingKnot == Data::DatabaseDowkerNotation::HALF_POS ) 00478 { 00479 // Check the current knot 00480 std::string name2; 00481 int knot = ConverseDowkerNotationToKnotName( &name2 ); 00482 00483 // The current knot is not a half knot 00484 if ( knot != Data::DatabaseDowkerNotation::UNDEFINED ) { 00485 // REMARK: 00486 // This change allows the knot to switch freely between 00487 // HALF_NEG and HALF_POS due to the result knot id from 00488 // Dowker notation. 00489 // This change is not allowed here. 00490 // So that the HALF knot (direction) will not be switched! 00491 //if ( knot == Data::DatabaseDowkerNotation::HALF_NEG 00492 // || knot == Data::DatabaseDowkerNotation::HALF_POS ) 00493 //{ 00494 // // Change from half knot to half knot 00495 // str = name = name2; 00496 // m_ucTrackingKnot = knot; 00497 //} 00498 //else 00499 00500 if ( knot == Data::DatabaseDowkerNotation::DOUBLE_NEG 00501 || knot == Data::DatabaseDowkerNotation::DOUBLE_POS ) 00502 { 00503 // Change from half knot to double knot 00504 str += name = name2; 00505 m_ucTrackingKnot = knot; 00506 // Add extra length threshold for the knot change 00507 m_uiLengthAccumulateTarget += m_puiLengthThresholds[0] / 2; 00508 } 00509 } 00510 } 00511 00512 //------------------------------------------------- 00513 // A new knot is formed or being tracked 00514 if ( m_ucTrackingKnot != Data::DatabaseDowkerNotation::UNDEFINED ) { 00515 00516 /* 00517 // Recovering from incorrect collision detection 00518 // Case when there was a knot then there is no crossing pairs 00519 if ( m_iNumCrossingPairs == 0 ) { 00520 m_ucTrackingKnot = Data::DatabaseDowkerNotation::UNDEFINED; 00521 str = "Recovering from an error!"; 00522 00523 m_uiCounterForFixingKnot = 0; 00524 ResetElapsedTime(); 00525 00526 // DEBUG 00527 //std::cout << "m_iNumCrossingPairs was ZERO!\n" << std::endl; 00528 } 00529 //*/ 00530 00531 // Recovering from incorrect collision detection 00532 // Case when there was a knot then there is no crossing pairs 00533 if ( m_iNumCrossingPairs == 0 ) { 00534 00535 // RECORD THE KNOT -- SPECIAL FOR BROKEN SIMULATION OF THE KNOT 00536 //------------------------------------------------- 00537 int knotLength = m_KnotLinkEndTempRecord - m_KnotLinkStartTempRecord; 00538 // Since the knot tracking is broken, then the locked knot length must be m_puiLengthThresholds[m_ucKnotCount] 00539 00540 std::stringstream ss; 00541 ss << "knotLength < m_puiLengthThresholds[m_ucKnotCount]?: " << knotLength << " < " << m_puiLengthThresholds[m_ucKnotCount] << "?"; 00542 wxMessageDialog( NULL, ss.str(), "Info", wxOK ); 00543 std::cout << ss.str() << "\n"; 00544 00545 if ( knotLength < static_cast<int>( m_puiLengthThresholds[m_ucKnotCount] ) ) { 00546 int diff = m_puiLengthThresholds[m_ucKnotCount] - knotLength; 00547 if ( diff % 2 == 0 ) { 00548 diff /= 2; 00549 m_KnotLinkStartTempRecord -= diff; 00550 m_KnotLinkEndTempRecord -= diff; 00551 } 00552 else { 00553 diff /= 2; 00554 m_KnotLinkStartTempRecord -= diff+1; 00555 m_KnotLinkEndTempRecord -= diff; 00556 } 00557 // Record knot ID and increase knot count 00558 RecordKnot( m_KnotLinkStartTempRecord-1, m_KnotLinkEndTempRecord+1, m_ucTrackingKnot ); 00559 // Reset counter and set the new accumulated target length for next knot 00560 m_uiCounterForFixingKnot = 0; 00561 ResetElapsedTime(); 00562 if ( static_cast<unsigned int>( knotLength ) > m_uiMinLengthThreshold ) { 00563 m_uiMinLengthThreshold = knotLength; // new min length 00564 } 00565 m_uiLengthAccumulateTarget = m_uiMinLengthThreshold + m_puiLengthThresholds[m_ucKnotCount]; 00566 // Reset tracking knot 00567 m_ucTrackingKnot = Data::DatabaseDowkerNotation::UNDEFINED; 00568 str += ""; 00569 //------------------------------- 00570 ResetStartTime(); 00571 return str; 00572 } 00573 else { 00574 m_ucTrackingKnot = Data::DatabaseDowkerNotation::UNDEFINED; 00575 str += "Recovering from an error!"; 00576 00577 m_uiCounterForFixingKnot = 0; 00578 ResetElapsedTime(); 00579 } 00580 //------------------------------------------------- 00581 00582 } 00583 00584 char val[16]; 00585 str += "Tracking Knot# "; 00586 str += _itoa(m_ucKnotCount+1, val, 10); 00587 str += " (" + name + ")"; 00588 00589 str += " ID: "; 00590 str += _itoa(m_ucTrackingKnot, val, 10); 00591 00592 // DEBUG 00593 //std::cout << "end-start: " << end-start << " = " << end << " - " << start << "\n"; 00594 //std::cout << "TargetLength: " << m_uiLengthAccumulateTarget << "\n"; 00595 //std::cout << "CounterForFixingKnot: " << m_uiCounterForFixingKnot << "\n"; 00596 00597 //----------------------------------- 00598 // Skip invalid length 00599 if ( end < 0 || start < 0 ) { 00600 //++m_uiCounterForFixingKnot; 00601 // start = m_KnotLinkStartTempRecord; 00602 // end = m_KnotLinkEndTempRecord; 00603 } 00604 00605 //----------------------------------- 00606 // Track the first knot 00607 if ( m_ucKnotCount == 0 ) { 00608 int knotLength = end-start; 00609 if ( knotLength >= static_cast<int>( m_uiMinLengthThreshold ) || static_cast<int>( m_uiCounterForFixingKnot ) <= m_uiCounterThreshold ) 00610 { 00611 if ( knotLength < static_cast<int>( m_uiLengthAccumulateTarget ) ) { 00612 // Reset counter and set new accumulated target length 00613 m_uiCounterForFixingKnot = 0; 00614 m_uiLengthAccumulateTarget = knotLength; 00615 ResetElapsedTime(); 00616 } 00617 // LOCK KNOT 00618 else if ( m_pParameters->EnableKR_LockKnots && ( knotLength <= static_cast<int>( m_uiLengthAccumulateTarget ) + 2 ) ) { 00619 if ( ++m_uiCounterForFixingKnot >= m_uiCounterThreshold ) { 00620 00621 // RECORD THE KNOT 00622 //------------------------------------------------- 00623 // Record knot ID and increase knot count 00624 RecordKnot( start-1, end+1, m_ucTrackingKnot ); 00625 // Reset counter and set the new accumulated target length for next knot 00626 m_uiCounterForFixingKnot = 0; 00627 ResetElapsedTime(); 00628 if ( knotLength >= static_cast<int>( m_uiMinLengthThreshold ) ) { 00629 m_uiMinLengthThreshold = knotLength; // new min length 00630 } 00631 m_uiLengthAccumulateTarget = m_uiMinLengthThreshold + m_puiLengthThresholds[m_ucKnotCount]; 00632 // Reset tracking knot 00633 m_ucTrackingKnot = Data::DatabaseDowkerNotation::UNDEFINED; 00634 str += ""; 00635 //------------------------------------------------- 00636 } 00637 } 00638 //*/ 00639 else { 00640 ++m_uiCounterForFixingKnot; 00641 AddElapsedTime(); 00642 } 00643 } 00644 } 00645 //----------------------------------- 00646 // Tracking the second, third, and so on 00647 else if ( 0 < m_ucKnotCount && m_ucKnotCount < m_ucMaxNumKnotsAllowed ) { 00648 int knotLength = end-start; 00649 if ( knotLength >= static_cast<int>( m_uiMinLengthThreshold ) || static_cast<int>( m_uiCounterForFixingKnot ) <= m_uiCounterThreshold ) { 00650 if ( knotLength < static_cast<int>( m_uiLengthAccumulateTarget ) ) { 00651 // Reset counter and set new accumulated target length 00652 m_uiCounterForFixingKnot = 0; 00653 m_uiLengthAccumulateTarget = knotLength; 00654 ResetElapsedTime(); 00655 } 00656 else if ( ( knotLength <= static_cast<int>( m_uiLengthAccumulateTarget ) + 2 ) || 00657 00658 ( IsTimeLimitReached() && knotLength <= static_cast<int>( m_uiLengthAccumulateTarget ) + 4 ) ) { 00659 00660 //(m_uiCounterForFixingKnot >= 125) ) { 00661 00662 #ifdef TAPs_STRAND_DEBUG 00663 if ( IsTimeLimitReached() ) { 00664 std::cout << "Elapsed Time: " << m_tAccTime << "\n"; 00665 } 00666 #endif//TAPs_STRAND_DEBUG 00667 00668 // LOCK KNOT 00669 if ( m_pParameters->EnableKR_LockKnots && ++m_uiCounterForFixingKnot >= m_uiCounterThreshold ) { 00670 00671 // RECORD THE KNOT 00672 //------------------------------------------------- 00673 // Record knot ID and increase knot count 00674 RecordKnot( start-1, end+1, m_ucTrackingKnot ); 00675 // Reset counter and set the new accumulated target length for next knot 00676 m_uiCounterForFixingKnot = 0; 00677 ResetElapsedTime(); 00678 if ( knotLength >= static_cast<int>( m_uiMinLengthThreshold ) ) { 00679 m_uiMinLengthThreshold = knotLength; // new min length 00680 } 00681 m_uiLengthAccumulateTarget = m_uiMinLengthThreshold + m_puiLengthThresholds[m_ucKnotCount]; 00682 // Reset tracking knot 00683 m_ucTrackingKnot = Data::DatabaseDowkerNotation::UNDEFINED; 00684 str += ""; 00685 //------------------------------------------------- 00686 00687 } 00688 //*/ 00689 } 00690 else { 00691 ++m_uiCounterForFixingKnot; 00692 AddElapsedTime(); 00693 } 00694 } 00695 } 00696 } 00697 //std::cout << "Acc Time: " << m_tAccTime << "\n"; 00698 } 00699 ResetStartTime(); 00700 return str; 00701 } 00702 00703 00704 // Record a knot 00705 template <typename T> 00706 void ElasticRodKR<T>::RecordKnot ( int startLink, int endLink, int knotID ) 00707 { 00708 int startLoopLink = ( endLink - startLink )/2 + startLink; 00709 int endLoopLink = startLoopLink + 1; 00710 00711 RecordKnot( startLink, startLoopLink, endLoopLink, endLink, knotID ); 00712 00713 } 00714 00715 00716 // Record a knot with flexible knot loop part 00717 template <typename T> 00718 void ElasticRodKR<T>::RecordKnot ( int startLink, int startLoopLink, int endLoopLink, int endLink, int knotID ) 00719 { 00720 // 00721 // Store the min and max of point IDs that belong to recorded knots 00722 // 00723 if ( m_iMinPtIdThatIsInRecordedKnots > startLink || m_iMinPtIdThatIsInRecordedKnots < 0 ) { 00724 m_iMinPtIdThatIsInRecordedKnots = startLink; 00725 } 00726 if ( m_iMaxPtIdThatIsInRecordedKnots < endLink ) { 00727 m_iMaxPtIdThatIsInRecordedKnots = endLink; 00728 } 00729 00730 // 00731 // Record the knot 00732 // 00733 m_pListOfLockedKnots[m_ucKnotCount].ID = knotID; 00734 m_pListOfLockedKnots[m_ucKnotCount].StartLinkID = startLink; 00735 m_pListOfLockedKnots[m_ucKnotCount].StartLoopLinkID = startLoopLink; 00736 m_pListOfLockedKnots[m_ucKnotCount].EndLoopLinkID = endLoopLink; 00737 m_pListOfLockedKnots[m_ucKnotCount].EndLinkID = endLink; 00738 ++m_ucKnotCount; 00739 // 00740 // Set the status of all links forming the knot to "CLUSTERED" 00741 int count = 0; 00742 SetOfElasticRodNodes::iterator currNode = m_pNodeList->begin(); 00743 while ( currNode != m_pNodeList->end() ) { 00744 if ( ( startLink <= count && count <= startLoopLink ) 00745 || ( endLoopLink <= count && count <= endLink ) ) 00746 { 00747 currNode->SimFlags.SetSimulationConstraints( Enum::AddOn::CLUSTERED ); 00748 00749 // DEBUG 00750 //currNode->SimFlags.SetSimulationConstraints( Enum::AddOn::FIXED ); 00751 } 00752 ++count; 00753 ++currNode; 00754 } 00755 } 00756 00757 00758 // Create a knot (shape) from a set of links 00759 template <typename T> 00760 void ElasticRodKR<T>::CombineTwoKnots ( 00761 int startLockedKnotID, 00762 Data::DatabaseDowkerNotation::KNOT knotType, 00763 Matrix4x4<T> const & orientation 00764 ) 00765 { 00766 const T angleDeg = 30; 00767 00768 T angle = angleDeg * Math<T>::DEG_TO_RAD; 00769 T cos_X = cos( angle ); 00770 T sin_Y = sin( angle ); 00771 T dx = cos_X * m_pParameters->LinkLength; 00772 T dy = sin_Y * m_pParameters->LinkLength; 00773 T dy2 = dy * 2; // for raising the 2nd knot in y-direction 00774 T dz = m_pParameters->Radius; 00775 T dz2 = dz * 2; 00776 T x1, x2, y1, y2, z1, z2, z1_2, z2_2; 00777 int numOfCrossings_1; // the 1st knot adjacent to the combined knot's loop 00778 int numOfCrossings_2; // the 2nd knot on top of the 1st knot 00779 00780 // 00781 // Setting up the 1st knot 00782 // 00783 00784 // REMARK: 00785 // From the view point the 2nd knot is 180 degree rotated from the first knot. 00786 // Therefore, z2 and z2_2 values for the 2nd knot have to be multiplied by -1. 00787 // Hence, for example, HALF_NEG_FOLLOWED_BY_HALF_POS which has 00788 // the 1st knot of HALF_NEG followed by the 2nd knot of HALF_POS. 00789 // The z values for forming the 1st knot are set same as setting up a HALF_NEG knot, 00790 // but the z values of the 2nd knot are set same as setting up a HALF_NEG knot, 00791 // due to the 180 degree rotation. 00792 00793 // Set suture's node offsets for creating the knot shape 00794 switch ( knotType ) { 00795 00796 case Data::DatabaseDowkerNotation::DOUBLE_NEG_FOLLOWED_BY_HALF_NEG: 00797 numOfCrossings_1 = 5; 00798 z1 = dz; 00799 z1_2 = dz2; 00800 numOfCrossings_2 = 3; 00801 z2 = -dz; 00802 z2_2 = -dz2; 00803 break; 00804 00805 case Data::DatabaseDowkerNotation::DOUBLE_NEG_FOLLOWED_BY_HALF_POS: 00806 numOfCrossings_1 = 5; 00807 z1 = dz; 00808 z1_2 = dz2; 00809 numOfCrossings_2 = 3; 00810 z2 = dz; 00811 z2_2 = dz2; 00812 break; 00813 00814 case Data::DatabaseDowkerNotation::DOUBLE_POS_FOLLOWED_BY_HALF_NEG: 00815 numOfCrossings_1 = 5; 00816 z1 = -dz; 00817 z1_2 = -dz2; 00818 numOfCrossings_2 = 3; 00819 z2 = -dz; 00820 z2_2 = -dz2; 00821 break; 00822 00823 case Data::DatabaseDowkerNotation::DOUBLE_POS_FOLLOWED_BY_HALF_POS: 00824 numOfCrossings_1 = 5; 00825 z1 = -dz; 00826 z1_2 = -dz2; 00827 numOfCrossings_2 = 3; 00828 z2 = dz; 00829 z2_2 = dz2; 00830 break; 00831 00832 case Data::DatabaseDowkerNotation::HALF_NEG_FOLLOWED_BY_HALF_NEG: 00833 numOfCrossings_1 = 3; 00834 z1 = dz; 00835 z1_2 = dz2; 00836 numOfCrossings_2 = 3; 00837 z2 = -dz; 00838 z2_2 = -dz2; 00839 break; 00840 00841 case Data::DatabaseDowkerNotation::HALF_POS_FOLLOWED_BY_HALF_NEG: 00842 numOfCrossings_1 = 3; 00843 z1 = -dz; 00844 z1_2 = -dz2; 00845 numOfCrossings_2 = 3; 00846 z2 = -dz; 00847 z2_2 = -dz2; 00848 break; 00849 00850 case Data::DatabaseDowkerNotation::HALF_POS_FOLLOWED_BY_HALF_POS: 00851 numOfCrossings_1 = 3; 00852 z1 = -dz; 00853 z1_2 = -dz2; 00854 numOfCrossings_2 = 3; 00855 z2 = dz; 00856 z2_2 = dz2; 00857 break; 00858 00859 case Data::DatabaseDowkerNotation::HALF_NEG_FOLLOWED_BY_HALF_POS: 00860 default: // same as HALF_NEG_FOLLOWED_BY_HALF_POS 00861 numOfCrossings_1 = 3; 00862 z1 = dz; 00863 z1_2 = dz2; 00864 numOfCrossings_2 = 3; 00865 z2 = dz; 00866 z2_2 = dz2; 00867 break; 00868 } 00869 y1 = dy; 00870 y2 = dy; 00871 x1 = dx * numOfCrossings_1; 00872 x2 = -dx * numOfCrossings_2; 00873 int twiceNumOfCrossings_1 = numOfCrossings_1 * 2; 00874 int twiceNumOfCrossings_2 = numOfCrossings_2 * 2; 00875 00876 // DEBUG 00877 //std::cout << "twiceNumOfCrossings_1: " << twiceNumOfCrossings_1 << "\n"; 00878 //std::cout << "twiceNumOfCrossings_2: " << twiceNumOfCrossings_2 << "\n"; 00879 00880 //int knotShapeLength = twiceNumOfCrossings_1 + twiceNumOfCrossings_2; 00881 //int startLoopLinkID = startLinkID + knotShapeLength; 00882 //int endLoopLinkID = endLinkID - knotShapeLength; 00883 //int knotIDStart_1 = startLoopLinkID - twiceNumOfCrossings_1; 00884 //int knotIDEnd_1 = endLoopLinkID + twiceNumOfCrossings_1; 00885 //int knotIDStart_2 = knotIDStart_1 - twiceNumOfCrossings_2; 00886 //int knotIDEnd_2 = knotIDEnd_1 + twiceNumOfCrossings_2; 00887 00888 int startLoopLinkID = m_pListOfLockedKnots[startLockedKnotID].StartLoopLinkID; 00889 int endLoopLinkID = m_pListOfLockedKnots[startLockedKnotID].EndLoopLinkID; 00890 int knotIDStart_1 = startLoopLinkID - twiceNumOfCrossings_1; 00891 int knotIDEnd_1 = endLoopLinkID + twiceNumOfCrossings_1; 00892 int knotIDStart_2 = knotIDStart_1 - twiceNumOfCrossings_2; 00893 int knotIDEnd_2 = knotIDEnd_1 + twiceNumOfCrossings_2; 00894 00895 00896 // 00897 // Calculate translation and orientation for the animated knot 00898 // 00899 //if ( m_pListOfLockedKnots[startLockedKnotID].GetStatusCalKnotPosition() ) { 00900 Vector3<T> center = ( (*m_pNodeList)[knotIDStart_2-1].Centerline[*m_pIdxNext].GetPosition() 00901 + (*m_pNodeList)[knotIDEnd_2+1].Centerline[*m_pIdxNext].GetPosition() ) * T(0.5); 00902 //Vector3<T> direction = ( (*m_pNodeList)[knotIDStart-1].Centerline[*m_pIdxNext].GetPosition() 00903 // - (*m_pNodeList)[knotIDEnd+1].Centerline[*m_pIdxNext].GetPosition() ).GetUnit(); 00904 //Matrix4x4<T> orientation = CGMath<T>::CreateRotationMatrix4x4FromVectorAtoVectorB( CGMath<T>::VectorX, direction ); 00905 //} 00906 00907 // 00908 // Create the 1st knot shape from the constrained links 00909 // 00910 00911 int s = knotIDStart_1; 00912 int e = knotIDEnd_1 - twiceNumOfCrossings_1; 00913 Vector3<T> posS, posE; 00914 for ( int i = 0; i <= twiceNumOfCrossings_1; ) 00915 { 00916 { 00917 posS = (orientation * Vector4<T>( x1, y1, z1, 1)).GetVector3() + center; 00918 posE = (orientation * Vector4<T>( x1,-y1,-z1, 1)).GetVector3() + center; 00919 (*m_pNodeList)[s].Centerline[*m_pIdxNext].SetPosition( posS ); 00920 (*m_pNodeList)[e].Centerline[*m_pIdxNext].SetPosition( posE ); 00921 (*m_pNodeList)[s].Centerline[*m_pIdxCurr].SetPosition( posS ); 00922 (*m_pNodeList)[e].Centerline[*m_pIdxCurr].SetPosition( posE ); 00923 } 00924 ++i; ++s; ++e; 00925 x1 -= dx; 00926 00927 if ( i < twiceNumOfCrossings_1 ) 00928 { 00929 posS = (orientation * Vector4<T>( x1, 0, z1_2, 1)).GetVector3() + center; 00930 posE = (orientation * Vector4<T>( x1, 0,-z1_2, 1)).GetVector3() + center; 00931 (*m_pNodeList)[s].Centerline[*m_pIdxNext].SetPosition( posS ); 00932 (*m_pNodeList)[e].Centerline[*m_pIdxNext].SetPosition( posE ); 00933 (*m_pNodeList)[s].Centerline[*m_pIdxCurr].SetPosition( posS ); 00934 (*m_pNodeList)[e].Centerline[*m_pIdxCurr].SetPosition( posE ); 00935 } 00936 ++i; ++s; ++e; 00937 x1 -= dx; 00938 y1 = -y1; 00939 z1 = -z1; 00940 z1_2 = -z1_2; 00941 } 00942 00943 // 00944 // Create the 2nd knot shape from the constrained links 00945 // 00946 //Matrix4x4<T> orientation2 = orientation * CGMath<T>::CreateRotationMatrix4x4( 1, 0, 0, 180 ); 00947 center[1] += dy2; 00948 s = knotIDStart_2; 00949 e = knotIDEnd_2 - twiceNumOfCrossings_2; 00950 for ( int i = 0; i <= twiceNumOfCrossings_2; ) 00951 { 00952 { 00953 posS = (orientation * Vector4<T>( x2, y2, z2, 1)).GetVector3() + center; 00954 posE = (orientation * Vector4<T>( x2,-y2,-z2, 1)).GetVector3() + center; 00955 (*m_pNodeList)[s].Centerline[*m_pIdxNext].SetPosition( posS ); 00956 (*m_pNodeList)[e].Centerline[*m_pIdxNext].SetPosition( posE ); 00957 (*m_pNodeList)[s].Centerline[*m_pIdxCurr].SetPosition( posS ); 00958 (*m_pNodeList)[e].Centerline[*m_pIdxCurr].SetPosition( posE ); 00959 } 00960 ++i; ++s; ++e; 00961 x2 += dx; 00962 00963 if ( i < twiceNumOfCrossings_2 ) 00964 { 00965 posS = (orientation * Vector4<T>( x2, 0, z2_2, 1)).GetVector3() + center; 00966 posE = (orientation * Vector4<T>( x2, 0,-z2_2, 1)).GetVector3() + center; 00967 (*m_pNodeList)[s].Centerline[*m_pIdxNext].SetPosition( posS ); 00968 (*m_pNodeList)[e].Centerline[*m_pIdxNext].SetPosition( posE ); 00969 (*m_pNodeList)[s].Centerline[*m_pIdxCurr].SetPosition( posS ); 00970 (*m_pNodeList)[e].Centerline[*m_pIdxCurr].SetPosition( posE ); 00971 } 00972 ++i; ++s; ++e; 00973 x2 += dx; 00974 y2 = -y2; 00975 z2 = -z2; 00976 z2_2 = -z2_2; 00977 } 00978 00982 //s = startLoopLinkID + 1; 00983 //e = endLoopLinkID - 1; 00984 //int m = ( e - s ) / 2; 00985 //... 00986 00987 // 00988 // Combined locked knots into one locked knot, start at startLockedKnotID 00989 // 00990 { 00991 int numOfCombinedKnots = m_ucKnotCount - startLockedKnotID; 00992 if ( numOfCombinedKnots <= 1 ) return; 00993 numOfCombinedKnots = 2; 00994 00995 m_ucKnotCount -= numOfCombinedKnots - 1; 00996 m_pListOfLockedKnots[startLockedKnotID].ID = knotType; 00997 m_pListOfLockedKnots[startLockedKnotID].StartLinkID = knotIDStart_2; 00998 m_pListOfLockedKnots[startLockedKnotID].StartLoopLinkID = startLoopLinkID; 00999 m_pListOfLockedKnots[startLockedKnotID].EndLoopLinkID = endLoopLinkID; 01000 m_pListOfLockedKnots[startLockedKnotID].EndLinkID = knotIDEnd_2; 01001 01002 int i = knotIDStart_2; 01003 for ( ; i < startLoopLinkID; ++i ) { 01004 (*m_pNodeList)[i].SimFlags.SetSimulationConstraints( Enum::AddOn::CLUSTERED ); 01005 } 01006 for ( ; i <= endLoopLinkID; ++i ) { 01007 (*m_pNodeList)[i].SimFlags.ClearSimulationConstraints( Enum::AddOn::CLUSTERED ); 01008 } 01009 for ( ; i <= knotIDEnd_2; ++i ) { 01010 (*m_pNodeList)[i].SimFlags.SetSimulationConstraints( Enum::AddOn::CLUSTERED ); 01011 } 01012 } 01013 /* 01014 // For multiple knots 01015 { 01016 int numOfCombinedKnots = m_ucKnotCount - startLockedKnotID; 01017 if ( numOfCombinedKnots <= 1 ) return; 01018 01019 int i = startLockedKnotID; 01020 int startLinkID = m_pListOfLockedKnots[i].StartLinkID; 01021 int startLoopLinkID = m_pListOfLockedKnots[i].StartLoopLinkID; 01022 int endLoopLinkID = m_pListOfLockedKnots[i].EndLoopLinkID; 01023 int endLinkID = m_pListOfLockedKnots[i].EndLinkID; 01024 for ( ++i; i < startLockedKnotID + numOfCombinedKnots; ++i ) { 01025 if ( m_pListOfLockedKnots[i].StartLinkID < startLinkID ) startLinkID = m_pListOfLockedKnots[i].StartLinkID; 01026 if ( m_pListOfLockedKnots[i].StartLoopLinkID > startLoopLinkID ) startLoopLinkID = m_pListOfLockedKnots[i].StartLoopLinkID; 01027 if ( m_pListOfLockedKnots[i].EndLoopLinkID < endLoopLinkID ) endLoopLinkID = m_pListOfLockedKnots[i].EndLoopLinkID; 01028 if ( m_pListOfLockedKnots[i].EndLinkID > endLinkID ) endLinkID = m_pListOfLockedKnots[i].EndLinkID; 01029 } 01030 m_ucKnotCount -= numOfCombinedKnots - 1; 01031 m_pListOfLockedKnots[startLockedKnotID].ID = knotType; 01032 m_pListOfLockedKnots[startLockedKnotID].StartLinkID = startLinkID; 01033 m_pListOfLockedKnots[startLockedKnotID].StartLoopLinkID = startLoopLinkID-2; 01034 m_pListOfLockedKnots[startLockedKnotID].EndLoopLinkID = endLoopLinkID+2; 01035 m_pListOfLockedKnots[startLockedKnotID].EndLinkID = endLinkID; 01036 } 01037 //*/ 01038 } 01039 01040 01041 // Constraint knots (forcing all links forming each knot to move as a unit) 01042 template <typename T> 01043 void ElasticRodKR<T>::ConstrainKnots () 01044 { 01045 // For each locked knot 01046 for ( int i = 0; i < m_ucKnotCount; ++i ) { 01047 Quaternion<T> ori_o( 0, 0, 0, 0 ); 01048 Quaternion<T> ori_n( 0, 0, 0, 0 ); 01049 Vector3<T> pos_o( 0, 0, 0 ); 01050 Vector3<T> pos_n( 0, 0, 0 ); 01051 Vector3<T> vel_o( 0, 0, 0 ); 01052 Vector3<T> vel_n( 0, 0, 0 ); 01053 int div = 0; 01054 01055 // There is at least one pickd point 01056 bool IsThereAtLeastOneEnforcedPosPt = false; 01057 01058 // Sum up 01059 //for ( int n = m_pListOfLockedKnots[i].StartLinkID; n <= m_pListOfLockedKnots[i].EndLinkID; ++n ) { 01060 for ( int n = m_pListOfLockedKnots[i].StartLinkID; n <= m_pListOfLockedKnots[i].StartLoopLinkID; ++n ) { 01061 //if ( !(*m_pNodeList)[n].SimFlags.CheckSimulationConstraints( Enum::AddOn::FIXED ) ) 01062 { 01063 ori_o += (*m_pNodeList)[n].Orientation[*m_pIdxCurr]; 01064 ori_n += (*m_pNodeList)[n].Orientation[*m_pIdxNext]; 01065 pos_o += (*m_pNodeList)[n].Centerline[*m_pIdxCurr].GetPosition(); 01066 pos_n += (*m_pNodeList)[n].Centerline[*m_pIdxNext].GetPosition(); 01067 vel_o += (*m_pNodeList)[n].Centerline[*m_pIdxCurr].GetVelocity(); 01068 vel_n += (*m_pNodeList)[n].Centerline[*m_pIdxNext].GetVelocity(); 01069 ++div; 01070 01071 if ( (*m_pNodeList)[n].UseEnforcedPosition ) IsThereAtLeastOneEnforcedPosPt = true; 01072 } 01073 } 01074 for ( int n = m_pListOfLockedKnots[i].EndLoopLinkID; n <= m_pListOfLockedKnots[i].EndLinkID; ++n ) { 01075 //if ( !(*m_pNodeList)[n].SimFlags.CheckSimulationConstraints( Enum::AddOn::FIXED ) ) 01076 { 01077 ori_o += (*m_pNodeList)[n].Orientation[*m_pIdxCurr]; 01078 ori_n += (*m_pNodeList)[n].Orientation[*m_pIdxNext]; 01079 pos_o += (*m_pNodeList)[n].Centerline[*m_pIdxCurr].GetPosition(); 01080 pos_n += (*m_pNodeList)[n].Centerline[*m_pIdxNext].GetPosition(); 01081 vel_o += (*m_pNodeList)[n].Centerline[*m_pIdxCurr].GetVelocity(); 01082 vel_n += (*m_pNodeList)[n].Centerline[*m_pIdxNext].GetVelocity(); 01083 ++div; 01084 01085 if ( (*m_pNodeList)[n].UseEnforcedPosition ) IsThereAtLeastOneEnforcedPosPt = true; 01086 } 01087 } 01088 01089 // Averaging 01090 if ( div > 0 ) { 01091 ori_o *= T(1)/div; 01092 ori_n *= T(1)/div; 01093 pos_o /= div; 01094 pos_n /= div; 01095 vel_o /= div; 01096 vel_n /= div; 01097 if ( m_pListOfLockedKnots[i].DoLockLocation && !IsThereAtLeastOneEnforcedPosPt ) { 01098 pos_n += m_pListOfLockedKnots[i].Center - pos_o; 01099 } 01100 Quaternion<T> ori_change = ori_n - ori_o; 01101 Vector3<T> pos_change = pos_n - pos_o; 01102 Vector3<T> vel_change = vel_n - vel_o; 01103 //for ( int n = m_pListOfLockedKnots[i].StartLinkID; n <= m_pListOfLockedKnots[i].EndLinkID; ++n ) { 01104 for ( int n = m_pListOfLockedKnots[i].StartLinkID; n <= m_pListOfLockedKnots[i].StartLoopLinkID; ++n ) { 01105 (*m_pNodeList)[n].Centerline[*m_pIdxNext].SetVelocity( (*m_pNodeList)[n].Centerline[*m_pIdxCurr].GetVelocity() + vel_change ); 01106 (*m_pNodeList)[n].Centerline[*m_pIdxNext].SetPosition( (*m_pNodeList)[n].Centerline[*m_pIdxCurr].GetPosition() + pos_change ); 01107 (*m_pNodeList)[n].Orientation[*m_pIdxNext] = (*m_pNodeList)[n].Orientation[*m_pIdxCurr] + ori_change; 01108 (*m_pNodeList)[n].Orientation[*m_pIdxNext].Normalized(); 01109 } 01110 for ( int n = m_pListOfLockedKnots[i].EndLoopLinkID; n <= m_pListOfLockedKnots[i].EndLinkID; ++n ) { 01111 (*m_pNodeList)[n].Centerline[*m_pIdxNext].SetVelocity( (*m_pNodeList)[n].Centerline[*m_pIdxCurr].GetVelocity() + vel_change ); 01112 (*m_pNodeList)[n].Centerline[*m_pIdxNext].SetPosition( (*m_pNodeList)[n].Centerline[*m_pIdxCurr].GetPosition() + pos_change ); 01113 (*m_pNodeList)[n].Orientation[*m_pIdxNext] = (*m_pNodeList)[n].Orientation[*m_pIdxCurr] + ori_change; 01114 (*m_pNodeList)[n].Orientation[*m_pIdxNext].Normalized(); 01115 } 01116 } 01117 } 01118 } 01119 01120 01121 /* 01122 // Get an approximate center of knot i 01123 template <typename T> 01124 void ElasticRodKR<T>::GetApproxKnotCenterAndOrientation ( unsigned int i, Vector3<T> ¢er, Quaternion<T> &orientation ) 01125 { 01126 if ( i >= GetKnotCount() ) return; 01127 01128 // Averaging all positions as an approximate center 01129 int div = 0; 01130 for ( int n = m_pListOfLockedKnots[i].StartLinkID; n <= m_pListOfLockedKnots[i].EndLinkID; ++n ) 01131 { 01132 center += (*m_pNodeList)[n].Centerline[*m_pIdxNext].GetPosition(); 01133 ++div; 01134 } 01135 // Averaging 01136 if ( div > 0 ) { 01137 center /= div; 01138 } 01139 } 01140 //*/ 01141 01142 01143 // Return the name of a knot 01144 template <typename T> 01145 std::string ElasticRodKR<T>::GetNameOfKnot ( unsigned int i, bool withPosOrNegPostfix ) 01146 { 01147 if ( i >= m_ucKnotCount ) return "n\a"; 01148 if ( withPosOrNegPostfix ) { 01149 if ( m_pListOfLockedKnots[i].ID % 2 == 0 ) { 01150 return Data::DatabaseDowkerNotation::GetKnotName( m_pListOfLockedKnots[i].ID ) + "(-)"; 01151 } 01152 else { 01153 return Data::DatabaseDowkerNotation::GetKnotName( m_pListOfLockedKnots[i].ID ) + "(+)"; 01154 } 01155 } 01156 return Data::DatabaseDowkerNotation::GetKnotName( m_pListOfLockedKnots[i].ID ); 01157 } 01158 01159 01160 // Return the name of a knot combination 01161 template <typename T> 01162 std::string ElasticRodKR<T>::GetStrNameForKnotCombination () 01163 { 01164 std::string str; 01165 for ( int i = 1; i < m_ucKnotCount; ++i ) { 01166 if ( m_pListOfLockedKnots[i-1].ID == 0 ) { 01167 if ( m_pListOfLockedKnots[i].ID == 0 ) { 01168 str = "Granny " + str; 01169 } 01170 else if ( m_pListOfLockedKnots[i].ID == 1 ) { 01171 str = "Square " + str; 01172 } 01173 } 01174 else if ( m_pListOfLockedKnots[i-1].ID == 1 ) { 01175 if ( m_pListOfLockedKnots[i].ID == 1 ) { 01176 str = "Granny " + str; 01177 } 01178 else if ( m_pListOfLockedKnots[i].ID == 0 ) { 01179 str = "Square " + str; 01180 } 01181 } 01182 } 01183 return str + " Knot"; 01184 } 01185 01186 01188 template <typename T> 01189 bool ElasticRodKR<T>::SetKnotControlThreshold ( enum Threshold thdID, T val ) 01190 { 01191 if ( val < 0.0 ) return false; 01192 switch ( thdID ) { 01193 case THRESHOLD_FOR_FIXING_KNOT: 01194 m_uiCounterThreshold = static_cast< unsigned int >( val ); 01195 return true; 01196 case THRESHOLD_WAIT_TIME: 01197 m_tWaitTime = val; 01198 return true; 01199 case LENGTH_THRESHOLD_0: 01200 m_puiLengthThresholds[0] = static_cast< unsigned int >( val ); 01201 return true; 01202 case LENGTH_THRESHOLD_1: 01203 m_puiLengthThresholds[1] = static_cast< unsigned int >( val ); 01204 return true; 01205 case LENGTH_THRESHOLD_2: 01206 m_puiLengthThresholds[2] = static_cast< unsigned int >( val ); 01207 return true; 01208 case LENGTH_THRESHOLD_3: 01209 m_puiLengthThresholds[3] = static_cast< unsigned int >( val ); 01210 return true; 01211 case LENGTH_THRESHOLD_4: 01212 m_puiLengthThresholds[4] = static_cast< unsigned int >( val ); 01213 return true; 01214 case LENGTH_THRESHOLD_5: 01215 m_puiLengthThresholds[5] = static_cast< unsigned int >( val ); 01216 return true; 01217 case LENGTH_THRESHOLD_6: 01218 m_puiLengthThresholds[6] = static_cast< unsigned int >( val ); 01219 return true; 01220 case LENGTH_THRESHOLD_7: 01221 m_puiLengthThresholds[7] = static_cast< unsigned int >( val ); 01222 return true; 01223 } 01224 return false; 01225 } 01226 01227 01229 template <typename T> 01230 T ElasticRodKR<T>::GetKnotControlThreshold ( enum Threshold thdID ) const 01231 { 01232 switch ( thdID ) { 01233 case THRESHOLD_FOR_FIXING_KNOT: 01234 return static_cast<T>( m_uiCounterThreshold ); 01235 case THRESHOLD_WAIT_TIME: 01236 return static_cast<T>( m_tWaitTime ); 01237 case LENGTH_THRESHOLD_0: 01238 return static_cast<T>( m_puiLengthThresholds[0] ); 01239 case LENGTH_THRESHOLD_1: 01240 return static_cast<T>( m_puiLengthThresholds[1] ); 01241 case LENGTH_THRESHOLD_2: 01242 return static_cast<T>( m_puiLengthThresholds[2] ); 01243 case LENGTH_THRESHOLD_3: 01244 return static_cast<T>( m_puiLengthThresholds[3] ); 01245 case LENGTH_THRESHOLD_4: 01246 return static_cast<T>( m_puiLengthThresholds[4] ); 01247 case LENGTH_THRESHOLD_5: 01248 return static_cast<T>( m_puiLengthThresholds[5] ); 01249 case LENGTH_THRESHOLD_6: 01250 return static_cast<T>( m_puiLengthThresholds[6] ); 01251 case LENGTH_THRESHOLD_7: 01252 return static_cast<T>( m_puiLengthThresholds[7] ); 01253 } 01254 return -1; 01255 } 01256 01257 01259 template <typename T> 01260 int ElasticRodKR<T>::KnotRecognition () 01261 { 01262 return CheckSelfCrossingForKnotRecognition( GetProjDirection() ); 01263 } 01264 01265 01267 template <typename T> 01268 int ElasticRodKR<T>::CheckSelfCrossingForKnotRecognition ( Vector3<T> const & projectionDirection ) 01269 { 01270 #ifdef TAPs_NO_DOWKER_KNOT_CHECKING 01271 // NO CHECKING FOR KNOTS BY DOWKER NOTATION 01272 return -1; 01273 #endif//TAPs_NO_DOWKER_KNOT_CHECKING 01274 01275 // Reset 01276 for ( int i = 0; i < m_iMaxCrossingPairs; ++i ) m_iaDowkerNotation[i] = 0; 01277 m_crossings.clear(); 01278 for ( int i = 0; i < m_pParameters->NumOfNodes-1; ++i ) m_iaCrossingCounters[i] = 0; 01279 01280 // Find Crossings 01281 CheckSelfCrossingsNextLevelRecursively( m_BVHTree->Root()->Child(0), 01282 m_BVHTree->Root()->Child(1), 01283 projectionDirection ); 01284 // For Recording Dowker Notation 01285 std::vector<int> crosses; 01286 std::vector<int> crossesID; 01287 01288 //std::cout << "m_crossings.size(): " << m_crossings.size() << std::endl; 01289 01290 //return -1; 01291 01292 std::list< IC_Crossing >::const_iterator it = m_crossings.begin(); 01293 while ( it != m_crossings.end() ) { 01294 // crossesID records the node number that has another node cross over or under it. 01295 // crosses records the crossing identified by node number that crosses over the crossesID. 01296 // E.g. real cross# 1 2 3 4 5 6 01297 // crossesID: 30 31 32 74 77 79 01298 // crosses: -74 77 -79 30 -31 32 01299 // results in the Dowker notation below 01300 // Dowker#: (1,4) (3,6) (5,2) 01301 // which is a half knot 01302 crossesID.push_back( (*it).id ); 01303 crosses.push_back( (*it).number ); 01304 ++it; 01305 } 01306 01307 int numOfCrosses = static_cast<int>( crosses.size() ); 01308 01309 if ( numOfCrosses == 0 ) { // Not a knot 01310 m_iKnotStartPt = m_iKnotEndPt = -1; 01311 m_iNumCrossingPairs = 0; 01312 } 01313 else if ( numOfCrosses % 2 == 0 ) { 01314 01315 //std::cout << "numOfCrosses % 2 == 0" << "\tm_iMaxCrossingPairs: " << m_iMaxCrossingPairs << std::endl; 01316 01317 m_iNumCrossingPairs = numOfCrosses/2; 01318 assert( m_iNumCrossingPairs <= m_iMaxCrossingPairs ); 01319 int idx = 0; 01320 for ( int i = 0, odd = 1; i < numOfCrosses; i+=2, odd+=2 ) { 01321 for ( int j = 1, even = 2; j < numOfCrosses; j+=2, even+=2 ) { 01322 if ( crossesID[i] == abs( crosses[j] ) ) { 01323 01324 //std::cout << "idx: " << idx << std::endl; 01325 01326 //iaDowkerNotation[ idx++ ] = odd; 01327 if ( crosses[j] < 0 ) 01328 m_iaDowkerNotation[ idx++ ] = -even; 01329 else 01330 m_iaDowkerNotation[ idx++ ] = even; 01331 } 01332 } 01333 } 01334 01336 m_iKnotStartPt = crossesID[0]; 01337 m_iKnotEndPt = crossesID[numOfCrosses-1]; 01338 01339 //std::cout << "END: numOfCrosses % 2 == 0" << std::endl; 01340 } 01341 else { // Not a knot 01342 m_iKnotStartPt = m_iKnotEndPt = -1; 01343 m_iNumCrossingPairs = numOfCrosses/2; 01344 } 01345 01346 //* 01347 // DEBUG 01348 debug_crosses = crosses; 01349 debug_crossesID = crossesID; 01350 std::cout << Debug_Str(); 01351 //*/ 01352 01353 // Find the knot that match with the Dowker notation 01354 int knotID = ConverseDowkerNotationToKnotName(); 01355 if ( knotID >= 0 ) { 01356 return knotID; 01357 } 01358 01359 /* 01360 // Check Clumped 01361 if ( m_iNumCrossingPairs > 1 ) { 01362 if ( m_ucTrackingKnot != Data::DatabaseDowkerNotation::UNDEFINED ) { 01363 T sphereRadius = m_tLinkLength * 10.0; 01364 CheckClumped( m_iKnotStartPt, m_iKnotEndPt, sphereRadius ); 01365 if ( IsClumped() ) { 01366 #ifdef TAPs_STRAND_DEBUG 01367 std::cout << "CLUMPED: true (" << m_iKnotStartPt << "," << m_iKnotEndPt << ")" << "\n"; 01368 #endif//TAPs_STRAND_DEBUG 01369 01370 m_uiCounterForFixingKnot = m_uiCounterThreshold+1; 01371 01372 #ifdef TAPs_STRAND_DEBUG 01373 std::cout << "RET: " << m_ucTrackingKnot << "\n"; 01374 #endif//TAPs_STRAND_DEBUG 01375 01376 return m_ucTrackingKnot; 01377 } 01378 } 01379 else { 01380 //std::cout << "CLUMPED: false (" << m_iKnotStartPt << "," << m_iKnotEndPt << ")" << std::endl; 01381 } 01382 } 01383 //*/ 01384 01385 return knotID; 01386 } 01387 01388 01389 01390 //============================================================================= 01391 // START: Fns for CheckSelfCrossingForKnotRecognition function 01392 //----------------------------------------------------------------------------- 01393 // CheckSelfCrossingsNextLevelRecursively 01394 // Assume no intersections between immediate adjacent links 01395 // Assume a BVH node either has both children or none, therefore 01396 // checking either it has a left or right child is enough to determine 01397 // whether it is a leaf node or not. 01398 template <typename T> 01399 void ElasticRodKR<T>::CheckSelfCrossingsNextLevelRecursively ( 01400 BVHNode<T> * node1, BVHNode<T> * node2, 01401 Vector3<T> const & projectionDirection 01402 ) 01403 { 01404 CheckSelfCrossingsRecursively( node1, node2, projectionDirection ); 01405 if ( node1->Child(0) ) 01406 CheckSelfCrossingsNextLevelRecursively( node1->Child(0), node1->Child(1), projectionDirection ); 01407 if ( node2->Child(0) ) 01408 CheckSelfCrossingsNextLevelRecursively( node2->Child(0), node2->Child(1), projectionDirection ); 01409 } 01410 //----------------------------------------------------------------- 01411 // CheckSelfCrossingsRecursively 01412 // Assume no intersections between immediate adjacent links 01413 // Use the fact that the ids of sphere bvh leaf nodes are the same as 01414 // the link id and 01415 template <typename T> 01416 T ElasticRodKR<T>::CheckSelfCrossingsRecursively ( 01417 BVHNode<T> * node1, BVHNode<T> * node2, 01418 Vector3<T> const & projectionDirection 01419 ) 01420 { 01421 const T LinkDiameter = static_cast<T>(2.0) * m_pParameters->Radius; 01422 const T epsilon = m_pParameters->Radius * static_cast<T>(0.05); // for collision response 01423 //------------------------------------------------------------- 01424 if ( !node1->Child(0) && !node2->Child(0) && 01425 ( abs(node1->GetID() - node2->GetID()) == 1 ) ) 01426 { 01427 return DBL_MAX; 01428 } 01429 //------------------------------------------------------------- 01430 T overlap = TestOverlapCircle( node1, node2, projectionDirection ); 01431 //------------------------------------------------------------- 01432 if ( overlap < DBL_MIN ) { 01433 if ( node2->Child(0) == NULL ) { //&& node2->RightChild() == NULL ) { 01434 if ( node1->Child(0) ) { 01435 overlap = CheckSelfCrossingsRecursively( node1->Child(0), node2, projectionDirection ); 01436 } 01437 if ( node1->Child(1) ) { 01438 overlap = CheckSelfCrossingsRecursively( node1->Child(1), node2, projectionDirection ); 01439 } 01440 } 01441 else { 01442 if ( node2->Child(0) ) { 01443 overlap = TestOverlapCircle( node1, node2->Child(0), projectionDirection ); 01444 if ( overlap < DBL_MIN ) { 01445 if ( node1->Child(0) ) { 01446 overlap = CheckSelfCrossingsRecursively( node1->Child(0), node2->Child(0), projectionDirection ); 01447 } 01448 if ( node1->Child(1) ) { 01449 overlap = CheckSelfCrossingsRecursively( node1->Child(1), node2->Child(0), projectionDirection ); 01450 } 01451 } 01452 } 01453 if ( node2->Child(1) ) { 01454 overlap = TestOverlapCircle( node1, node2->Child(1), projectionDirection ); 01455 if ( overlap < DBL_MIN ) { 01456 if ( node1->Child(0) ) { 01457 overlap = CheckSelfCrossingsRecursively( node1->Child(0), node2->Child(1), projectionDirection ); 01458 } 01459 if ( node1->Child(1) ) { 01460 overlap = CheckSelfCrossingsRecursively( node1->Child(1), node2->Child(1), projectionDirection ); 01461 } 01462 } 01463 } 01464 } 01465 //--------------------------------------------------------- 01466 if ( node1->Child(0) == NULL && //node1->Child(1) == NULL && 01467 node2->Child(0) == NULL ) //&& node2->Child(1) == NULL ) 01468 { 01469 CheckCrossings( node1, node2, projectionDirection ); 01470 } 01471 } 01472 //------------------------------------------------------------- 01473 return overlap; 01474 } 01475 //----------------------------------------------------------------- 01476 template <typename T> 01477 T ElasticRodKR<T>::TestOverlapCircle ( 01478 BVHNode<T> * node1, BVHNode<T> * node2, 01479 Vector3<T> const & projectionDirection 01480 ) 01481 { 01482 Vector3<T> C1 = node1->GetCenter(); 01483 Vector3<T> C2 = node2->GetCenter(); 01484 01485 01486 C1.SetZ( 0 ); 01487 C2.SetZ( 0 ); 01488 return (C1 - C2).Length() - ( node1->GetRadius() + node2->GetRadius() ); 01489 } 01490 //----------------------------------------------------------------- 01491 template <typename T> 01492 void ElasticRodKR<T>::CheckCrossings ( 01493 BVHNode<T> * node1, BVHNode<T> * node2, 01494 Vector3<T> const & projectionDirection 01495 ) 01496 { 01497 int i = node1->GetID(); 01498 int j = node2->GetID(); 01499 01500 BVHNodeLeafElasticRodNode<T> * Node1 = dynamic_cast<BVHNodeLeafElasticRodNode<T> *>( node1 ); 01501 BVHNodeLeafElasticRodNode<T> * Node2 = dynamic_cast<BVHNodeLeafElasticRodNode<T> *>( node2 ); 01502 01503 // Skip if a node is clustered 01504 if ( Node1->GetPtrToPrimitive_1()->SimFlags.CheckSimulationConstraints( Enum::AddOn::CLUSTERED ) ) return; 01505 if ( Node1->GetPtrToPrimitive_2()->SimFlags.CheckSimulationConstraints( Enum::AddOn::CLUSTERED ) ) return; 01506 if ( Node2->GetPtrToPrimitive_1()->SimFlags.CheckSimulationConstraints( Enum::AddOn::CLUSTERED ) ) return; 01507 if ( Node2->GetPtrToPrimitive_2()->SimFlags.CheckSimulationConstraints( Enum::AddOn::CLUSTERED ) ) return; 01508 01509 Matrix3x3<T> rotationMatrix = CGMath<T>::CreateRotationMatrix3x3FromVectorAtoVectorB( 01510 Vector3<T>( 0, 0, 1 ), projectionDirection ); 01511 01512 // the start and end points of link i and link j 01513 Vector3<T> I1 = Node1->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].GetPosition(); 01514 Vector3<T> I2 = Node1->GetPtrToPrimitive_2()->Centerline[*m_pIdxCurr].GetPosition(); 01515 Vector3<T> J1 = Node2->GetPtrToPrimitive_1()->Centerline[*m_pIdxCurr].GetPosition(); 01516 Vector3<T> J2 = Node2->GetPtrToPrimitive_2()->Centerline[*m_pIdxCurr].GetPosition(); 01517 01518 // Link# i 01519 Vector3<T> P1 = rotationMatrix * I1; 01520 Vector3<T> P2 = rotationMatrix * I2; 01521 // Link# j 01522 Vector3<T> Q1 = rotationMatrix * J1; 01523 Vector3<T> Q2 = rotationMatrix * J2; 01524 01525 // Project in z-direction 01526 Vector3<T> p1( P1[0], P1[1], 0 ); 01527 Vector3<T> p2( P2[0], P2[1], 0 ); 01528 Vector3<T> q1( Q1[0], Q1[1], 0 ); 01529 Vector3<T> q2( Q2[0], Q2[1], 0 ); 01530 01531 bool isTouched; 01532 T pt, qt; // parameter for the 1st & 2nd line 01533 // where intersection point = p1 + pt(p2-p1) 01534 // where intersection point = q1 + qt(q2-q1) 01535 CGMath<T>::FindIntersectionLineSegmentLineSegment( 01536 p1, p2, q1, q2, // I/P 01537 pt, qt, // O/P 01538 isTouched // O/P 01539 ); 01540 if ( 0 <= pt && pt <= 1 && 0 <= qt && qt <= 1 ) { 01541 Vector3<T> P = P1 + pt*( P2 - P1 ); 01542 Vector3<T> Q = Q1 + qt*( Q2 - Q1 ); 01543 01544 // i+1 and j+1 are for making the link# to be one-based instead of zero-based 01545 if ( P[2] > Q[2] ) { 01546 InsertToList( -(j), i ); 01547 InsertToList( +(i), j ); 01548 } 01549 else { 01550 InsertToList( +(j), i ); 01551 InsertToList( -(i), j ); 01552 } 01553 } 01554 } 01555 //----------------------------------------------------------------------------- 01556 // END: Fns for CheckSelfCrossingForKnotRecognition function 01557 //============================================================================= 01558 01559 01560 01561 01562 //============================================================================= 01563 // START: Animating Knot Tying 01564 #ifdef TAPs_ADD_ANIMATED_KNOTS 01565 //----------------------------------------------------------------------------- 01566 template <typename T> 01567 void ElasticRodKR<T>::ProcessKnotAnimation () 01568 { 01569 Data::DatabaseDowkerNotation::KNOT knotType; 01570 int knotStartLinkID, knotEndLinkID, knotNumOfCrossings; 01571 int tightenKnotID = ConstrainAnimatedKnots( knotType, knotStartLinkID, knotEndLinkID, knotNumOfCrossings ); 01572 if ( tightenKnotID < 0 ) return; 01573 01574 // Record the tighten knot 01575 // 01576 int twiceNumOfCrossings = knotNumOfCrossings * 2; 01577 RecordKnot( 01578 knotStartLinkID, 01579 knotStartLinkID + twiceNumOfCrossings, 01580 knotEndLinkID - twiceNumOfCrossings, 01581 knotEndLinkID, 01582 knotType 01583 ); 01584 01585 // 01586 // Fix the combined knot 01587 // 01588 if ( GetKnotCount() == 2 ) { 01589 int knotID_1 = m_pListOfLockedKnots[0].ID; 01590 int knotID_2 = m_pListOfLockedKnots[1].ID; 01591 01592 knotType = Data::DatabaseDowkerNotation::UNDEFINED; 01593 01594 if ( knotID_1 == Data::DatabaseDowkerNotation::HALF_NEG ) { 01595 if ( knotID_2 == Data::DatabaseDowkerNotation::HALF_NEG ) { 01596 knotType = Data::DatabaseDowkerNotation::HALF_NEG_FOLLOWED_BY_HALF_NEG; 01597 } 01598 else if ( knotID_2 == Data::DatabaseDowkerNotation::HALF_POS ) { 01599 knotType = Data::DatabaseDowkerNotation::HALF_NEG_FOLLOWED_BY_HALF_POS; 01600 } 01601 } 01602 else if ( knotID_1 == Data::DatabaseDowkerNotation::HALF_POS ) { 01603 if ( knotID_2 == Data::DatabaseDowkerNotation::HALF_NEG ) { 01604 knotType = Data::DatabaseDowkerNotation::HALF_POS_FOLLOWED_BY_HALF_NEG; 01605 } 01606 else if ( knotID_2 == Data::DatabaseDowkerNotation::HALF_POS ) { 01607 knotType = Data::DatabaseDowkerNotation::HALF_POS_FOLLOWED_BY_HALF_POS; 01608 } 01609 } 01610 else if ( knotID_1 == Data::DatabaseDowkerNotation::DOUBLE_NEG ) { 01611 if ( knotID_2 == Data::DatabaseDowkerNotation::HALF_NEG ) { 01612 knotType = Data::DatabaseDowkerNotation::DOUBLE_NEG_FOLLOWED_BY_HALF_NEG; 01613 } 01614 else if ( knotID_2 == Data::DatabaseDowkerNotation::HALF_POS ) { 01615 knotType = Data::DatabaseDowkerNotation::DOUBLE_NEG_FOLLOWED_BY_HALF_POS; 01616 } 01617 } 01618 else if ( knotID_1 == Data::DatabaseDowkerNotation::DOUBLE_POS ) { 01619 if ( knotID_2 == Data::DatabaseDowkerNotation::HALF_NEG ) { 01620 knotType = Data::DatabaseDowkerNotation::DOUBLE_POS_FOLLOWED_BY_HALF_NEG; 01621 } 01622 else if ( knotID_2 == Data::DatabaseDowkerNotation::HALF_POS ) { 01623 knotType = Data::DatabaseDowkerNotation::DOUBLE_POS_FOLLOWED_BY_HALF_POS; 01624 } 01625 } 01626 01627 /* 01628 // DEBUG 01629 std::cout << "knotID_1: " << knotID_1 << "\n"; 01630 std::cout << "knotID_2: " << knotID_2 << "\n"; 01631 std::cout << "knotType: " << knotType << "\n"; 01632 //*/ 01633 01634 CombineTwoKnots( 01635 0, // start id of locked knots to be combined 01636 knotType, 01637 m_OrientationForCombinedKnot 01638 ); 01639 } 01640 01641 } 01642 //----------------------------------------------------------------------------- 01643 // Constraint and animate knots (forcing all links forming each animated knot to move as a unit) 01644 // Each animated knot will be tighten until it is locked and becomes a permanent knot. 01645 template <typename T> 01646 int ElasticRodKR<T>::ConstrainAnimatedKnots ( 01647 Data::DatabaseDowkerNotation::KNOT & knotTypeOfTheFinishTightenKnot, 01648 int & knotIDStartOfTheFinishTightenKnot, 01649 int & knotIDEndOfTheFinishTightenKnot, 01650 int & numOfCrossingsOfTheFinishTightenKnot 01651 ) 01652 { 01653 // \ /\ /\ / 01654 // -- -- -- -- -- -- 01655 // \ / \ / \ / 01656 // -- -- -- -- -- -- 01657 // \ / \ / \ / <------ angle 01658 // ----------------------0---------------------- 01659 // / \ / \ / \ 01660 // -- -- -- -- -- -- 01661 // / \ / \ / \ 01662 // -- -- -- -- -- -- 01663 // / \/ \/ \ 01664 // 01665 // 01666 // 01667 01668 if ( m_ListOfAnimatedKnot.size() <= 0 ) return -1; 01669 01670 int returnID = -1; 01671 01672 //static T offsetAngleDeg = -0.01; 01673 //angleDeg -= offsetAngleDeg; 01674 //if ( angleDeg < -90 || angleDeg > 90 ) offsetAngleDeg *= -1; 01675 01676 // For each animated knot 01677 int knotNumber = 0; 01678 for ( std::vector< AnimatedKnot >::iterator knot = m_ListOfAnimatedKnot.begin(); knot != m_ListOfAnimatedKnot.end(); ++knot ) 01679 { 01680 01681 //SetTheShapeOfAnimatedKnot( *knot ); 01682 //return -1; 01683 01684 01685 // 01686 // Setting up the knot 01687 // 01688 if ( knot->StepsLeftForSettingKnot > 0 ) { 01689 --knot->StepsLeftForSettingKnot; 01690 SetTheShapeOfAnimatedKnot( *knot ); 01691 } 01692 else { 01693 01694 01695 // 01696 // Move the crossing pairs by avaraging 01697 // 01698 01699 Quaternion<T> ori_o( 0, 0, 0, 0 ); 01700 Quaternion<T> ori_n( 0, 0, 0, 0 ); 01701 Vector3<T> pos_o( 0, 0, 0 ); 01702 Vector3<T> pos_n( 0, 0, 0 ); 01703 Vector3<T> vel_o( 0, 0, 0 ); 01704 Vector3<T> vel_n( 0, 0, 0 ); 01705 int div = 0; 01706 01707 int size = knot->NumOfCrossings * 2; 01708 int s = knot->KnotIDStart; 01709 int e = knot->KnotIDEnd - size; 01710 for ( int i = 0; i <= size; ++i, ++s, ++e ) { 01711 if ( !(*m_pNodeList)[s].SimFlags.CheckSimulationConstraints( Enum::AddOn::FIXED ) ) { 01712 ori_o += (*m_pNodeList)[s].Orientation[*m_pIdxCurr]; 01713 ori_n += (*m_pNodeList)[s].Orientation[*m_pIdxNext]; 01714 pos_o += (*m_pNodeList)[s].Centerline[*m_pIdxCurr].GetPosition(); 01715 pos_n += (*m_pNodeList)[s].Centerline[*m_pIdxNext].GetPosition(); 01716 vel_o += (*m_pNodeList)[s].Centerline[*m_pIdxCurr].GetVelocity(); 01717 vel_n += (*m_pNodeList)[s].Centerline[*m_pIdxNext].GetVelocity(); 01718 ++div; 01719 } 01720 if ( !(*m_pNodeList)[e].SimFlags.CheckSimulationConstraints( Enum::AddOn::FIXED ) ) { 01721 ori_o += (*m_pNodeList)[e].Orientation[*m_pIdxCurr]; 01722 ori_n += (*m_pNodeList)[e].Orientation[*m_pIdxNext]; 01723 pos_o += (*m_pNodeList)[e].Centerline[*m_pIdxCurr].GetPosition(); 01724 pos_n += (*m_pNodeList)[e].Centerline[*m_pIdxNext].GetPosition(); 01725 vel_o += (*m_pNodeList)[e].Centerline[*m_pIdxCurr].GetVelocity(); 01726 vel_n += (*m_pNodeList)[e].Centerline[*m_pIdxNext].GetVelocity(); 01727 ++div; 01728 } 01729 } 01730 01731 // Averaging 01732 if ( div > 0 ) { 01733 ori_o *= T(1)/div; 01734 ori_n *= T(1)/div; 01735 pos_o /= div; 01736 pos_n /= div; 01737 vel_o /= div; 01738 vel_n /= div; 01739 Quaternion<T> ori_change = ori_n - ori_o; 01740 Vector3<T> pos_change = pos_n - pos_o; 01741 Vector3<T> vel_change = vel_n - vel_o; 01742 s = knot->KnotIDStart; 01743 e = knot->KnotIDEnd - size; 01744 01745 for ( int i = 0; i <= size; ++i, ++s, ++e ) { 01746 (*m_pNodeList)[s].Centerline[*m_pIdxNext].SetVelocity( (*m_pNodeList)[s].Centerline[*m_pIdxCurr].GetVelocity() + vel_change ); 01747 (*m_pNodeList)[s].Centerline[*m_pIdxNext].SetPosition( (*m_pNodeList)[s].Centerline[*m_pIdxCurr].GetPosition() + pos_change ); 01748 (*m_pNodeList)[s].Orientation[*m_pIdxNext] = (*m_pNodeList)[s].Orientation[*m_pIdxCurr] + ori_change; 01749 (*m_pNodeList)[s].Orientation[*m_pIdxNext].Normalized(); 01750 (*m_pNodeList)[e].Centerline[*m_pIdxNext].SetVelocity( (*m_pNodeList)[e].Centerline[*m_pIdxCurr].GetVelocity() + vel_change ); 01751 (*m_pNodeList)[e].Centerline[*m_pIdxNext].SetPosition( (*m_pNodeList)[e].Centerline[*m_pIdxCurr].GetPosition() + pos_change ); 01752 (*m_pNodeList)[e].Orientation[*m_pIdxNext] = (*m_pNodeList)[e].Orientation[*m_pIdxCurr] + ori_change; 01753 (*m_pNodeList)[e].Orientation[*m_pIdxNext].Normalized(); 01754 } 01755 } 01756 01757 // 01758 // Tighten the knot 01759 // 01760 const T lenThs = 0.5; 01761 bool bReachStartNodeIDLimit = false; 01762 bool bReachEndNodeIDLimit = false; 01763 //int lookAheadIdOffset = size; 01764 //if ( GetKnotCount() > 0 ) { 01765 // lookAheadIdOffset += 2; 01766 //} 01767 int lookAheadIdOffset = 1; 01768 int knotSizeLimit = knot->KnotSizeLimit + (lookAheadIdOffset << 1); // adjust knot size limit by lookAheadOffset*2 01769 01770 int knotSize = knot->KnotIDEnd - knot->KnotIDStart; 01771 01772 /* 01773 // DEBUG 01774 std::stringstream ss; 01775 ss << "knotSize: " << knotSize << "; knot->KnotSizeLimit: " << knot->KnotSizeLimit; 01776 ss << "; StartD: " << knot->KnotIDStart << "<" << knot->KnotIDStart_Limit; 01777 ss << "; EndID: " << knot->KnotIDEnd << ">" << knot->KnotIDEnd_Limit; 01778 gDebugStr[11] = ss.str(); 01779 //*/ 01780 01781 if ( knot->KnotIDStart < knot->KnotIDStart_Limit - size && knotSize > knotSizeLimit ) { 01782 int check = knot->KnotIDStart + lookAheadIdOffset; 01783 if ( ( (*m_pNodeList)[check].SimFlags.CheckSimulationConstraints( Enum::AddOn::ATTACHED ) == false ) 01784 && ( (*m_pNodeList)[check].SimFlags.CheckSimulationConstraints( Enum::AddOn::CLUSTERED ) == false ) 01785 ) { 01786 s = knot->KnotIDStart; 01787 T lenS_0 = ( (*m_pNodeList)[s-1].Centerline[*m_pIdxCurr].GetPosition() - (*m_pNodeList)[s].Centerline[*m_pIdxCurr].GetPosition() ).Length(); 01788 T lenS_1 = ( (*m_pNodeList)[s+1].Centerline[*m_pIdxCurr].GetPosition() - (*m_pNodeList)[s].Centerline[*m_pIdxCurr].GetPosition() ).Length(); 01789 if ( lenS_0 - lenS_1 > lenS_1 * lenThs ) 01790 { 01791 ++knot->KnotIDStart; 01792 //knot->StepsLeftForSettingKnot = m_pParameters->NumOfNodes * T(0.05); 01793 knot->StepsLeftForSettingKnot = 1; 01794 } 01795 } 01796 else { 01797 bReachStartNodeIDLimit = true; 01798 } 01799 } 01800 else { 01801 bReachStartNodeIDLimit = true; 01802 } 01803 // 01804 // 01805 // 01806 if ( knot->KnotIDEnd > knot->KnotIDEnd_Limit + size && knotSize > knotSizeLimit ) { 01807 int check = knot->KnotIDEnd - lookAheadIdOffset; 01808 if ( ( (*m_pNodeList)[check].SimFlags.CheckSimulationConstraints( Enum::AddOn::ATTACHED ) == false ) 01809 && ( (*m_pNodeList)[check].SimFlags.CheckSimulationConstraints( Enum::AddOn::CLUSTERED ) == false ) 01810 ) { 01811 e = knot->KnotIDEnd; 01812 T lenE_0 = ( (*m_pNodeList)[e-1].Centerline[*m_pIdxCurr].GetPosition() - (*m_pNodeList)[e].Centerline[*m_pIdxCurr].GetPosition() ).Length(); 01813 T lenE_1 = ( (*m_pNodeList)[e+1].Centerline[*m_pIdxCurr].GetPosition() - (*m_pNodeList)[e].Centerline[*m_pIdxCurr].GetPosition() ).Length(); 01814 if ( lenE_1 - lenE_0 > lenE_0 * lenThs ) { 01815 --knot->KnotIDEnd; 01816 //knot->StepsLeftForSettingKnot = m_pParameters->NumOfNodes * T(0.05); 01817 knot->StepsLeftForSettingKnot = 1; 01818 } 01819 } 01820 else { 01821 bReachEndNodeIDLimit = true; 01822 } 01823 } 01824 else { 01825 bReachEndNodeIDLimit = true; 01826 } 01827 01828 // 01829 // If the knot is tighten, then record the knot. 01830 // 01831 if ( bReachStartNodeIDLimit && bReachEndNodeIDLimit ) { 01832 knot->IsKnotTight = true; 01833 01834 #ifdef TAPs_SPECIFIC_FOR_SUTUREAPP_02 01835 *(knot->pKnotTightenStatus) = true; 01836 #endif//TAPs_SPECIFIC_FOR_SUTUREAPP_02 01837 01838 // 01839 // Rearrange the knot 01840 // 01841 if ( GetKnotCount() <= 0 ) { 01842 FinalizeTheShapeOfAnimatedKnot( *knot ); 01843 } 01844 01845 returnID = knot->GetID(); 01846 knotIDStartOfTheFinishTightenKnot = knot->KnotIDStart; 01847 knotIDEndOfTheFinishTightenKnot = knot->KnotIDEnd; 01848 numOfCrossingsOfTheFinishTightenKnot = knot->NumOfCrossings; 01849 knotTypeOfTheFinishTightenKnot = knot->KnotType; 01850 01851 m_ListOfAnimatedKnot.erase( knot ); 01852 01853 return returnID; 01854 01855 break; 01856 } 01857 else { 01858 //SetTheShapeOfAnimatedKnot( *knot ); 01859 } 01860 } 01861 } 01862 return returnID; 01863 } 01864 //----------------------------------------------------------------------------- 01865 template <typename T> 01866 void ElasticRodKR<T>::SetTheShapeOfAnimatedKnot ( AnimatedKnot & knot ) 01867 { 01868 // Variables 01869 const T angleDeg = 30; 01870 T angle = angleDeg * Math<T>::DEG_TO_RAD; 01871 T cos_X = cos( angle ); 01872 T sin_Y = sin( angle ); 01873 T dx = cos_X * m_pParameters->LinkLength; 01874 T dy = sin_Y * m_pParameters->LinkLength; 01875 T dz = m_pParameters->Radius; 01876 T dz2 = dz * 2; 01877 T x, y, z, z2; 01878 01879 // Set suture's node offsets for creating the knot shape 01880 x = dx * knot.NumOfCrossings; 01881 switch ( knot.KnotType ) { 01882 case Data::DatabaseDowkerNotation::HALF_NEG: 01883 case Data::DatabaseDowkerNotation::DOUBLE_NEG: 01884 y = dy; 01885 z = dz; 01886 z2 = dz2; 01887 break; 01888 case Data::DatabaseDowkerNotation::HALF_POS: 01889 case Data::DatabaseDowkerNotation::DOUBLE_POS: 01890 y = dy; 01891 z = -dz; 01892 z2 = -dz2; 01893 break; 01894 default: 01895 y = dy; 01896 z = dz; 01897 z2 = dz2; 01898 break; 01899 } 01900 01901 // 01902 // Calculate translation and orientation for the animated knot 01903 // 01904 if ( knot.GetStatusCalKnotPosition() ) { 01905 knot.Center = ( (*m_pNodeList)[knot.KnotIDStart-1].Centerline[*m_pIdxNext].GetPosition() 01906 + (*m_pNodeList)[knot.KnotIDEnd+1].Centerline[*m_pIdxNext].GetPosition() ) * T(0.5); 01907 Vector3<T> direction = ( (*m_pNodeList)[knot.KnotIDStart-1].Centerline[*m_pIdxNext].GetPosition() 01908 - (*m_pNodeList)[knot.KnotIDEnd+1].Centerline[*m_pIdxNext].GetPosition() ).GetUnit(); 01909 if ( !knot.IsOrientationFixed ) { 01910 knot.Orientation = CGMath<T>::CreateRotationMatrix4x4FromVectorAtoVectorB( CGMath<T>::VectorX, direction ); 01911 } 01912 } 01913 01914 // Create a knot shape from the constrained links 01915 int size = knot.NumOfCrossings * 2; 01916 int s = knot.KnotIDStart; 01917 int e = knot.KnotIDEnd - size; 01918 Vector3<T> posS, posE; 01919 for ( int i = 0; i <= size; ) 01920 { 01921 //if ( i > 0 ) 01922 { 01923 posS = (knot.Orientation * Vector4<T>( x, y, z, 1)).GetVector3() + knot.Center; 01924 posE = (knot.Orientation * Vector4<T>( x,-y,-z, 1)).GetVector3() + knot.Center; 01925 (*m_pNodeList)[s].Centerline[*m_pIdxNext].SetPosition( posS ); 01926 (*m_pNodeList)[e].Centerline[*m_pIdxNext].SetPosition( posE ); 01927 (*m_pNodeList)[s].Centerline[*m_pIdxCurr].SetPosition( posS ); 01928 (*m_pNodeList)[e].Centerline[*m_pIdxCurr].SetPosition( posE ); 01929 } 01930 ++i; ++s; ++e; 01931 x -= dx; 01932 01933 if ( i < size ) 01934 { 01935 posS = (knot.Orientation * Vector4<T>( x, 0, z2, 1)).GetVector3() + knot.Center; 01936 posE = (knot.Orientation * Vector4<T>( x, 0,-z2, 1)).GetVector3() + knot.Center; 01937 (*m_pNodeList)[s].Centerline[*m_pIdxNext].SetPosition( posS ); 01938 (*m_pNodeList)[e].Centerline[*m_pIdxNext].SetPosition( posE ); 01939 (*m_pNodeList)[s].Centerline[*m_pIdxCurr].SetPosition( posS ); 01940 (*m_pNodeList)[e].Centerline[*m_pIdxCurr].SetPosition( posE ); 01941 } 01942 ++i; ++s; ++e; 01943 x -= dx; 01944 y = -y; 01945 z = -z; 01946 z2 = -z2; 01947 01948 } 01949 //knot.Orientation = CGMath<T>::CreateRotationMatrix4x4FromVectorAtoVectorB( CGMath<T>::VectorZ, direction ); 01950 } 01951 //----------------------------------------------------------------------------- 01952 template <typename T> 01953 void ElasticRodKR<T>::FinalizeTheShapeOfAnimatedKnot ( AnimatedKnot & knot ) 01954 { 01955 // Variables 01956 const T angleDeg = 30; 01957 T angle = angleDeg * Math<T>::DEG_TO_RAD; 01958 T cos_X = cos( angle ); 01959 T sin_Y = sin( angle ); 01960 T dx = cos_X * m_pParameters->LinkLength; 01961 T dy = sin_Y * m_pParameters->LinkLength; 01962 T dz = m_pParameters->Radius; 01963 T dz2 = dz * 2; 01964 T x, y, z, z2; 01965 01966 // Set suture's node offsets for creating the knot shape 01967 x = dx * knot.NumOfCrossings; 01968 switch ( knot.KnotType ) { 01969 case Data::DatabaseDowkerNotation::HALF_NEG: 01970 case Data::DatabaseDowkerNotation::DOUBLE_NEG: 01971 y = dy; 01972 z = dz; 01973 z2 = dz2; 01974 break; 01975 case Data::DatabaseDowkerNotation::HALF_POS: 01976 case Data::DatabaseDowkerNotation::DOUBLE_POS: 01977 y = dy; 01978 z = -dz; 01979 z2 = -dz2; 01980 break; 01981 default: 01982 y = dy; 01983 z = dz; 01984 z2 = dz2; 01985 break; 01986 } 01987 01988 // 01989 // Calculate translation and orientation for the animated knot 01990 // 01991 if ( knot.GetStatusCalKnotPosition() ) { 01992 knot.Center = ( (*m_pNodeList)[knot.KnotIDStart-1].Centerline[*m_pIdxNext].GetPosition() 01993 + (*m_pNodeList)[knot.KnotIDEnd+1].Centerline[*m_pIdxNext].GetPosition() ) * T(0.5); 01994 Vector3<T> direction = ( (*m_pNodeList)[knot.KnotIDStart-1].Centerline[*m_pIdxNext].GetPosition() 01995 - (*m_pNodeList)[knot.KnotIDEnd+1].Centerline[*m_pIdxNext].GetPosition() ).GetUnit(); 01996 if ( !knot.IsOrientationFixed ) { 01997 knot.Orientation = CGMath<T>::CreateRotationMatrix4x4FromVectorAtoVectorB( CGMath<T>::VectorX, direction ); 01998 } 01999 } 02000 02001 // 02002 // Create a knot shape from the constrained links 02003 // 02004 int size = knot.NumOfCrossings * 2; 02005 knot.KnotIDStart = knot.KnotIDStart_Limit - size; 02006 knot.KnotIDEnd = knot.KnotIDEnd_Limit + size; 02007 int s = knot.KnotIDStart; 02008 int e = knot.KnotIDEnd - size; 02009 Vector3<T> posS, posE; 02010 for ( int i = 0; i <= size; ) 02011 { 02012 //if ( i > 0 ) 02013 { 02014 posS = (knot.Orientation * Vector4<T>( x, y, z, 1)).GetVector3() + knot.Center; 02015 posE = (knot.Orientation * Vector4<T>( x,-y,-z, 1)).GetVector3() + knot.Center; 02016 (*m_pNodeList)[s].Centerline[*m_pIdxNext].SetPosition( posS ); 02017 (*m_pNodeList)[e].Centerline[*m_pIdxNext].SetPosition( posE ); 02018 (*m_pNodeList)[s].Centerline[*m_pIdxCurr].SetPosition( posS ); 02019 (*m_pNodeList)[e].Centerline[*m_pIdxCurr].SetPosition( posE ); 02020 } 02021 ++i; ++s; ++e; 02022 x -= dx; 02023 02024 if ( i < size ) 02025 { 02026 posS = (knot.Orientation * Vector4<T>( x, 0, z2, 1)).GetVector3() + knot.Center; 02027 posE = (knot.Orientation * Vector4<T>( x, 0,-z2, 1)).GetVector3() + knot.Center; 02028 (*m_pNodeList)[s].Centerline[*m_pIdxNext].SetPosition( posS ); 02029 (*m_pNodeList)[e].Centerline[*m_pIdxNext].SetPosition( posE ); 02030 (*m_pNodeList)[s].Centerline[*m_pIdxCurr].SetPosition( posS ); 02031 (*m_pNodeList)[e].Centerline[*m_pIdxCurr].SetPosition( posE ); 02032 } 02033 ++i; ++s; ++e; 02034 x -= dx; 02035 y = -y; 02036 z = -z; 02037 z2 = -z2; 02038 02039 } 02040 //knot.Orientation = CGMath<T>::CreateRotationMatrix4x4FromVectorAtoVectorB( CGMath<T>::VectorZ, direction ); 02041 } 02042 //----------------------------------------------------------------------------- 02043 // Add an animated knot -- used with knot tying by wrapping loops 02044 template <typename T> 02045 bool ElasticRodKR<T>::AddAnimatedKnot ( 02046 #ifdef TAPs_SPECIFIC_FOR_SUTUREAPP_02 02047 bool * pKnotTightenStatus, 02048 #endif//TAPs_SPECIFIC_FOR_SUTUREAPP_02 02049 int grabbedNodeID, 02050 Data::DatabaseDowkerNotation::KNOT knot, 02051 int startNodeIDLimit, 02052 int endNodeIDLimit, 02053 bool bCalKnotPosition, 02054 bool bEndIsGrabbed, 02055 int offset, 02056 Matrix4x4<T> * pOrientation 02057 ) 02058 { 02059 // Clear the previous animated knot 02060 //DoneAnimatingKnot(); 02061 02062 // The suture tail is grabbed, so check only nodes from the suture head to 02063 // an offset of number of points from the grabbed point 02064 if ( bEndIsGrabbed ) { 02065 02066 // Find the closest node to the grabbed node 02067 Vector3<T> position = (*m_pNodeList)[grabbedNodeID].Centerline[*m_pIdxCurr].GetPosition(); 02068 #ifndef _WINDOWS_ 02069 //T shortestDist = std::numeric_limits<T>::max(); 02070 #else 02071 //T shortestDist = Math<T>::MAX; 02072 #endif 02073 //T shortestDist = std::numeric_limits<T>::max(); 02074 T shortestDist = 5E32; 02075 02076 int closestNodeID = 1; // not zero to avoid boundary error, since ConstrainAnimatedKnots fn use this value minus by 1 for indexing 02077 for ( int i = 0; i < grabbedNodeID - offset; ++i ) { 02078 Vector3<T> pos2 = (*m_pNodeList)[i].Centerline[*m_pIdxCurr].GetPosition(); 02079 T dist = (position - pos2).Length(); 02080 if ( dist < shortestDist ) { 02081 shortestDist = dist; 02082 closestNodeID = i; 02083 } 02084 //std::cout << "i" << i << std::endl; 02085 } 02086 02087 /* 02088 // DEBUG 02089 std::stringstream ss; 02090 ss << "grabbedNodeID: " << grabbedNodeID; 02091 ss << " closestNodeID: " << closestNodeID; 02092 gDebugStr[10] = ss.str(); 02093 //*/ 02094 02095 // Set number of crossing pairs according to the knot type 02096 int numOfCrossings = 3; 02097 switch ( knot ) { 02098 case Data::DatabaseDowkerNotation::HALF_NEG: 02099 numOfCrossings = 3; 02100 break; 02101 case Data::DatabaseDowkerNotation::HALF_POS: 02102 numOfCrossings = 3; 02103 break; 02104 case Data::DatabaseDowkerNotation::DOUBLE_NEG: 02105 numOfCrossings = 5; 02106 break; 02107 case Data::DatabaseDowkerNotation::DOUBLE_POS: 02108 numOfCrossings = 5; 02109 break; 02110 default: 02111 numOfCrossings = 3; 02112 break; 02113 } 02114 02115 int knotSizeLimit = numOfCrossings*4; 02116 02117 // The knot could not be added if the knot size is smaller than the knot size limit 02118 if ( grabbedNodeID - closestNodeID < knotSizeLimit ) return false; 02119 02120 //std::cout << "closestNodeID: " << closestNodeID << std::endl; 02121 02122 // Create an animated knot 02123 m_ListOfAnimatedKnot.push_back( AnimatedKnot() ); 02124 m_ListOfAnimatedKnot.back().SetStatusCalKnotPosition( bCalKnotPosition ); 02125 02126 #ifdef TAPs_SPECIFIC_FOR_SUTUREAPP_02 02127 *pKnotTightenStatus = false; 02128 m_ListOfAnimatedKnot.back().pKnotTightenStatus = pKnotTightenStatus; 02129 #endif//TAPs_SPECIFIC_FOR_SUTUREAPP_02 02130 02131 // Set the animated knot's properties 02132 { 02133 int idA = closestNodeID; 02134 int idB = grabbedNodeID; 02135 int twiceNumOfCrossings = numOfCrossings*2; 02136 int id_at_half_loop = ( idB - idA - twiceNumOfCrossings ) / 2; 02137 int knot_tighten_half_length = numOfCrossings * 2; // *2 for the number of links reserved for half knot loop 02138 02139 m_ListOfAnimatedKnot.back().KnotIDStart = idA; 02140 m_ListOfAnimatedKnot.back().KnotIDEnd = idB; 02141 02142 m_ListOfAnimatedKnot.back().KnotSizeLimit = knotSizeLimit; 02143 m_ListOfAnimatedKnot.back().NumOfCrossings = numOfCrossings; 02144 m_ListOfAnimatedKnot.back().KnotType = knot; 02145 02146 if ( pOrientation ) { 02147 m_ListOfAnimatedKnot.back().IsOrientationFixed = true; 02148 m_ListOfAnimatedKnot.back().Orientation = *pOrientation; 02149 } 02150 02151 // Set the start limit id 02152 if ( startNodeIDLimit >= 0 ) { 02153 //if ( idA <= startNodeIDLimit && startNodeIDLimit <= idB ) { 02154 m_ListOfAnimatedKnot.back().KnotIDStart_Limit = startNodeIDLimit; 02155 //} 02156 //else { 02157 //} 02158 } 02159 else { 02160 m_ListOfAnimatedKnot.back().KnotIDStart_Limit = id_at_half_loop - knot_tighten_half_length; 02161 } 02162 02163 // Set the end limit id 02164 if ( endNodeIDLimit >= 0 ) { 02165 //if ( idA <= endNodeIDLimit && endNodeIDLimit <= idB ) { 02166 m_ListOfAnimatedKnot.back().KnotIDEnd_Limit = endNodeIDLimit; 02167 //} 02168 //else { 02169 //} 02170 } 02171 else { 02172 m_ListOfAnimatedKnot.back().KnotIDEnd_Limit = id_at_half_loop + knot_tighten_half_length; 02173 } 02174 02175 // Adjust the start and end limit ids due to the existing locked knots 02176 for ( int i = 0; i < m_ucKnotCount; ++i ) { 02177 int sid = m_pListOfLockedKnots[i].StartLinkID - twiceNumOfCrossings; 02178 int eid = m_pListOfLockedKnots[i].EndLinkID + twiceNumOfCrossings; 02179 if ( m_ListOfAnimatedKnot.back().KnotIDStart <= sid && sid < m_ListOfAnimatedKnot.back().KnotIDStart_Limit ) { 02180 m_ListOfAnimatedKnot.back().KnotIDStart_Limit = sid; 02181 } 02182 if ( m_ListOfAnimatedKnot.back().KnotIDEnd_Limit < sid && sid <= m_ListOfAnimatedKnot.back().KnotIDEnd ) { 02183 m_ListOfAnimatedKnot.back().KnotIDEnd_Limit = eid; 02184 } 02185 } 02186 // Set the number of simulation loops for setting up the knot 02187 //m_ListOfAnimatedKnot.back().StepsLeftForSettingKnot = m_pParameters->NumOfNodes; 02188 m_ListOfAnimatedKnot.back().StepsLeftForSettingKnot = 1; 02189 02190 //* 02191 // DEBUG 02192 { 02193 std::stringstream ss; 02194 ss << "after add, start--end IDs: " << m_ListOfAnimatedKnot.back().KnotIDStart 02195 << "--" << m_ListOfAnimatedKnot.back().KnotIDEnd 02196 << " : (" << m_ListOfAnimatedKnot.back().KnotIDStart_Limit 02197 << ", " << m_ListOfAnimatedKnot.back().KnotIDEnd_Limit << ")" 02198 << "; knot size limit: " << m_ListOfAnimatedKnot.back().KnotSizeLimit; 02199 gDebugStr[9] = ss.str(); 02200 } 02201 //*/ 02202 } 02203 } 02204 else { 02205 std::cout << __FILE__ << ":" << __LINE__ << ": (!bEndIsGrabbed) does not implemented/supported!" << std::endl; 02206 } 02207 return true; 02208 } //END: Add an animated knot -- used with knot tying by wrapping loops 02209 02210 //----------------------------------------------------------------------------- 02211 // Add an animated knot -- used with knot tying by Tyco Endo Stitch Device 02212 template <typename T> 02213 bool ElasticRodKR<T>::AddAnimatedKnot ( 02214 #ifdef TAPs_SPECIFIC_FOR_SUTUREAPP_02 02215 bool * pKnotTightenStatus, 02216 #endif//TAPs_SPECIFIC_FOR_SUTUREAPP_02 02217 Data::DatabaseDowkerNotation::KNOT knot, 02218 int startNodeIDLimit, 02219 int startLoopNodeIDLimit, 02220 int endLoopNodeIDLimit, 02221 int endNodeIDLimit, 02222 bool bCalKnotPosition, 02223 bool bEndIsGrabbed, 02224 Matrix4x4<T> * pOrientation 02225 ) 02226 { 02227 if ( startNodeIDLimit < 0 ) startNodeIDLimit = 1; 02228 else if ( endNodeIDLimit < 0 ) endNodeIDLimit = m_pParameters->NumOfNodes - 2; 02229 02230 // The suture tail is grabbed 02231 if ( bEndIsGrabbed ) { 02232 02233 // Set number of crossing pairs according to the knot type 02234 int numOfCrossings = 3; 02235 switch ( knot ) { 02236 case Data::DatabaseDowkerNotation::HALF_NEG: 02237 numOfCrossings = 3; 02238 break; 02239 case Data::DatabaseDowkerNotation::HALF_POS: 02240 numOfCrossings = 3; 02241 break; 02242 case Data::DatabaseDowkerNotation::DOUBLE_NEG: 02243 numOfCrossings = 5; 02244 break; 02245 case Data::DatabaseDowkerNotation::DOUBLE_POS: 02246 numOfCrossings = 5; 02247 break; 02248 default: 02249 numOfCrossings = 3; 02250 break; 02251 } 02252 02253 int knotSizeLimit = numOfCrossings*4; 02254 02255 //knotSizeLimit = numOfCrossings; 02256 02257 // The knot could not be added if the knot size is smaller than the knot size limit 02258 if ( endNodeIDLimit - startNodeIDLimit < knotSizeLimit ) return false; 02259 02260 //std::cout << "closestNodeID: " << closestNodeID << std::endl; 02261 02262 // Create an animated knot 02263 m_ListOfAnimatedKnot.push_back( AnimatedKnot() ); 02264 m_ListOfAnimatedKnot.back().SetStatusCalKnotPosition( bCalKnotPosition ); 02265 02266 #ifdef TAPs_SPECIFIC_FOR_SUTUREAPP_02 02267 *pKnotTightenStatus = false; 02268 m_ListOfAnimatedKnot.back().pKnotTightenStatus = pKnotTightenStatus; 02269 #endif//TAPs_SPECIFIC_FOR_SUTUREAPP_02 02270 02271 // Set the animated knot's properties 02272 { 02273 int idA = startNodeIDLimit; 02274 int idB = endNodeIDLimit; 02275 int twiceNumOfCrossings = numOfCrossings*2; 02276 int id_at_half_loop = ( idB - idA - twiceNumOfCrossings ) / 2; 02277 int knot_tighten_half_length = numOfCrossings * 2; // *2 for the number of links reserved for half knot loop 02278 02279 m_ListOfAnimatedKnot.back().KnotIDStart = idA; 02280 m_ListOfAnimatedKnot.back().KnotIDEnd = idB; 02281 02282 m_ListOfAnimatedKnot.back().NumOfCrossings = numOfCrossings; 02283 m_ListOfAnimatedKnot.back().KnotType = knot; 02284 02285 if ( pOrientation ) { 02286 m_ListOfAnimatedKnot.back().IsOrientationFixed = true; 02287 m_ListOfAnimatedKnot.back().Orientation = *pOrientation; 02288 } 02289 02290 // 02291 // Set the start limit id, end limit id, and knot size limit 02292 // 02293 if ( startLoopNodeIDLimit < 0 || endLoopNodeIDLimit < 0 || ( startLoopNodeIDLimit >= endLoopNodeIDLimit ) ) { 02294 m_ListOfAnimatedKnot.back().KnotIDStart_Limit = startNodeIDLimit; 02295 m_ListOfAnimatedKnot.back().KnotIDEnd_Limit = endNodeIDLimit; 02296 m_ListOfAnimatedKnot.back().KnotSizeLimit = knotSizeLimit; 02297 } 02298 else { 02299 m_ListOfAnimatedKnot.back().KnotIDStart_Limit = startLoopNodeIDLimit; 02300 m_ListOfAnimatedKnot.back().KnotIDEnd_Limit = endLoopNodeIDLimit; 02301 m_ListOfAnimatedKnot.back().KnotSizeLimit = endLoopNodeIDLimit - startLoopNodeIDLimit + 1; 02302 } 02303 02304 // Adjust the start and end limit ids due to the existing locked knots 02305 for ( int i = 0; i < m_ucKnotCount; ++i ) { 02306 int sid = m_pListOfLockedKnots[i].StartLinkID - twiceNumOfCrossings; 02307 int eid = m_pListOfLockedKnots[i].EndLinkID + twiceNumOfCrossings; 02308 if ( m_ListOfAnimatedKnot.back().KnotIDStart <= sid && sid < m_ListOfAnimatedKnot.back().KnotIDStart_Limit ) { 02309 m_ListOfAnimatedKnot.back().KnotIDStart_Limit = sid; 02310 } 02311 if ( m_ListOfAnimatedKnot.back().KnotIDEnd_Limit < sid && sid <= m_ListOfAnimatedKnot.back().KnotIDEnd ) { 02312 m_ListOfAnimatedKnot.back().KnotIDEnd_Limit = eid; 02313 } 02314 } 02315 // Set the number of simulation loops for setting up the knot 02316 //m_ListOfAnimatedKnot.back().StepsLeftForSettingKnot = m_pParameters->NumOfNodes; 02317 m_ListOfAnimatedKnot.back().StepsLeftForSettingKnot = 1; 02318 02319 //* 02320 // DEBUG 02321 { 02322 std::stringstream ss; 02323 ss << "after add, start--end IDs: " << m_ListOfAnimatedKnot.back().KnotIDStart 02324 << "--" << m_ListOfAnimatedKnot.back().KnotIDEnd 02325 << " : (" << m_ListOfAnimatedKnot.back().KnotIDStart_Limit 02326 << ", " << m_ListOfAnimatedKnot.back().KnotIDEnd_Limit << ")" 02327 << "; knot size limit: " << m_ListOfAnimatedKnot.back().KnotSizeLimit; 02328 gDebugStr[9] = ss.str(); 02329 } 02330 //*/ 02331 } 02332 } 02333 else { 02334 std::cout << __FILE__ << ":" << __LINE__ << ": (!bEndIsGrabbed) does not implemented/supported!" << std::endl; 02335 } 02336 return true; 02337 } //END: Add an animated knot -- used with knot tying by Tyco Endo Stitch Device 02338 //----------------------------------------------------------------------------- 02339 #endif//TAPs_ADD_ANIMATED_KNOTS 02340 // END: Animating Knot Tying 02341 //============================================================================= 02342 02343 02344 02345 02346 //----------------------------------------------------------------------------- 02347 #if defined(__gl_h_) || defined(__GL_H__) 02348 //============================================================================= 02349 //----------------------------------------------------------------------------- 02350 template <typename T> 02351 void ElasticRodKR<T>::Draw () const 02352 { 02353 glPushAttrib( GL_ALL_ATTRIB_BITS ); 02354 glEnable( GL_BLEND ); 02355 glPushMatrix(); 02356 02357 //std::cout << "KR -> Draw\n"; 02358 02359 /* 02360 // Draw animated knot info 02361 { 02362 for ( unsigned int k = 0; k < m_ListOfAnimatedKnot.size(); ++k ) { 02363 02364 int S = m_ListOfAnimatedKnot[k].KnotIDStart; 02365 int E = m_ListOfAnimatedKnot[k].KnotIDEnd; 02366 02367 // Draw points 02368 glPointSize( 10 ); 02369 glDisable( GL_DEPTH_TEST ); 02370 glDisable( GL_LIGHTING ); 02371 glBegin( GL_POINTS ); 02372 02373 for ( int i = 0; i <= m_ListOfAnimatedKnot[k].NumOfCrossings*2; ++i ) { 02374 glColor3f( 1, 0, 0 ); 02375 glVertex3fv( (*m_pNodeList)[S+i].Centerline[*m_pIdxCurr].GetPosition().GetDataFloat() ); 02376 glColor3f( 0, 0, 1 ); 02377 glVertex3fv( (*m_pNodeList)[E-i].Centerline[*m_pIdxCurr].GetPosition().GetDataFloat() ); 02378 02379 //std::cout << "S: " << S+i << "\n"; 02380 //std::cout << "E: " << E-i << "\n"; 02381 } 02382 glEnd(); 02383 02384 // Draw link lines 02385 glColor3f( 0, 0, 1 ); 02386 glLineWidth( 5 ); 02387 glBegin( GL_LINE_STRIP ); 02388 for ( int i = 0; i <= m_ListOfAnimatedKnot[k].NumOfCrossings*2; ++i ) { 02389 glColor3f( 1, 0, 0 ); 02390 glVertex3fv( (*m_pNodeList)[S+i].Centerline[*m_pIdxCurr].GetPosition().GetDataFloat() ); 02391 } 02392 glEnd(); 02393 glBegin( GL_LINE_STRIP ); 02394 for ( int i = 0; i <= m_ListOfAnimatedKnot[k].NumOfCrossings*2; ++i ) { 02395 glColor3f( 0, 0, 1 ); 02396 glVertex3fv( (*m_pNodeList)[E-i].Centerline[*m_pIdxCurr].GetPosition().GetDataFloat() ); 02397 } 02398 glEnd(); 02399 } 02400 } 02401 //*/ 02402 02403 /* 02404 // Draw animated knot info 02405 { 02406 // Draw points 02407 glPointSize( 5 ); 02408 glBegin( GL_POINTS ); 02409 for ( int i = 0; i < m_AnimatedKnot.NumOfPairs; ++i ) { 02410 glColor3f( 1, 0, 0 ); 02411 glVertex3fv( (*m_pNodeList)[m_AnimatedKnot.ListANodes[i]].Centerline[*m_pIdxCurr].GetPosition().GetDataFloat() ); 02412 glColor3f( 0, 0, 1 ); 02413 glVertex3fv( (*m_pNodeList)[m_AnimatedKnot.ListBNodes[i]].Centerline[*m_pIdxCurr].GetPosition().GetDataFloat() ); 02414 } 02415 glEnd(); 02416 02417 // Draw link lines 02418 glBegin( GL_LINES ); 02419 glColor3f( 0, 0, 1 ); 02420 glLineWidth(3); 02421 for ( int i = 0; i < m_AnimatedKnot.NumOfPairs; ++i ) { 02422 glColor3f( 1, 0, 0 ); 02423 glVertex3fv( (*m_pNodeList)[m_AnimatedKnot.ListANodes[i]].Centerline[*m_pIdxCurr].GetPosition().GetDataFloat() ); 02424 glColor3f( 0, 0, 1 ); 02425 glVertex3fv( (*m_pNodeList)[m_AnimatedKnot.ListBNodes[i]].Centerline[*m_pIdxCurr].GetPosition().GetDataFloat() ); 02426 } 02427 glEnd(); 02428 } 02429 //*/ 02430 02431 glPopMatrix(); 02432 glPopAttrib(); 02433 } 02434 //----------------------------------------------------------------------------- 02435 template <typename T> 02436 void ElasticRodKR<T>::DrawForDebug () const 02437 { 02438 //if ( m_BVHTree ) { 02439 // m_BVHTree->Draw(); 02440 //} 02441 02442 Vector3<T> direction = GetProjDirection(); 02443 02444 // Draw the three points for fiding a projection direction 02445 glPushAttrib( GL_ALL_ATTRIB_BITS ); 02446 glPushMatrix(); 02447 glEnable( GL_COLOR_MATERIAL ); 02448 glColor3f( 0, 1, 0 ); 02449 glPointSize( 25 ); 02450 glBegin( GL_LINE_LOOP ); 02451 glVertex3fv( m_NodesForProjPoints[0]->Centerline[*m_pIdxCurr].GetPosition().GetDataFloat() ); 02452 glVertex3fv( m_NodesForProjPoints[1]->Centerline[*m_pIdxCurr].GetPosition().GetDataFloat() ); 02453 glVertex3fv( m_NodesForProjPoints[2]->Centerline[*m_pIdxCurr].GetPosition().GetDataFloat() ); 02454 glEnd(); 02455 glTranslatef( 02456 m_NodesForProjPoints[1]->Centerline[*m_pIdxCurr].GetPosition()[0], 02457 m_NodesForProjPoints[1]->Centerline[*m_pIdxCurr].GetPosition()[1], 02458 m_NodesForProjPoints[1]->Centerline[*m_pIdxCurr].GetPosition()[2] 02459 ); 02460 m_pOGLUsefulObj->DrawOneHeadArrow( direction, 0.2 ); 02461 glPopMatrix(); 02462 glPopAttrib(); 02463 } 02464 //----------------------------------------------------------------------------- 02465 //============================================================================= 02466 #endif // #if defined(__gl_h_) || defined(__GL_H__) 02467 02468 //============================================================================= 02469 END_NAMESPACE_TAPs 02470 //----------------------------------------------------------------------------- 02471 //34567890123456789012345678901234567890123456789012345678901234567890123456789 02472 //--+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----