![]() |
TAPs 0.7.7.3
|
00001 /****************************************************************************** 00002 TAPsModelStrand.hpp 00003 ******************************************************************************/ 00016 /****************************************************************************** 00017 SUKITTI PUNAK (07/10/2005) 00018 UPDATE (12/09/2010) 00019 ******************************************************************************/ 00020 #ifndef TAPs_STRAND_MODEL_HPP 00021 #define TAPs_STRAND_MODEL_HPP 00022 00023 //============================================================================= 00025 //----------------------------------------------------------------------------- 00026 //----------------------------------------------------------------------------- 00027 //============================================================================= 00028 00029 //#define TAPs_STRAND_DEBUG 00031 00032 //#ifdef TAPs_STRAND_DEBUG 00033 #if (defined TAPs_STRAND_DEBUG || defined TAPs_STRAND_SPECIAL_DEBUG ) 00034 int special_debug_knotID = -1; 00035 #endif//TAPs_STRAND_DEBUG 00036 00037 //============================================================================= 00058 //----------------------------------------------------------------------------- 00059 //#define TAPs_STRAND_LOCK_SEGMENTS 00060 #ifdef TAPs_STRAND_LOCK_SEGMENTS 00061 #endif//TAPs_STRAND_LOCK_SEGMENTS 00062 //============================================================================= 00063 00064 //============================================================================= 00070 //----------------------------------------------------------------------------- 00071 //#define TAPs_STRAND_KNOT_RECOGNITION_ADD_ONs 00072 //----------------------------------------------------------------------------- 00073 #ifdef TAPs_STRAND_KNOT_RECOGNITION_ADD_ONs 00074 bool m_bIsClumpped = false; 00075 #endif//TAPs_STRAND_KNOT_RECOGNITION_ADD_ONs 00076 //----------------------------------------------------------------------------- 00077 //============================================================================= 00078 00079 //============================================================================= 00087 //----------------------------------------------------------------------------- 00088 //#define TAPs_STRAND_KNOT_CONTROL 00089 //----------------------------------------------------------------------------- 00090 #ifdef TAPs_STRAND_KNOT_CONTROL 00091 00092 00093 #ifdef TAPs_STRAND_KNOT_RECOGNITION_BY_DOWKER_NOTATION 00094 00095 //----------------------------------------------------------- 00101 //#define TAPs_PROJECTION_ALLOWS_MULTIPLE_CONTACT_POINTS 00102 //----------------------------------------------------------- 00103 00104 //----------------------------------------------------------- 00108 //#define TAPs_ALLOW_SETTING_PROJECTION_DIRECTION 00109 //----------------------------------------------------------- 00110 00111 //----------------------------------------------------------- 00115 //#define TAPs_STRAND_KNOT_CONTROL_USE_DOWKER_NOTATION_VERSION_01 00116 #ifdef TAPs_STRAND_KNOT_CONTROL_USE_DOWKER_NOTATION_VERSION_01 00117 00118 #define TAPs_PROJECTION_ALLOWS_MULTIPLE_CONTACT_POINTS 00119 #define TAPs_ALLOW_SETTING_PROJECTION_DIRECTION 00120 00121 #include <ctime> 00122 00123 #endif//TAPs_STRAND_KNOT_CONTROL_USE_DOWKER_NOTATION_VERSION_01 00124 //----------------------------------------------------------- 00125 00126 #endif//TAPs_STRAND_KNOT_RECOGNITION_BY_DOWKER_NOTATION 00127 00128 #endif//TAPs_STRAND_KNOT_CONTROL 00129 //----------------------------------------------------------------------------- 00130 //============================================================================= 00131 00132 //============================================================================= 00142 //----------------------------------------------------------------------------- 00143 //#define TAPs_STRAND_KNOT_RECOGNITION_BY_DOWKER_NOTATION 00144 //----------------------------------------------------------------------------- 00145 #ifdef TAPs_STRAND_KNOT_RECOGNITION_BY_DOWKER_NOTATION 00146 #include "../Data/TAPsDatabaseDowkerNotation.hpp" 00147 #endif//TAPs_STRAND_KNOT_RECOGNITION_BY_DOWKER_NOTATION 00148 //----------------------------------------------------------------------------- 00149 //============================================================================= 00150 00151 #include "TAPsOpenGLModel.hpp" 00152 00153 #include "../Physics/TAPsPhysics.hpp" 00154 #include "../Simulation/TAPsListOfODESolvers.hpp" 00155 #include <set> 00156 #include "../CD/TAPsBVHTree.hpp" 00157 #include "../CD/TAPsMultiBoundingVolume.hpp" // for collision detection by bounding volumes 00158 00160 //#define TAPs_USE_EXTERNAL_ODE_SOLVER 00161 00162 #ifdef TAPs_USE_EXTERNAL_ODE_SOLVER 00163 #else //TAPs_USE_EXTERNAL_ODE_SOLVER 00164 #define TAPs_USE_INTERNAL_ODE_SOLVER_EULER 00165 #include "../Gadgets/TAPsCircularCounter.hpp" 00166 #endif//TAPs_USE_EXTERNAL_ODE_SOLVER 00167 00168 // Add On Fns 00169 //#include "AddOn/TAPsAddOnForStrandModelCatmullRom.hpp" 00170 00171 BEGIN_NAMESPACE_TAPs__OpenGL 00172 //============================================================================= 00173 template <typename T> 00174 class ModelStrand : public /*virtual*/ OpenGLModel<T> { 00175 //------------------------------------------------------------------------- 00176 // (Friend Fn) put it through ostream 00177 friend std::ostream & operator<< ( std::ostream &output, ModelStrand<T> const &o ) 00178 { 00179 output << "\n======================\n" 00180 << "TAPs::ModelStrand<" 00181 << typeid(T).name() << "> Class:\n" 00182 << "======================\n"; 00183 //---------------------------------------------------------------- 00184 output << "\n# of Links " << o.m_iNoLinks 00185 << "\nEach link has length " << o.m_tLinkLength 00186 << " and weight " << o.m_tPointWeight << "\n"; 00187 return output; 00188 } 00189 //----------------------------------------------------------------------------- 00190 // Member Functions ------------------------------------------------------------ 00191 public: 00192 //------------------------------------------------------------------------- 00193 // Constructor(s) 00194 ModelStrand (); 00195 ModelStrand ( 00196 int iNoLinks, // # of links/segments 00197 T tLength, // the strand length 00198 T tWeight, // the strand weight 00199 Vector3<T> & posOfVertex0 = Vector3<T>(), // position of the 1st node 00200 T tRadius = 0.05 00201 ); 00202 /* 00203 ModelStrand ( 00204 int iNoLinks, // # of links/segments 00205 T tLength, // the strand length 00206 T tWeight, // the strand weight 00207 Vector3<T> & posOfVertex0, // position of the 1st node 00208 T tRadius, 00209 T tKRatioOfStretchingAllowed, 00210 T tKRatioOfCompressionAllowed, 00211 T tKStretching, 00212 T tKBending, 00213 T tKTwisting, 00214 T tKFriction, 00215 T tKContact, 00216 T tKGravity 00217 ); 00218 //*/ 00219 //------------------------------------------------------------------------- 00220 // Destructor 00221 virtual ~ModelStrand (); 00222 //------------------------------------------------------------------------- 00223 // Abstract Virtual Fn(s) from Model<T> 00224 virtual T GetMaxHalfLength () const { return m_iNoLinks * m_tLinkLength; } 00225 virtual void Initialize () {}; // Need it for OpenGL Model Hierarchy 00226 virtual void Reset (); 00227 //------------------------------------------------------------------------- 00228 // Abstract Virtual Fn(s) from ColDetSupport<T> 00229 // Collision Detection Fn(s) 00230 virtual void CalBoundingAABB () {}; 00231 virtual void CalBoundingEllipsoid () {}; 00232 virtual void CalBoundingSphere () {}; 00233 //------------------------------------------------------------------------- 00234 // Get/Set Fn(s) 00235 inline virtual int GetNumberOfLinks () { return m_iNoLinks; } 00236 inline int GetNumberOfStrandLinksWithoutNeedle () { return m_iNoLinks; } 00237 inline T GetLength () { return m_iNoLinks * m_tLinkLength; } 00238 inline T GetLinkLength () { return m_tLinkLength; } 00239 inline T GetWeight () { return (m_iNoLinks+1) * m_tPointWeight; } 00240 inline void SetWeight ( T w ) { m_tPointWeight = w / (m_iNoLinks+1); } 00241 inline T GetPointWeight () { return m_tPointWeight; } 00242 inline void SetPointWeight ( T w ) { m_tPointWeight = w; } 00243 inline T GetRadius () { return m_tRadius; } 00244 inline void SetRadius ( T val ) { m_tRadius = val; } 00245 00247 T GetCurrentLength () 00248 { 00249 T currLen = 0; 00250 for ( int i = 0; i < m_iNoLinks; ++i ) { 00251 currLen += ( m_prVertex[i+1] - m_prVertex[i] ).Length(); 00252 } 00253 return currLen; 00254 } 00255 00256 // Fix Point Status 00257 inline bool GetFixStatusOfPtNo ( int i ) { return m_prIsFixed[i]; } 00258 inline void SetFixStatusOfPtNo ( int i, bool b ); 00259 inline void ToggleFixStatusOfPtNo ( int i ); 00260 inline unsigned int GetNumFixedPts () 00261 { return static_cast<unsigned int>( m_setOfFixedPts.size() ) }; 00262 00264 void FixSegment ( int start, int end ); 00265 00266 void UnfixSegment ( int start, int end ); 00267 00268 inline virtual Vector3<T> const & RetPointPosition ( int i ) const; 00269 inline virtual Vector3<T> & RetPointPosition ( int i ); 00270 00271 inline virtual Vector3<T> GetPointPosition ( int i ) const; 00272 inline virtual void SetPointPosition ( 00273 int i, const Vector3<T> & position, 00274 //T tMoveDistanceLimit = 100, 00275 MultiBoundingVolume<T> const * const mbvObj = NULL, 00276 TransformationSupport<T> const * const pTransform = NULL 00277 ); 00278 inline virtual void ChangeOnlyPointPositionByAddedWithThisVector ( int i, const Vector3<T> & adjuster ) 00279 { 00280 m_prVertex[i] += adjuster; 00281 } 00282 //---------------------------------------------------------------- 00283 // Get/Set Fn(s) for Parameters 00284 inline T GetPercentOfStretchingAllowed () const { return m_tKRatioOfStretchingAllowed * 100.0; } 00285 inline T GetPercentOfCompressionAllowed () const { return m_tKRatioOfCompressionAllowed * 100.0; } 00286 inline T GetKStretching () const { return m_tKStretching; } 00287 inline T GetKBending () const { return m_tKBending; } 00288 inline T GetKTwisting () const { return m_tKTwisting; } 00289 inline T GetKFriction () const { return m_tKFriction; } 00290 inline T GetKContact1 () const { return m_tKContact1; } 00291 inline T GetKContact2 () const { return m_tKContact2; } 00292 inline T GetKGravity () const { return m_tKGravity; } 00293 //------------------------------------------- 00294 inline void SetPercentOfStretchingAllowed ( T val ) { m_tKRatioOfStretchingAllowed = val / 100.0; } 00295 inline void SetPercentOfCompressionAllowed ( T val ) { m_tKRatioOfCompressionAllowed = val / 100.0; } 00296 inline void SetKStretching ( T val ) { m_tKStretching = val; } 00297 inline void SetKBending ( T val ) { m_tKBending = val; } 00298 inline void SetKTwisting ( T val ) { m_tKTwisting = val; } 00299 inline void SetKFriction ( T val ) { m_tKFriction = val; } 00300 inline void SetKContact1 ( T val ) { m_tKContact1 = val; } 00301 inline void SetKContact2 ( T val ) { m_tKContact2 = val; } 00302 inline void SetKGravity ( T val ) { m_tKGravity = val; } 00303 //------------------------------------------- 00304 inline T GetMoveStepDistAllowed () const { return m_tMoveStepDistAllowed; } 00305 inline void SetMoveStepDistAllowed ( T v ) { m_tMoveStepDistAllowed = v; } 00306 //---------------------------------------------------------------- 00307 00312 //#define TAPs_STRAND_ENABLE_DAMPING_LIMIT 00313 #ifdef TAPs_STRAND_ENABLE_DAMPING_LIMIT 00314 inline void ResetCounterDamping () { uiCounterDamping = 0; } 00315 inline void SetCounterDamping ( unsigned int val ) { uiCounterDamping = val; } 00316 inline unsigned int GetLimitCounterDamping () const { return uiLimitCounterDamping; } 00317 inline void SetLimitCounterDamping ( unsigned int i ) { uiLimitCounterDamping = i; } 00318 inline bool IsLimitCouterDampingReached () { return uiLimitCounterDamping <= uiCounterDamping; } 00319 #endif//TAPs_STRAND_ENABLE_DAMPING_LIMIT 00320 00321 //---------------------------------------------------------------- 00322 // Return size of too stretch strand parts 00323 int ReportTooStretchStrandSections ( 00324 const int * leftPts, 00325 const int * rightPts ) 00326 { 00327 leftPts = m_aiTooStretchLeftPts; 00328 rightPts = m_aiTooStretchRightPts; 00329 return m_iNumTooStretchSections; 00330 } 00331 //protected: 00332 int m_iNumTooStretchSections; 00333 int m_aiTooStretchLeftPts[20]; 00334 int m_aiTooStretchRightPts[20]; 00335 public: 00336 //---------------------------------------------------------------- 00337 // User adjustable parameters 00338 // void SetKstiff ( T k ) { m_tKstiff = k; } 00339 // T GetKstiff () const { return m_tKstiff; } 00340 // void SetKfollow ( T k ) { m_tKfollow = k; } 00341 // T GetKfollow () const { return m_tKfollow; } 00342 //---------------------------------------------------------------- 00343 // Collision Detection 00344 BVHTree<T> * GetBVHTree () // use sphere node for BVHTree 00345 { return m_BVHTree; } 00346 //---------------------------------------------------------------- 00347 // SetDispLinks() --> use Chaikin (quardratic) subdivision to set display 00348 // links according to the original links. 00349 void SetDisplayLinks (); 00350 protected: 00351 //========================================================================== 00352 // Helper Fn(s) 00353 void AllocateLinkProps ( Vector3<T> &posOfVertex0 ); // for assisting ctor 00354 //================================================================ 00355 // For Simulation 00356 //---------------------------------------------------------------- 00357 public: 00358 //------------------------------------------------------------------------- 00359 // Collided Nodes 00360 virtual std::vector< BVHNode<T> * > & GetListOfCollidedNodes() { return m_svCollidedNode; } 00361 virtual std::vector< BVHNode<T> * > & GetListOfCollidedNodesThat() { return m_svCollidedNodeThat; } 00362 protected: 00363 std::vector< BVHNode<T> * > m_svCollidedNode; 00364 std::vector< BVHNode<T> * > m_svCollidedNodeThat; 00365 //---------------------------------------------------------------- 00366 protected: 00367 /* 00368 //---------------------------------------------------------- 00369 // pos is from 0 to #links 00370 inline Vector3<T> CalForceStretchingAndCompression ( int pos ); 00371 inline Vector3<T> CalForceBending ( int pos ); 00372 inline Vector3<T> CalForceTwisting ( int pos ); 00373 inline Vector3<T> CalForceFriction ( int pos ); 00374 inline Vector3<T> CalForceContact ( int pos ); 00375 inline Vector3<T> CalForceGravity ( int pos ); 00376 //------------------------------------------- 00377 // Link No is from 0 to #links - 1 00378 inline Vector3<T> GetLinkUnitVector ( int linkNo ); 00379 inline T GetLinkCurrentLength ( int linkNo ); 00380 //*/ 00381 //---------------------------------------------------------- 00382 void CalTorqueTorsion (); 00383 void CalTorqueBending (); 00384 //---------------------------------------------------------- 00385 void SimGravity ( T tCurrent, T tNext ); 00386 void SimByForce ( T tCurrent, T tNext ); 00387 //--------------------------------------------------------------- 00388 // Collision Detection and Response for Strand with An MBV Object 00389 protected: 00390 void CDAndRForStrandWithAnMBVObj ( 00391 int iLeader, int iFollower, 00392 MultiBoundingVolume<T> const * const pMBV, 00393 TransformationSupport<T> const * const pTransform = NULL ); 00394 //---------------------------------------------------------- 00395 int FindClosestStrandPtToPt ( Vector3<T> const & point ); 00396 //---------------------------------------------------------- 00397 //---------------------------------------------------------- 00398 public: 00399 //---------------------------------------------------------- 00400 // Collision Detection 00401 void BuildBVHTree (); 00402 BVHTree<T> * BuildBVHTreeRecursively ( 00403 int startID, 00404 BVHNode<T> ** childNodeList, 00405 int numOfChildNodes ); 00406 public: 00407 void UpdateBVHTree (); 00408 // Assume no intersections between immediate adjacent links 00409 void CheckSelfIntersections (); 00410 protected: 00411 void UpdateBVHNodeRecursively ( BVHNode<T> * node ); 00412 void CheckSelfIntersectionsNextLevelRecursively ( 00413 BVHNode<T> * node1, BVHNode<T> * node2 ); 00414 T CheckSelfIntersectionsRecursively ( 00415 BVHNode<T> * node1, BVHNode<T> * node2 ); 00416 //---------------------------------------------------------- 00417 00418 //============================================================================= 00419 #ifdef TAPs_STRAND_KNOT_RECOGNITION_BY_DOWKER_NOTATION 00420 //----------------------------------------------------------------------------- 00421 // Knot Recognition by Dowker Notation 00443 public: 00444 00445 #ifdef TAPs_ALLOW_SETTING_PROJECTION_DIRECTION 00446 00447 00448 Vector3<T> GetProjectionDirection ( 00449 Vector3<T> const & pt1, Vector3<T> const & pt2, Vector3<T> const & pt3 ); 00450 00452 int CheckSelfCrossingForKnotRecognition ( Vector3<T> const & projectionDirection ); 00453 00455 void CheckSelfCrossingsNextLevelRecursively ( 00456 BVHNode<T> * node1, BVHNode<T> * node2, 00457 Vector3<T> const & projectionDirection 00458 ); 00459 T CheckSelfCrossingsRecursively ( 00460 BVHNode<T> * node1, BVHNode<T> * node2, 00461 Vector3<T> const & projectionDirection 00462 ); 00463 T TestOverlapCircle ( 00464 BVHNode<T> * node1, BVHNode<T> * node2, 00465 Vector3<T> const & projectionDirection 00466 ); 00467 void CheckCrossings ( 00468 BVHNode<T> * node1, BVHNode<T> * node2, 00469 Vector3<T> const & projectionDirection 00470 ); 00471 #endif//TAPs_ALLOW_SETTING_PROJECTION_DIRECTION 00472 00474 int CheckSelfCrossingForKnotRecognition () 00475 { 00476 // In z-direction 00477 // Find the Dowker notation on the current strand 00478 CheckSelfCrossingForKnotRecognition_zDir(); 00479 // Find the knot that match with the Dowker notation 00480 int knotID = DowkerNotationToKnotName(); 00481 if ( knotID >= 0 ) { 00482 //std::cout << "zDir found Knot ID# " << knotID << "\n"; 00483 return knotID; 00484 } 00485 00486 //* 00487 // In y-direction 00488 // Find the Dowker notation on the current strand 00489 CheckSelfCrossingForKnotRecognition_yDir(); 00490 // Find the knot that match with the Dowker notation 00491 knotID = DowkerNotationToKnotName(); 00492 if ( knotID >= 0 ) { 00493 //std::cout << "yDir found Knot ID# " << knotID << "\n"; 00494 return knotID; 00495 } 00496 // In x-direction 00497 // Find the Dowker notation on the current strand 00498 CheckSelfCrossingForKnotRecognition_xDir(); 00499 // Find the knot that match with the Dowker notation 00500 knotID = DowkerNotationToKnotName(); 00501 if ( knotID >= 0 ) { 00502 //std::cout << "xDir found Knot ID# " << knotID << "\n"; 00503 return knotID; 00504 } 00505 //*/ 00506 00507 //------------------------------------------------- 00508 #ifdef TAPs_STRAND_KNOT_RECOGNITION_ADD_ONs 00509 // Check Clumped 00510 if ( m_iNumCrossingPairs > 1 ) { 00511 if ( m_ucTrackingKnot != Data::DatabaseDowkerNotation::KNOT::UNDEFINED ) { 00512 T sphereRadius = m_tLinkLength * 10.0; 00513 CheckClumped( m_iKnotStartPt, m_iKnotEndPt, sphereRadius ); 00514 if ( IsClumped() ) { 00515 #ifdef TAPs_STRAND_DEBUG 00516 std::cout << "CLUMPED: true (" << m_iKnotStartPt << "," << m_iKnotEndPt << ")" << "\n"; 00517 #endif//TAPs_STRAND_DEBUG 00518 00519 m_uiCounterForFixingKnot = m_uiCounterThreshold+1; 00520 00521 #ifdef TAPs_STRAND_DEBUG 00522 std::cout << "RET: " << m_ucTrackingKnot << "\n"; 00523 #endif//TAPs_STRAND_DEBUG 00524 00525 return m_ucTrackingKnot; 00526 } 00527 } 00528 else { 00529 //std::cout << "CLUMPED: false (" << m_iKnotStartPt << "," << m_iKnotEndPt << ")" << std::endl; 00530 } 00531 } 00532 #endif//TAPs_STRAND_KNOT_RECOGNITION_ADD_ONs 00533 //------------------------------------------------- 00534 00535 // return -1 if not found, otherwise the knotID 00536 //std::cout << "Not found Knot ID# " << knotID << "\n"; 00537 return knotID; 00538 } 00539 void CheckSelfCrossingForKnotRecognition_zDir (); 00540 void CheckSelfCrossingForKnotRecognition_yDir (); 00541 void CheckSelfCrossingForKnotRecognition_xDir (); 00542 00546 #ifdef TAPs_ALLOW_SETTING_PROJECTION_DIRECTION 00547 std::string GetKnotName ( Vector3<T> const & projectionDirection ); 00548 #else //TAPs_ALLOW_SETTING_PROJECTION_DIRECTION 00549 std::string GetKnotName (); 00550 #endif//TAPs_ALLOW_SETTING_PROJECTION_DIRECTION 00551 00562 int DowkerNotationToKnotName ( std::string * knotName = NULL ); 00563 //unsigned char GetNumKnots () { return m_ucNumKnots; } 00564 00566 void PrtDowkerNotation () 00567 { 00568 std::cout << "Dowker Notation:"; 00569 for ( int i = 0; i < m_iNumCrossingPairs; ++i ) { 00570 std::cout << " " << m_iaDowkerNotation[i]; 00571 } 00572 std::cout << "\n"; 00573 } 00574 00576 int GetKnotStartPt () { return m_iKnotStartPt; }; 00578 int GetKnotEndPt () { return m_iKnotEndPt; }; 00579 00580 protected: 00581 // Data Members ------------------------------------------------- 00582 int m_iMaxCrossingPairs, m_iNumCrossingPairs; 00583 int * m_iaDowkerNotation; 00584 int m_iKnotStartPt, m_iKnotEndPt; 00585 #ifdef TAPs_PROJECTION_ALLOWS_MULTIPLE_CONTACT_POINTS 00586 00635 int * m_iaCrossingCounters; 00636 class IC_Crossing { public: 00637 int number, id; 00638 IC_Crossing( int number, int id ) { this->number = number; this->id = id; } 00639 }; 00640 std::list< IC_Crossing > m_crossings; 00641 void InsertToList( int number, int id ) 00642 { 00643 // Add at the start 00644 if ( m_crossings.size() == 0 ) { 00645 m_crossings.push_back( IC_Crossing( number, id ) ); 00646 return; 00647 } 00648 // Insert in a middle 00649 std::list< IC_Crossing >::iterator it = m_crossings.begin(); 00650 while ( it != m_crossings.end() ) { 00651 if ( (*it).id > id ) { 00652 m_crossings.insert( it, IC_Crossing( number, id ) ); 00653 return; 00654 } 00655 ++it; 00656 } 00657 // Add at the end 00658 m_crossings.push_back( IC_Crossing( number, id ) ); 00659 } 00660 00661 //#define DEBUG_TOO 00662 #ifdef DEBUG_TOO 00663 std::list< IC_Crossing > m_crossings_TOO; 00664 void InsertToList_TOO( int number, int id ) 00665 { 00666 // Add at the start 00667 if ( m_crossings_TOO.size() == 0 ) { 00668 m_crossings_TOO.push_back( IC_Crossing( number, id ) ); 00669 return; 00670 } 00671 // Insert in a middle 00672 std::list< IC_Crossing >::iterator it = m_crossings_TOO.begin(); 00673 while ( it != m_crossings_TOO.end() ) { 00674 if ( (*it).id > id ) { 00675 m_crossings_TOO.insert( it, IC_Crossing( number, id ) ); 00676 return; 00677 } 00678 ++it; 00679 } 00680 // Add at the end 00681 m_crossings_TOO.push_back( IC_Crossing( number, id ) ); 00682 } 00683 #endif//DEBUG_TOO 00684 00685 #else //TAPs_PROJECTION_ALLOWS_MULTIPLE_CONTACT_POINTS 00686 int * m_iaCrossingsForDowkerNotation; 00687 #endif//TAPs_PROJECTION_ALLOWS_MULTIPLE_CONTACT_POINTS 00688 00689 //#ifdef TAPs_STRAND_DEBUG 00690 #if (defined TAPs_STRAND_DEBUG || defined TAPs_STRAND_SPECIAL_DEBUG ) 00691 public: 00692 void PrintLinkLengths () 00693 { 00694 std::cout << "\n----------\n"; 00695 std::cout << "LINK INFO:\n"; 00696 std::cout << "----------\n"; 00697 std::cout << "(Link Length: " << m_tLinkLength << ")\n"; 00698 for ( int i = 0; i < m_iNoLinks; ++i ) { 00699 std::cout << "Link# " << i << ":\t"; 00700 std::cout << (m_prVertex[i] - m_prVertex[i+1]).Length(); 00701 std::cout << "\n"; 00702 } 00703 std::cout << "----------\n\n"; 00704 } 00705 00706 std::vector<int> debug_crosses; 00707 std::vector<int> debug_crossesID; 00708 00709 std::string Debug_Str () 00710 { 00711 std::ostringstream ss; 00712 ss << "# of crossing pairs: " << m_iNumCrossingPairs << "\n"; 00713 ss << "Cross#: "; 00714 for ( int i = 0; i < static_cast<int>(debug_crosses.size()); ++i ) { 00715 ss << "\t" << debug_crosses[i]; 00716 } 00717 ss << "\n"; 00718 00719 ss << "ID#: "; 00720 for ( int i = 0; i < static_cast<int>(debug_crossesID.size()); ++i ) { 00721 ss << "\t" << debug_crossesID[i]; 00722 } 00723 ss << "\n"; 00724 00725 ss << "Dowker#:"; 00726 for ( int i = 0; i < static_cast<int>(debug_crossesID.size()); ++i ) { 00727 ss << "\t" << m_iaDowkerNotation[i]; 00728 } 00729 ss << "\n"; 00730 00731 ss << "Recognized Knot ID: " << special_debug_knotID << "\n"; 00732 00733 ss << "Tracking Knot: " << m_ucTrackingKnot 00734 << " Accumulate: " << m_uiCounterForFixingKnot 00735 << " Knot Len: " << GetKnotEndPt() << " - " << GetKnotStartPt() << " = " << GetKnotEndPt() - GetKnotStartPt() 00736 << " Acc Length: " << m_uiLengthAccumulateTarget 00737 << " m_uiMinLengthThreshold: " << m_uiMinLengthThreshold 00738 << "\n\n"; 00739 00740 return ss.str(); 00741 } 00742 #endif//TAPs_STRAND_DEBUG 00743 00744 00745 #ifdef TAPs_STRAND_KNOT_RECOGNITION_ADD_ONs 00746 00756 bool CheckClumped ( int startPt, int endPt, T sphereRadius ); 00757 bool IsClumped () { return m_bIsClumped; } 00758 00759 bool m_bIsClumped; 00760 #endif//TAPs_STRAND_KNOT_RECOGNITION_ADD_ONs 00761 00762 //unsigned char m_ucNumKnots; //! Number of knots formed on the strand 00763 void CreateDataSpaceForKnotRecognitionByDowkerNotation (); 00764 void DeleteDataSpaceForKnotRecognitionByDowkerNotation (); 00765 00766 // Member Functions --------------------------------------------- 00767 //--------------------------------------------------------------- 00769 //--------------------------------------------------------------- 00770 void CheckSelfCrossingsNextLevelRecursively_zDir ( 00771 BVHNode<T> * node1, BVHNode<T> * node2 ); 00772 T CheckSelfCrossingsRecursively_zDir ( 00773 BVHNode<T> * node1, BVHNode<T> * node2 ); 00774 T TestOverlapCircle_zDir ( BVHNode<T> * node1, BVHNode<T> * node2 ); 00775 void CheckCrossings_zDir ( 00776 BVHNode<T> * node1, BVHNode<T> * node2 ); 00777 //--------------------------------------------------------------- 00778 00779 //--------------------------------------------------------------- 00781 //--------------------------------------------------------------- 00782 void CheckSelfCrossingsNextLevelRecursively_yDir ( 00783 BVHNode<T> * node1, BVHNode<T> * node2 ); 00784 T CheckSelfCrossingsRecursively_yDir ( 00785 BVHNode<T> * node1, BVHNode<T> * node2 ); 00786 T TestOverlapCircle_yDir ( BVHNode<T> * node1, BVHNode<T> * node2 ); 00787 void CheckCrossings_yDir ( 00788 BVHNode<T> * node1, BVHNode<T> * node2 ); 00789 //--------------------------------------------------------------- 00790 00791 //--------------------------------------------------------------- 00793 //--------------------------------------------------------------- 00794 void CheckSelfCrossingsNextLevelRecursively_xDir ( 00795 BVHNode<T> * node1, BVHNode<T> * node2); 00796 T CheckSelfCrossingsRecursively_xDir ( 00797 BVHNode<T> * node1, BVHNode<T> * node2 ); 00798 T TestOverlapCircle_xDir ( BVHNode<T> * node1, BVHNode<T> * node2 ); 00799 void CheckCrossings_xDir ( 00800 BVHNode<T> * node1, BVHNode<T> * node2 ); 00801 //--------------------------------------------------------------- 00802 00803 //=============================================================== 00804 00805 //----------------------------------------------------------------------------- 00806 #endif//TAPs_STRAND_KNOT_RECOGNITION_BY_DOWKER_NOTATION 00807 //============================================================================= 00808 00809 //---------------------------------------------------------- 00810 // REMARK: DxDt has to be static so that we can pass it to 00811 // ODESolver Fn. 00812 // But we don't want StateToArray and ArrayToState be static. 00813 // Therefore, we need to pass userData, i.e. this pointer 00814 // as a void pointer. 00815 static bool DxDt ( 00816 T dt, // i/p: time step 00817 Simulation::VectorSet<T> &x, // i/p: array x = {pos, vel} 00818 Simulation::VectorSet<T> &xdot, // o/p: array xdot = {vel, accel} 00819 void *userData // o/p: array of user data 00820 ); 00821 //---------------------------------------------------------- 00822 void StateToArray ( T *dst ); // copy Strand states to dst array 00823 void ArrayToState ( T *src ); // copy src array to Strand states 00824 void DdtStateToArray ( T *xdot, T dt ); // copy d/dt Strand states to dst (xdot) array 00825 void ClearForces (); // clear (all) forces 00826 void ClearVelocities (); // clear (all) velocities 00827 public: 00828 virtual void AdvanceSimulation ( T tCurrent, T tNext ); 00829 virtual void AdvanceSimulation ( Simulation::SimClock<T> & simClock ); 00830 00831 //---------------------------------------------------------------- 00832 // Collision Detection 00833 virtual bool TestOverlapWith ( BVHTree<T> const * const that ); 00834 00835 //---------------------------------------------------------------- 00836 /* 00837 // Move the vertex # i by vector u 00838 void MoveVertexNo ( int i, Vector3<T> & u ); 00839 //---------------------------------------------------------------- 00840 // Twist the vertex i for deg degrees 00841 void TwistVertexNo ( int i, Real deg ); 00842 //---------------------------------------------------------------- 00843 // Move and Twist the vertex # i by vector u and deg respectively 00844 void MoveAndTwistVertexNo ( int i, Vector3<T> & u, Real deg ); 00845 */ 00846 //---------------------------------------------------------------- 00847 public: 00848 void BackToPreviousPosition ( int iVertexNo ) 00849 { m_prVertex[ iVertexNo ] = m_prVertexPrev[ iVertexNo ]; } 00850 void SavePreviousPositions (); 00851 void RestorePreviousPositions (); 00852 //--------------------------------------------------------------- 00853 //============================================================================= 00854 // Data Members ---------------------------------------------------------------- 00855 protected: 00856 00857 //============================================================================= 00858 // CUDA 00859 //----------------------------------------------------------------------------- 00860 // CUDA --------------------------------------------------------- 00861 #ifdef TAPs_USE_CUDA 00862 00863 bool CUDA_Initialize_All (); 00864 bool CUDA_Initialize_VertexList (); 00865 bool CUDA_Initialize_PrevVertexList (); 00866 void CUDA_Cleanup_All (); 00867 void CUDA_Cleanup_VertexList (); 00868 void CUDA_Cleanup_PrevVertexList (); 00869 void CUDA_CopyVertexToMem (); 00870 void CUDA_CopyMemToVertex (); 00871 void CUDA_CopyPrevVertexToMem (); 00872 void CUDA_CopyMemToPrevVertex (); 00873 00874 #ifdef TAPs_ADVANCED_SIMULATION 00875 bool CUDA_Initialize_SimFlagsList (); 00876 void CUDA_Cleanup_SimFlagsList (); 00877 void CUDA_CopySimFlagsToMem (); 00878 void CUDA_CopyMemToSimFlags (); 00879 00880 bool CUDA_Initialize_PosConstraintList (); 00881 void CUDA_Cleanup_PosConstraintList (); 00882 void CUDA_CopyPosConstraintToMem (); 00883 void CUDA_CopyMemToPosConstraint (); 00884 #endif//TAPs_ADVANCED_SIMULATION 00885 00886 inline void CUDA_SwapBuffers (); 00887 #endif//TAPs_USE_CUDA 00888 // CUDA --------------------------------------------------------- 00889 00890 #ifdef TAPs_USE_CUDA 00891 00892 00893 00894 unsigned int m_cudaID; 00895 float * m_cudaVertexList; 00896 float * m_cudaPrevVertexList; 00897 00898 #ifdef TAPs_ADVANCED_SIMULATION 00899 unsigned int * m_cudaSimFlagsList; 00900 float * m_cudaPosConstraintList; 00901 #endif//TAPs_ADVANCED_SIMULATION 00902 00903 // DEBUG 00904 void PrintDebug() 00905 { 00906 for ( int i = 0; i < 5; ++i ) { 00907 int idx = i*4; 00908 printf( "Host Vertex List # %d: %g %g %g %g\n", i, m_cudaVertexList[idx], m_cudaVertexList[idx+1], m_cudaVertexList[idx+2], m_cudaVertexList[idx+3] ); 00909 printf( "Host Prev Vertex List #%d: %g %g %g %g\n", i, m_cudaPrevVertexList[idx], m_cudaPrevVertexList[idx+1], m_cudaPrevVertexList[idx+2], m_cudaPrevVertexList[idx+3] ); 00910 } 00911 } 00912 #endif//TAPs_USE_CUDA 00913 //----------------------------------------------------------------------------- 00914 // CUDA 00915 //============================================================================= 00916 00917 //--------------------------------------------------------------- 00918 int m_iNoLinks; 00919 T m_tRadius; 00920 T m_tLinkLength; 00921 T m_tPointWeight; 00922 Vector3<T> * m_prVertex; 00923 Vector3<T> * m_prVertexPrevPos; 00924 Vector3<T> * m_prTempVertex1; 00925 Vector3<T> * m_prTempVertex2; 00926 Vector3<T> * m_prVelocity; 00927 Vector3<T> * m_prForce; 00928 T * m_prDegRot; 00929 00930 #ifdef TAPs_ADVANCED_SIMULATION 00931 public: 00932 00934 DS::SimulationFlags & RetSimulationFlagsOfVertexNo ( unsigned int i ) 00935 { return m_SimFlags[i]; } 00936 00938 DS::SimulationFlags const & RetSimulationFlagsOfVertexNo ( unsigned int i ) const 00939 { return m_SimFlags[i]; } 00940 00941 // t_TAPsAdvSimID AdvSimID; //!< advanced simulation ID 00942 static unsigned int TotalModels; 00943 00944 protected: 00945 DS::SimulationFlags * m_SimFlags; 00946 #endif//TAPs_ADVANCED_SIMULATION 00947 00948 protected: 00949 //=============================================================== 00950 // For simulation 00951 //--------------------------------------------------------------- 00952 #ifdef TAPs_USE_EXTERNAL_ODE_SOLVER 00953 00962 Simulation::ODESolver<T> * m_prODESolver; // ODE solver 00963 Simulation::VectorSet<T> x0; // #m_iStateSize 00964 Simulation::VectorSet<T> xEnd; // #m_iStateSize 00965 int m_iStateSize; // (#Links + 1) * 6; where 6 = 3 positions + 3 velocities (for x,y,z) 00966 00967 //#ifdef TAPs_USE_EXTERNAL_ODE_SOLVER 00968 #else //TAPs_USE_EXTERNAL_ODE_SOLVER 00969 00975 Vector3<T> ** m_prVertexPositionRecord; 00976 Vector3<T> ** m_prVertexVelocityRecord; 00977 Vector3<T> ** m_prVertexForceRecord; 00979 Vector3<T> * m_prVertexPrev; 00980 Vector3<T> * m_prVelocityPrev; 00981 Vector3<T> * m_prForcePrev; 00982 00983 private: 00984 CircularCounter<unsigned char> m_PositionCounter; 00985 CircularCounter<unsigned char> m_VelocityCounter; 00986 CircularCounter<unsigned char> m_ForceCounter; 00987 protected: 00988 inline void CycleBuffer () 00989 { 00990 m_prVertexPrev = m_prVertex; 00991 m_prVelocityPrev = m_prVelocity; 00992 m_prForcePrev = m_prForce; 00993 00994 m_prVertex = m_prVertexPositionRecord[ m_PositionCounter.CountUpAndReturnTheCountValue() ]; 00995 m_prVelocity = m_prVertexVelocityRecord[ m_VelocityCounter.CountUpAndReturnTheCountValue() ]; 00996 m_prForce = m_prVertexForceRecord[ m_ForceCounter.CountUpAndReturnTheCountValue() ]; 00997 } 00998 00999 #endif//TAPs_USE_EXTERNAL_ODE_SOLVER 01000 //----------------------------------------------------- 01001 // Physical Forces 01002 struct StructForce { 01003 Vector3<T> gravity; // gravity force 01004 //Vector3<T> antiBending; // anti-bending force 01005 }; 01006 StructForce * m_StructForce; 01007 //----------------------------------------------------- 01008 // Collision Detection 01009 BVHTree<T> * m_BVHTree; // use sphere node for BVHTree 01010 struct CollisionNodePairID { 01011 int id1; 01012 int id2; 01013 }; 01014 std::vector<CollisionNodePairID> m_svCollisionNodePairID; 01015 //--------------------------------------------------------------- 01016 //=============================================================== 01017 01018 //------------------------------------------- 01019 T m_tMoveStepDistAllowed; // how much each step the thread can move 01020 //---------------------------------------------------------------- 01021 // Temp Values 01022 Vector3<T> * m_prLinkDirection; // the link direction (from 0 to # of vertices-1) 01023 //---------------------------------------------------------------- 01024 // std::vector<int> m_vListOfFixedPoints; // list of fixed points 01025 //---------------------------------------------------------------- 01026 // Material Properties 01027 //--------------------- 01028 // Parameter Constants 01029 T m_tKRatioOfStretchingAllowed; // e.g. 0.10 of a link length 01030 T m_tKRatioOfCompressionAllowed; // e.g. 0.05 of a link length 01031 T m_tKStretching; // stretching and compression 01032 T m_tKBending; // bending 01033 T m_tKTwisting; // twisting 01034 T m_tKFriction; // friction 01035 T m_tGravity; // gravity / time (must not be set!) 01036 T m_tKGravity; // gravity constant 01037 T m_tKContact1; // contact1 (see SimByForce Fn on how this const is used) 01038 T m_tKContact2; // contact2 (see SimByForce Fn on how this const is used) 01039 // 01040 01041 #ifdef TAPs_STRAND_ENABLE_DAMPING_LIMIT 01042 unsigned int uiCounterDamping; // Counter for damping (for stopping vibration) 01043 unsigned int uiLimitCounterDamping; // stop advancing simulation when uiCounterDamping reaching this value 01044 #endif//TAPs_STRAND_ENABLE_DAMPING_LIMIT 01045 01046 //---------------------------------------------------------------- 01047 // Material Properties 01048 // T m_tKstretch; // stretch allowed 01049 // T m_tKstiff; // anti-bending 01050 // T m_tKfollow; // how much follower follows leader 01051 // 0 means follow 100% 01052 // 1 means rigid follower 01053 void InitCurrentShape (); 01054 //---------------------------------------------------------------- 01055 protected: 01056 //---------------------------------------------------------------- 01057 // Shape Memory 01058 public: 01059 void SetupShape ( Vector3<T> startPosition ); 01060 protected: 01061 Vector3<T> * m_prOrigVertex; // pointer to original (shape memory) vertices 01062 //---------------------------------------------------------------- 01063 01064 //============================================================================= 01065 #ifdef TAPs_STRAND_LOCK_SEGMENTS 01066 //----------------------------------------------------------------------------- 01067 public: 01077 int DivideAtPt ( unsigned int pt ); 01078 01080 void PrtSegments () 01081 { 01082 int i = 0; 01083 std::cout << "\nTotal Number of Segments: " << GetNumSegments() << "\n"; 01084 for ( std::vector<IC_Segment>::iterator it = m_Segments.begin(); it != m_Segments.end(); ++it, ++i ) { 01085 std::cout << " Segment: ID(" << i 01086 << ") start(" << GetStartPtOfSegment( i ) 01087 << ") end(" << GetEndPtOfSegment( i ) 01088 << ") isLocked(" << (*it).isLocked 01089 << ") isVisible(" << (*it).isVisible 01090 << ")\n"; 01091 } 01092 std::cout << "\n"; 01093 } 01094 01096 unsigned int GetNumSegments () { return static_cast<unsigned int>( m_Segments.size() ); } 01097 01099 int GetStartPtOfSegment ( unsigned int segment ); 01100 01102 int GetEndPtOfSegment ( unsigned int segment ); 01103 01105 bool GetSegmentLockStatus ( unsigned int segment ); 01106 01108 bool GetSegmentVisibleStatus ( unsigned int segment ); 01109 01111 void SetSegmentLockStatus ( unsigned int segment, bool status ); 01112 01114 void SetSegmentVisibleStatus ( unsigned int segment, bool status ); 01115 01116 protected: 01117 // Data Members --------------------------------------- 01118 class IC_Segment { 01119 // Data Members ------------------------- 01120 public: 01121 unsigned int start; 01122 unsigned int end; 01123 bool isLocked; 01124 bool isVisible; 01125 // Member Fns --------------------------- 01126 IC_Segment( unsigned int s, unsigned int e, bool l, bool v ) 01127 : start(s), end(e), isLocked(l), isVisible(v) 01128 {} 01129 }; 01134 std::vector<IC_Segment> m_Segments; 01135 private: 01140 bool * m_prIsLocked; 01141 01143 inline bool ValidateSegment ( unsigned int segment ) 01144 { return m_Segments.size() > segment; } 01145 01147 void ClearSegments () 01148 { 01149 m_Segments.clear(); 01150 m_Segments.push_back( IC_Segment( 0, m_iNoLinks, false, true ) ); 01151 for ( int i = 0; i <= m_iNoLinks; ++i ) { 01152 m_prIsLocked[i] = false; 01153 } 01154 } 01155 //----------------------------------------------------------------------------- 01156 #endif//TAPs_STRAND_LOCK_SEGMENTS 01157 //============================================================================= 01158 01159 //============================================================================= 01160 #ifdef TAPs_STRAND_KNOT_CONTROL 01161 //----------------------------------------------------------------------------- 01162 public: 01163 // Data Members ----------------------------------------------------------- 01164 // Member Fns ------------------------------------------------------------- 01165 void InitKnotControl ( unsigned char numKnotAllowed ); 01166 void ResetKnotControl (); 01167 std::string CheckSurgeonsKnot (); 01168 std::string GetStrNameForKnotCombination (); 01169 01170 #ifdef TAPs_COLLECT_DATA 01171 01172 std::string GetNameOfKnot ( unsigned int i, bool withPosOrNegPostfix = false ); 01173 01175 int GetIDOfKnot ( unsigned int i ); 01176 #endif//TAPs_COLLECT_DATA 01177 01178 protected: 01179 // Data Members ----------------------------------------------------------- 01180 // Member Fns ------------------------------------------------------------- 01181 public: 01182 unsigned int GetKnotCount () const { return m_ucKnotCount; } 01183 private: 01184 // Data Members ----------------------------------------------------------- 01185 unsigned char m_ucMaxNumKnotsAllowed; 01186 unsigned char m_ucKnotCount; 01187 int * m_piKnotID; 01188 // Member Fns ------------------------------------------------------------- 01189 void CreateKnotControl ( unsigned char numKnotAllowed = 8 ); 01190 void DeleteKnotControl (); 01191 01192 //========================================================================= 01193 #ifdef TAPs_STRAND_KNOT_CONTROL_USE_DOWKER_NOTATION_VERSION_01 01194 //------------------------------------------------------------------------- 01195 public: 01196 // Data Members ------------------------------------------------------- 01197 enum Threshold { 01198 THRESHOLD_FOR_FIXING_KNOT, 01199 THRESHOLD_WAITING_TIME, 01200 LENGTH_THRESHOLD_0, 01201 LENGTH_THRESHOLD_1, 01202 LENGTH_THRESHOLD_2, 01203 LENGTH_THRESHOLD_3, 01204 LENGTH_THRESHOLD_4, 01205 LENGTH_THRESHOLD_5, 01206 LENGTH_THRESHOLD_6, 01207 LENGTH_THRESHOLD_7, 01208 }; 01209 // Member Fns --------------------------------------------------------- 01211 bool SetKnotControlThreshold ( Threshold th, T val ); 01213 T GetKnotControlThreshold ( Threshold th ) const; 01215 int GetTrackingKnot () const { return m_ucTrackingKnot; } 01216 01217 protected: 01218 // Data Members ------------------------------------------------------- 01219 // Member Fns --------------------------------------------------------- 01220 private: 01221 // Data Members ------------------------------------------------------- 01224 unsigned int m_uiCounterThreshold; 01225 unsigned int m_uiCounterForFixingKnot; 01226 01233 // ??? 01235 // ??? 01236 //unsigned int m_uiCounterSpecialThreshold; 01237 double m_WaitingTime; 01238 double m_AccTime; 01239 time_t m_StartTime; 01240 inline void ResetStartTime () 01241 { 01242 time( &m_StartTime ); // reset time 01243 } 01244 inline void ResetElapsedTime () 01245 { 01246 time( &m_StartTime ); // reset time 01247 m_AccTime = 0.0; 01248 } 01249 inline double AddElapsedTime () 01250 { 01251 time_t prevTime = m_StartTime; 01252 time( &m_StartTime ); // new start time 01253 // difftime fn is from <ctime> 01254 m_AccTime += difftime( m_StartTime, prevTime ); 01255 01256 return m_AccTime; 01257 } 01258 inline bool IsTimeLimitReached () 01259 { 01260 return m_AccTime >= m_WaitingTime; 01261 } 01262 01265 unsigned int m_uiMinLengthThreshold; 01266 unsigned int m_uiLengthThreshold[8]; 01267 unsigned int m_uiLengthAccumulateTarget; 01268 01269 int m_ucTrackingKnot; 01270 // Member Fns --------------------------------------------------------- 01271 //------------------------------------------------------------------------- 01272 #endif//TAPs_STRAND_KNOT_CONTROL_USE_DOWKER_NOTATION_VERSION_01 01273 //========================================================================= 01274 //----------------------------------------------------------------------------- 01275 #endif//TAPs_STRAND_KNOT_CONTROL 01276 //============================================================================= 01277 01278 //---------------------------------------------------------------- 01283 private: 01284 bool * m_prIsFixed; 01285 protected: 01286 std::set<int> m_setOfFixedPts; 01287 01288 protected: 01289 //---------------------------------------------------------------- 01290 // For (Self) Intersection 01291 //char * m_prWasIntersect; // if previously intersect 01292 // manipulated by FTL and CheckSelfIntersections fns 01293 // 0 ==> no intersect 01294 // 1 ==> was intersect 01295 // 2 ==> is intersect 01296 //---------------------------------------------------------------- 01298 Vector3<T> * m_prDispVertex; 01299 //----------------------------------------------------------------------------- 01300 }; // CLASS END: ModelStrand ************************************************** 01301 //============================================================================= 01302 END_NAMESPACE_TAPs__OpenGL 01303 //----------------------------------------------------------------------------- 01304 // Include definition if TAPs_USE_EXPORT is not defined 01305 //#if !defined( TAPs_USE_EXPORT ) 01306 #include "TAPsModelStrand.cpp" 01307 //#endif 01308 //----------------------------------------------------------------------------- 01309 #endif 01310 //345678901234567890123456789012345678901234567890123456789012345678901234567890 01311 //--+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8