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