|
NCBI C++ ToolKit
|
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
1.7.5.1
Modified on Wed May 23 13:36:25 2012 by modify_doxy.py rev. 337098