NCBI C++ ToolKit
phylo_tree_ps.cpp
Go to the documentation of this file.
00001 /*  $Id: phylo_tree_ps.cpp 25383 2012-03-06 19:23:25Z ucko $
00002  * ===========================================================================
00003  *
00004  *                            PUBLIC DOMAIN NOTICE
00005  *               National Center for Biotechnology Information
00006  *
00007  *  This software/database is a "United States Government Work" under the
00008  *  terms of the United States Copyright Act.  It was written as part of
00009  *  the author's official duties as a United States Government employee and
00010  *  thus cannot be copyrighted.  This software/database is freely available
00011  *  to the public for use. The National Library of Medicine and the U.S.
00012  *  Government have not placed any restriction on its use or reproduction.
00013  *
00014  *  Although all reasonable efforts have been taken to ensure the accuracy
00015  *  and reliability of the software and data, the NLM and the U.S.
00016  *  Government do not and cannot warrant the performance or results that
00017  *  may be obtained by using this software or data. The NLM and the U.S.
00018  *  Government disclaim all warranties, express or implied, including
00019  *  warranties of performance, merchantability or fitness for any particular
00020  *  purpose.
00021  *
00022  *  Please cite the author in any work or product based on this material.
00023  *
00024  * ===========================================================================
00025  *
00026  * Authors:  Bob Falk
00027  *
00028  * File Description:
00029  *      Force tree layout
00030  */
00031 
00032 #include <ncbi_pch.hpp>
00033 
00034 #include <corelib/ncbitime.hpp>
00035 
00036 #include <gui/widgets/phylo_tree/phylo_tree_ps.hpp>
00037 #include <gui/widgets/phylo_tree/phylo_tree_ds.hpp>
00038 #include <gui/widgets/phylo_tree/phylo_tree_node.hpp>
00039 
00040 #include <gui/widgets/gl/attrib_menu.hpp>
00041 
00042 #include <corelib/ncbitime.hpp>
00043 #include <corelib/ncbistl.hpp>
00044 
00045 #include <cmath>
00046 
00047 BEGIN_NCBI_SCOPE
00048 
00049 //#define VALIDATE_NODE_NODE_FORCES 1
00050 
00051 CPhyloTreePS::PhysicsParms::PhysicsParms()
00052 : m_ElectricalRepulsion(100.0f)
00053 , m_Step(0.02f)
00054 , m_Damping(0.88f)
00055 , m_EdgeK(300.0f)
00056 , m_RepulsionDist(350.0f)
00057 , m_VelocityThresholdK(0.0008f)
00058 {
00059 }
00060 
00061 CPhyloTreePS::CPhyloTreePS(CPhyloTreeDataSource& ds)
00062 : m_AdaptiveStep(1.0f)
00063 , m_MaxVelocity(1.0f)
00064 , m_PrevMaxVelocity(1.0)
00065 , m_IsDone(false)
00066 {  
00067     // Set up interactive menus for debugging.  
00068 #ifdef ATTRIB_MENU_SUPPORT
00069     CAttribMenu& m = CAttribMenuInstance::GetInstance();
00070 
00071     CAttribMenu* sub_menu = m.AddSubMenuUnique("PhyloTreePS", this);
00072    
00073     sub_menu->AddFloat("Step Size", 
00074         &m_PhysicsParmsVolatile.m_Step, 0.02f, 0.000001f, 1.0f, 0.01f);
00075     sub_menu->AddFloat("Damping", 
00076         &m_PhysicsParmsVolatile.m_Damping, 0.88f, 0.0f, 1.0f, 0.01f);
00077     sub_menu->AddFloat("Edge K", 
00078         &m_PhysicsParmsVolatile.m_EdgeK, 300.0f, 0.0f, 1000.0f, 10.0f);
00079     sub_menu->AddFloat("Repulsion", 
00080         &m_PhysicsParmsVolatile.m_ElectricalRepulsion, 100.0f, 0.0f, 500.0f, 5.0f);
00081     sub_menu->AddFloat("Rep Dist", 
00082         &m_PhysicsParmsVolatile.m_RepulsionDist, 300.0f, 0.0f, 10000.0f, 20.0f);
00083     sub_menu->AddFloat("Vel Threshold K", 
00084         &m_PhysicsParmsVolatile.m_VelocityThresholdK, 0.003f, 0.0f, 1.0f, 0.001f);  
00085 
00086     sub_menu->AddFloatReadOnly("Time Edge F", &m_edge_forces_safe_t);
00087     sub_menu->AddFloatReadOnly("Time Node F", &m_node_forces_safe_t);
00088     sub_menu->AddFloatReadOnly("Time Int", &m_integrate_safe_t);
00089     sub_menu->AddFloatReadOnly("Time Vox Update", &m_bound_update_safe_t);
00090     sub_menu->AddIntReadOnly("Node-Node Int", &m_node_node_interactions_safe_t);
00091     sub_menu->AddFloatReadOnly("Maximum Velocity", &m_MaxVelocity);
00092     sub_menu->AddFloatReadOnly("Adaptive Step", &m_AdaptiveStep);
00093 #endif   
00094 
00095     Init(ds);
00096 }
00097 
00098 
00099 CPhyloTreePS::~CPhyloTreePS()
00100 {
00101 #ifdef ATTRIB_MENU_SUPPORT
00102     CAttribMenu& m = CAttribMenuInstance::GetInstance();
00103     m.RemoveMenuR("PhyloTreePS", this);
00104 #endif
00105 
00106     Clear();
00107 }
00108 
00109 void CPhyloTreePS::Clear()
00110 {
00111     m_NodeToIdx.clear();
00112     m_Nodes.clear();
00113     m_Edges.clear();
00114     m_MaxVelocity = 1.0f;
00115     m_PrevMaxVelocity = 1.0f;
00116     m_AdaptiveStep = 1.0f;
00117     m_IsDone = false;
00118 
00119     // This is taken care of in Init()
00120     //m_NodeGrid.Clear();
00121 
00122 #ifdef VALIDATE_NODE_NODE_FORCES
00123     m_ValidateGrid.clear();
00124     m_ValidateNsq.clear();
00125 #endif
00126 }
00127 
00128 void CPhyloTreePS::Init(CPhyloTreeDataSource& ds)
00129 {
00130     Clear();
00131 
00132     m_pRoot = ds.GetTree();
00133 
00134     m_DefaultEdgeLen = 0.0f;
00135 
00136     m_MinPos.X() = std::numeric_limits<float>::max();
00137     m_MinPos.Y() = std::numeric_limits<float>::max();
00138     m_MaxPos.X() = std::numeric_limits<float>::min();
00139     m_MaxPos.Y() = std::numeric_limits<float>::min();
00140 
00141     x_Init(ds.GetTree(), -1);
00142 
00143     x_UpdateVoxels();
00144 
00145     m_DefaultEdgeLen /= (float)m_Edges.size();
00146 
00147     // Compute edge forces between nodes
00148     std::vector<Edge>::iterator eiter;
00149     
00150     for (eiter=m_Edges.begin(); eiter!=m_Edges.end(); ++eiter) {
00151         (*eiter).rest_len_inv = 1.0f/m_DefaultEdgeLen;
00152     }
00153 }
00154 
00155 void CPhyloTreePS::x_ApplyNeighborCellForces(std::vector<int>& cell_nodes, 
00156                                              const CVect2<int>& adjacent_idx)
00157 {
00158     std::vector<int>& neighbor_nodes = m_NodeGrid.Get(adjacent_idx);
00159 
00160     // For all nodes in a pair of cells, compute the forces between them
00161     for (size_t i=0; i<cell_nodes.size(); ++i) {
00162         for (size_t j=0; j<neighbor_nodes.size(); ++j) {
00163             int idx1 = cell_nodes[i];
00164             int idx2 = neighbor_nodes[j];
00165 
00166             TVec offset(m_Nodes[idx1].pos - m_Nodes[idx2].pos);
00167 
00168             float dist2 = offset.Length2();
00169 
00170             if (dist2 < m_RepulsionDist2 && dist2 > FLT_EPSILON) {       
00171                 float dist = sqrtf(dist2);
00172 
00173                 offset *= (m_PhysicsParmsSafe.m_ElectricalRepulsion-
00174                            m_RepulsionInv_x_ElectricalRepulsion*dist)/dist2;
00175                 m_Nodes[idx1].accel += offset;
00176                 m_Nodes[idx2].accel -= offset;
00177 
00178                 ++m_node_node_interactions_t;
00179 
00180 #ifdef VALIDATE_NODE_NODE_FORCES
00181                 m_ValidateGrid.push_back( CVect2<int>(std::min(idx1, idx2), std::max(idx1, idx2) );
00182 #endif
00183 
00184                 // for debugging
00185                 //m_Nodes[idx1].force_nodes.push_back(idx2); 
00186                 //m_Nodes[idx2].force_nodes.push_back(idx1);
00187             }
00188         }
00189     }
00190 }
00191 
00192  void CPhyloTreePS::x_ApplyRepulsiveForcesHashed()
00193  {
00194     CVect2<int> min_pos = 0; //m_NodeGrid.GetMin();
00195     CVect2<int> max_pos = m_NodeGrid.GetMax() - m_NodeGrid.GetMin();
00196     
00197     // Iterate over the whole grid which subdivides the space occupied
00198     // by the tree into individual cells. For each cell, compute the 
00199     // forces between all the nodes in that cell, and then compute
00200     // the forces between nodes in that cell and nodes in adjacent
00201     // cells.  Node forces will not travel more than one cell since
00202     // we base cell size on the maximum distance for the the repulsion
00203     // force between cells.
00204     for (int x = min_pos.X(); x <= max_pos.X(); ++x) {
00205         for (int y = min_pos.Y(); y <= max_pos.Y(); ++y) {
00206             CVect2<int> idx(x,y);
00207             std::vector<int>& cell_nodes = m_NodeGrid.Get(idx);
00208             if (cell_nodes.size() > 0) {
00209                 // Find collisions between nodes hashed in this entry
00210                 for (size_t i=0; i<cell_nodes.size(); ++i) {
00211                     for (size_t j=i+1; j<cell_nodes.size(); ++j) {
00212                         
00213                         int idx1 = cell_nodes[i];
00214                         int idx2 = cell_nodes[j];
00215 
00216                         TVec offset(m_Nodes[idx1].pos - m_Nodes[idx2].pos);
00217         
00218                         float dist2 = offset.Length2();
00219 
00220                         // Compute forces between one pair of nodes
00221                         if (dist2 < m_RepulsionDist2 && dist2 > FLT_EPSILON) {
00222                             float dist = sqrtf(dist2);
00223 
00224                             offset *= (m_PhysicsParmsSafe.m_ElectricalRepulsion-
00225                                        m_RepulsionInv_x_ElectricalRepulsion*dist)/dist2;
00226                             m_Nodes[idx1].accel += offset;
00227                             m_Nodes[idx2].accel -= offset;
00228 
00229                             ++m_node_node_interactions_t;
00230 
00231 #ifdef VALIDATE_NODE_NODE_FORCES
00232                               m_ValidateGrid.push_back( CVect2<int>(std::min(idx1, idx2), std::max(idx1, idx2) );
00233 #endif
00234 
00235                             //m_Nodes[idx1].force_nodes.push_back(idx2);  // for debugging
00236                             //m_Nodes[idx2].force_nodes.push_back(idx1);
00237                         }                    
00238                     }
00239                 }
00240 
00241 
00242                 // Find all collisions between nodes in this entry and nodes
00243                 // in the adjacent cells idx(x+1,y), idx(x+1,y+1), idx(x,y+1), 
00244                 // idx(x-1,y+1). Only look at nodes in positive direction so that
00245                 // you don't compute forces between adjacent cells twice (once 
00246                 // when you visit each cell)
00247                 if (x+1 < m_NodeGrid.GetWidth()) {
00248                     x_ApplyNeighborCellForces(cell_nodes, CVect2<int>(x+1,y));
00249 
00250                     if (y+1 < m_NodeGrid.GetHeight())
00251                         x_ApplyNeighborCellForces(cell_nodes, CVect2<int>(x+1,y+1));
00252                 }
00253 
00254                 if (y+1 < m_NodeGrid.GetHeight()) {
00255                     x_ApplyNeighborCellForces(cell_nodes, CVect2<int>(x,y+1));
00256 
00257                     if (x > 0)
00258                         x_ApplyNeighborCellForces(cell_nodes, CVect2<int>(x-1,y+1));
00259                 }
00260 
00261             }
00262         }
00263     }
00264  }
00265 
00266 // Simple global form of repulsive forces.  Has better visual result still,
00267 // but is quite a bit slower.
00268 void CPhyloTreePS::x_ApplyRepulsiveForces()
00269 {
00270     // Iterate over all nodes and compute forces between them
00271     for (size_t i=0; i<m_Nodes.size(); ++i) {             
00272         for (size_t j=i+1; j<m_Nodes.size(); ++j) {                        
00273             TVec offset(m_Nodes[i].pos - m_Nodes[j].pos);
00274 
00275             float dist2 = offset.Length2();
00276             if (dist2 > FLT_EPSILON) {              
00277                 //offset *= (m_ElectricalRepulsion-m_RepulsionInv_x_ElectricalRepulsion*dist)/(dist2+ + FLT_EPSILON);
00278                 offset *=  m_PhysicsParmsSafe.m_ElectricalRepulsion/dist2;
00279                 m_Nodes[i].accel += offset;
00280                 m_Nodes[j].accel -= offset;
00281 
00282                 ++m_node_node_interactions_t;
00283 
00284 #ifdef VALIDATE_NODE_NODE_FORCES
00285                 m_ValidateGrid.push_back( CVect2<int>(std::min(idx1, idx2), std::max(idx1, idx2) );
00286 #endif
00287             }
00288         }
00289      }
00290 }
00291 
00292 
00293 void CPhyloTreePS::CalcForces()
00294 {
00295 #ifdef VALIDATE_NODE_NODE_FORCES
00296     m_ValidateGrid.clear();
00297     m_ValidateNsq.clear();
00298 #endif
00299 
00300 
00301     m_RepulsionDist2 = m_PhysicsParmsSafe.m_RepulsionDist * 
00302                        m_PhysicsParmsSafe.m_RepulsionDist;
00303     m_RepulsionInv_x_ElectricalRepulsion = (1.0f/m_PhysicsParmsSafe.m_RepulsionDist) *
00304                                            m_PhysicsParmsSafe.m_ElectricalRepulsion;
00305 
00306     // Compute edge forces between nodes
00307     std::vector<Edge>::iterator eiter;
00308 
00309     m_LogDistMax = -500.0f;
00310     m_LogDistMin = 500.0f;
00311 
00312     CStopWatch sw;
00313     m_node_node_interactions_t = 0;
00314 
00315     sw.Start();
00316     
00317     // Compute forces from all edges
00318     for (eiter=m_Edges.begin(); eiter!=m_Edges.end(); ++eiter) {
00319         Node& n1 = m_Nodes[(*eiter).from_idx];
00320         Node& n2 = m_Nodes[(*eiter).to_idx];
00321 
00322         TVec offset(n1.pos - n2.pos);
00323         float dist = offset.Length();
00324         (*eiter).len = dist;
00325 
00326         float ldist = logf(dist*(*eiter).rest_len_inv);
00327         //m_LogDistMax = std::max(ldist, m_LogDistMax);
00328         //m_LogDistMin = std::min(ldist, m_LogDistMin);
00329         offset *= (1.0f/dist)*ldist*m_PhysicsParmsSafe.m_EdgeK;
00330 
00331         n1.accel -= offset;
00332         n2.accel += offset;
00333     }
00334 
00335     sw.Stop();
00336     m_edge_forces_t = sw.Elapsed()*1000.0f;
00337     
00338 
00339     // Compute repulsion forces between all nodes  (n^2 version)
00340 #ifdef VALIDATE_NODE_NODE_FORCES                             
00341     std::vector<Node>::iterator niter1, niter2;
00342     for (niter1=m_Nodes.begin(); niter1!=m_Nodes.end(); ++niter1) {
00343         TVec p1 = (*niter1).pos;
00344 
00345         for (niter2=niter1+1; niter2!=m_Nodes.end(); ++niter2) {
00346             TVec p2 = (*niter2).pos;
00347             TVec offset(p1-p2);
00348 
00349             //float dist = offset.Length() + 0.00001f;
00350 
00351             float dist2 = offset.Length2();
00352             if (dist2 < m_RepulsionDist2) {      
00353                 int idx1 = niter1-m_Nodes.begin();
00354                 int idx2 = niter2-m_Nodes.begin();
00355                 m_ValidateNsq.push_back( CVect2<int>(std::min(idx1, idx2), std::max(idx1, idx2) );
00356                 /*
00357                 float dist = sqrtf(dist2);
00358                 float mult_factor = (1.0f/dist)* (m_ElectricalRepulsion/dist);
00359 
00360                 offset *= mult_factor;
00361 
00362                 (*niter1).accel += offset;
00363                 (*niter2).accel -= offset;
00364             */
00365             }
00366         }
00367     }    
00368 #endif
00369 
00370    
00371     sw.Restart();
00372 
00373     // Compute repulsive forces between nodes
00374     //x_ApplyRepulsiveForces();
00375     x_ApplyRepulsiveForcesHashed();
00376 
00377     m_node_forces_t = sw.Elapsed()*1000.0f;
00378 }
00379 
00380 
00381 void CPhyloTreePS::Update()
00382 {
00383     {
00384         // Throttle step size if velocity is too high.
00385         // Not really proper adaptive time stepping, but it should
00386         // keep things from exploding        
00387         if (m_MaxVelocity > 20.0f &&
00388             m_MaxVelocity > m_PrevMaxVelocity && 
00389             m_AdaptiveStep > 0.01f) {
00390             m_AdaptiveStep = m_AdaptiveStep*0.95f;
00391         }
00392         else if (m_AdaptiveStep < 1.0f &&
00393                  m_MaxVelocity < 20.0f &&
00394                  m_MaxVelocity < m_PrevMaxVelocity) {
00395             m_AdaptiveStep += (1.0f - m_AdaptiveStep)*0.01f;
00396         }        
00397     }
00398 
00399     // Compute all forces
00400     CalcForces(); 
00401 
00402     // Reset tree extent, so that we can recompute it as
00403     // we update the system.  Extent is neede for our spatial
00404     // collision grid each update.
00405     m_MinPos.X() = std::numeric_limits<float>::max();
00406     m_MinPos.Y() = std::numeric_limits<float>::max();
00407     m_MaxPos.X() = std::numeric_limits<float>::min();
00408     m_MaxPos.Y() = std::numeric_limits<float>::min();
00409 
00410     CStopWatch sw;
00411     sw.Start();
00412 
00413     // This will reduce step size if we seem unstable.
00414     float step = m_PhysicsParmsSafe.m_Step*m_AdaptiveStep;
00415     
00416     // Integrate forces into position updates
00417     std::vector<Node>::iterator niter;
00418     for (niter=m_Nodes.begin(); niter!=m_Nodes.end(); ++niter) {
00419         // pos = pos + (pos-prev_pos)*damping + accel*dt;
00420         TVec prev_offset((*niter).pos - (*niter).prev_pos);
00421         (*niter).prev_pos = (*niter).pos;
00422     
00423         (*niter).pos.X() += (prev_offset.X()*m_PhysicsParmsSafe.m_Damping + 
00424             (*niter).accel.X()*step)*(*niter).constrained;
00425         (*niter).pos.Y() += (prev_offset.Y()*m_PhysicsParmsSafe.m_Damping + 
00426             (*niter).accel.Y()*step)*(*niter).constrained;
00427 
00428         m_MinPos.X() = std::min(m_MinPos.X(), (*niter).pos.X());
00429         m_MinPos.Y() = std::min(m_MinPos.Y(), (*niter).pos.Y());
00430         m_MaxPos.X() = std::max(m_MaxPos.X(), (*niter).pos.X());
00431         m_MaxPos.Y() = std::max(m_MaxPos.Y(), (*niter).pos.Y());        
00432 
00433         (*niter).accel = TVec( TVec::TVecType(0) );       
00434         
00435         //(*niter).prev_force_nodes = (*niter).force_nodes;
00436         //(*niter).force_nodes.clear();     
00437     };
00438 
00439     sw.Stop();
00440     m_integrate_t = sw.Elapsed()*1000.0f;
00441 
00442     sw.Restart();
00443     // Update spatial data structure
00444     x_UpdateVoxels();
00445     m_bound_update_t  = sw.Elapsed()*1000.0f;
00446 }
00447 
00448 // Do the same thing as update, but also update the underlying
00449 // data structure.
00450 void CPhyloTreePS::UpdateAndSynch()
00451 {   
00452     // This function is thread-safe, so update parms here:
00453     m_PhysicsParmsSafe = m_PhysicsParmsVolatile;
00454 
00455     CalcForces();    
00456 
00457     float max_velocity_squared = 0.0f;
00458 
00459     m_MinPos.X() = std::numeric_limits<float>::max();
00460     m_MinPos.Y() = std::numeric_limits<float>::max();
00461     m_MaxPos.X() = std::numeric_limits<float>::min();
00462     m_MaxPos.Y() = std::numeric_limits<float>::min();
00463 
00464     float step = m_PhysicsParmsSafe.m_Step*m_AdaptiveStep;
00465 
00466     // Integrate and reset 
00467     std::vector<Node>::iterator niter;
00468     for (niter=m_Nodes.begin(); niter!=m_Nodes.end(); ++niter) {
00469         // pos = pos + (pos-prev_pos)*damping + accel*dt; 
00470         TVec prev_offset((*niter).pos - (*niter).prev_pos);
00471         (*niter).prev_pos = (*niter).pos;       
00472             
00473         float xoff = (prev_offset.X()*m_PhysicsParmsSafe.m_Damping + 
00474             (*niter).accel.X()*step)*(*niter).constrained;
00475         float yoff = (prev_offset.Y()*m_PhysicsParmsSafe.m_Damping + 
00476             (*niter).accel.Y()*step)*(*niter).constrained;
00477 
00478         max_velocity_squared = std::max(max_velocity_squared, xoff*xoff + yoff*yoff);
00479 
00480         (*niter).pos.X() += xoff;
00481         (*niter).pos.Y() += yoff;
00482 
00483         m_MinPos.X() = std::min(m_MinPos.X(), (*niter).pos.X());
00484         m_MinPos.Y() = std::min(m_MinPos.Y(), (*niter).pos.Y());
00485         m_MaxPos.X() = std::max(m_MaxPos.X(), (*niter).pos.X());
00486         m_MaxPos.Y() = std::max(m_MaxPos.Y(), (*niter).pos.Y());
00487 
00488         // update node....
00489         (*niter).tree_node->GetValue().X() = (*niter).pos.X();
00490         (*niter).tree_node->GetValue().Y() = (*niter).pos.Y();
00491         
00492         (*niter).accel = TVec( TVec::TVecType(0) );
00493     };
00494 
00495     m_PrevMaxVelocity = m_MaxVelocity;
00496     m_MaxVelocity = sqrtf(max_velocity_squared)/m_PhysicsParmsSafe.m_Step;
00497 
00498     /// It would be better to filter this result (probably filter x frames of
00499     /// velocity to search for outliers and make sure average is good)
00500     if (!m_IsDone) {
00501         float node_count = (float)m_Nodes.size();
00502         float threshold = m_PhysicsParmsSafe.m_VelocityThresholdK*((node_count+5.0f)/5.0f);     
00503         threshold = std::min(10.0f, threshold);
00504         if (m_AdaptiveStep > 0.9f &&
00505             m_MaxVelocity < threshold) {
00506             m_IsDone = true;
00507         }
00508     }
00509 
00510     m_edge_forces_safe_t = m_edge_forces_t;
00511     m_node_forces_safe_t = m_node_forces_t;
00512     m_integrate_safe_t = m_integrate_t;
00513     m_bound_update_safe_t = m_bound_update_t;
00514     m_node_node_interactions_safe_t = m_node_node_interactions_t;
00515 
00516     x_UpdateVoxels();
00517 }
00518 
00519 void CPhyloTreePS::Draw()
00520 {
00521     std::vector<Edge>::iterator eiter;
00522 
00523     
00524     glLineWidth(2.0f);
00525     glBegin(GL_LINES);
00526 
00527     for (eiter=m_Edges.begin(); eiter!=m_Edges.end(); ++eiter) {
00528         Node& n1 = m_Nodes[(*eiter).from_idx];
00529         Node& n2 = m_Nodes[(*eiter).to_idx];
00530 
00531         TVec offset(n1.pos - n2.pos);
00532         float dist = offset.Length();      
00533         float ldist = logf(dist*(*eiter).rest_len_inv);       
00534         
00535         if (ldist >= 0.0f)
00536             glColor3f(std::max(0.0f, ldist/m_LogDistMax), 0.0f, 0.0f);
00537         else
00538             glColor3f(0.0f, 0.0f, std::max(0.0f, std::abs(ldist/m_LogDistMin)));
00539 
00540         glVertex2fv(n1.pos.GetData());
00541         glVertex2fv(n2.pos.GetData());
00542     }
00543     
00544     glEnd();
00545     
00546    
00547     glPointSize(5.0f);
00548     glColor3f(1.0f, 1.0f, 0.0f);
00549     glBegin(GL_POINTS);
00550     std::vector<Node>::iterator niter;
00551     for (niter=m_Nodes.begin(); niter!=m_Nodes.end(); ++niter) {
00552         /*
00553         if ( (*(*niter).tree_node)->GetSelectedState() == IPhyGraphicsNode::eSelected) {                     
00554             glBegin(GL_LINES);
00555             for (size_t j=0; j<(*niter).prev_force_nodes.size(); ++j) {
00556                 int idx = (*niter).prev_force_nodes[j];
00557                 TVec p1 = (*niter).pos;
00558                 TVec p2 = m_Nodes[idx].pos;
00559                 glVertex2fv(p1.GetData());
00560                 glVertex2fv(p2.GetData());
00561             }
00562             glEnd();            
00563 
00564             glLineWidth(1.0f);
00565         }
00566         */
00567         if ( !(*niter).constrained ) {
00568             glVertex2fv((*niter).pos.GetData());
00569         }
00570     }    
00571     glEnd();
00572 
00573 #ifdef VALIDATE_NODE_NODE_FORCES
00574     //m_ValidateGrid.clear();
00575     //m_ValidateNsq.clear();
00576 #endif
00577 }
00578 
00579 
00580 void CPhyloTreePS::x_UpdateVoxels()
00581 {      
00582     // Reset size of collision grid based on current  node extent
00583     CVect2<int> min_idx(int(m_MinPos[0]/m_PhysicsParmsSafe.m_RepulsionDist), 
00584                         int(m_MinPos[1]/m_PhysicsParmsSafe.m_RepulsionDist));
00585     CVect2<int> max_idx(int(m_MaxPos[0]/m_PhysicsParmsSafe.m_RepulsionDist), 
00586                         int(m_MaxPos[1]/m_PhysicsParmsSafe.m_RepulsionDist));
00587 
00588     m_NodeGrid.SetMax(max_idx);
00589     m_NodeGrid.SetMin(min_idx);
00590 
00591     // Resize and clear spatial grid
00592     m_NodeGrid.ResizeFast();
00593     m_NodeGrid.Clear();
00594 
00595     // Put all nodes into the correct places in the grid
00596     for (size_t j=0; j<m_Nodes.size(); ++j) {
00597         TVec pos = m_Nodes[j].pos;
00598         CVect2<int> posi(int(pos[0]/m_PhysicsParmsSafe.m_RepulsionDist) - min_idx.X(), 
00599                          int(pos[1]/m_PhysicsParmsSafe.m_RepulsionDist) - min_idx.Y());
00600 
00601         m_NodeGrid.Get(posi).push_back(j);
00602     }
00603 }
00604 
00605 int CPhyloTreePS::x_Init(CPhyloTreeNode * tnode, int parent_idx)
00606 {    
00607     int node_idx = m_Nodes.size();
00608     m_NodeToIdx[tnode] = node_idx;
00609 
00610     CVect2<float> pos(tnode->GetValue().X(), 
00611                       tnode->GetValue().Y());
00612 
00613     Node n;
00614     n.pos = pos;
00615     n.prev_pos = pos;    
00616     n.accel = 0.0f;
00617     //n.constrained = 0.0f;
00618     n.constrained = 1.0f;
00619     n.tree_node = tnode;
00620     n.is_leaf = tnode->IsLeaf();
00621    
00622     m_MinPos.X() = std::min(m_MinPos.X(), pos.X());
00623     m_MinPos.Y() = std::min(m_MinPos.Y(), pos.Y());
00624     m_MaxPos.X() = std::max(m_MaxPos.X(), pos.X());
00625     m_MaxPos.Y() = std::max(m_MaxPos.Y(), pos.Y());
00626 
00627     /// Add the edge from the current node to its parent
00628     if (parent_idx != -1) {
00629         n.constrained = 1.0f;
00630         CVect2<float> ppos(tnode->GetParent()->GetValue().X(),
00631                            tnode->GetParent()->GetValue().Y());
00632 
00633         float len = (pos-ppos).Length();
00634         m_DefaultEdgeLen += len;
00635 
00636         _ASSERT(&(*(tnode->GetParent())) == m_Nodes[parent_idx].tree_node);
00637 
00638         Edge e(parent_idx, node_idx);
00639         e.len = len;
00640         e.rest_len_inv = 1.0f/100.0f;
00641         m_Edges.push_back(e);
00642 
00643         
00644         /*
00645         CPhyloTreeNode* grandparent = static_cast<CPhyloTreeNode*>(tnode->GetParent()->GetParent());
00646         int parent_offspring = static_cast<CPhyloTreeNode*>(tnode->GetParent())->NumChildren();
00647         if (grandparent != NULL && parent_offspring == 1) {
00648             int grandparent_idx = m_NodeToIdx[grandparent];
00649         
00650             CVect2<float> ppos(grandparent->GetValue().X(),
00651                                grandparent->GetValue().Y());
00652 
00653             float len = (pos-ppos).Length();
00654             m_DefaultEdgeLen += len;
00655 
00656             //_ASSERT(&(*(tnode->GetParent())) == m_Nodes[parent_idx].tree_node);
00657 
00658             Edge e(grandparent_idx, node_idx);
00659             e.len = len;
00660             e.rest_len_inv = 1.0f/200.0f;
00661             m_Edges.push_back(e);
00662         }
00663         */
00664 
00665         
00666         //m_Nodes[parent_idx].edges.push_back(m_Edges.size()-1);    
00667         //m_Nodes[node_idx].m_ParentEdge = m_Edges.size() - 1;
00668 
00669     }
00670 
00671     //else {
00672     //    n.constrained = 0.0f;
00673     //}
00674 
00675     m_Nodes.push_back(n);
00676 
00677     for(CPhyloTreeNode::TNodeList_I  it = tnode->SubNodeBeginEx();
00678         it != tnode->SubNodeEndEx(); it++ ){     
00679         x_Init(static_cast<CPhyloTreeNode*>(*it), node_idx);
00680     }
00681 
00682     //if (tnode->IsLeafEx())
00683     //    m_LeafNodes.push_back(node_idx);
00684 
00685     return parent_idx;
00686 }
00687 
00688 END_NCBI_SCOPE
Modified on Wed May 23 13:36:25 2012 by modify_doxy.py rev. 337098