NCBI C++ ToolKit
tree_collision_model2d.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: tree_collision_model2d.cpp 47479 2023-05-02 13:24:02Z ucko $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Authors: Bob Falk
27  *
28  * File Description:
29  *
30  */
31 
32 #include <ncbi_pch.hpp>
33 #include <corelib/ncbistl.hpp>
34 
40 
42 #include <corelib/ncbitime.hpp>
43 
44 
46 
48 : m_Model(NULL)
49 {
50 #ifdef ATTRIB_MENU_SUPPORT
51  m_VisUpdateTime = 0.0f;
52  m_ScaleUpdateTime = 0.0f;
53 
55 
56  CAttribMenu* sub_menu = m.AddSubMenuUnique("Collision", this);
57 
58  sub_menu->AddIntReadOnly("CD Width", &m_Width);
59  sub_menu->AddIntReadOnly("CD Height", &m_Height);
60 
61  sub_menu->AddFloatReadOnly("UpdateVis T", &m_VisUpdateTime);
62  sub_menu->AddFloatReadOnly("UpdateScale T", &m_ScaleUpdateTime);
63 
64  sub_menu->AddFloat("Resolution Scaler", &m_ResolutionScaler, 1.0f, 0.1f, 10.0f, 0.05f);
65 #endif
66 }
67 
69 {
70 #ifdef ATTRIB_MENU_SUPPORT
71  CAttribMenuInstance::GetInstance().RemoveMenuR("Collision", this);
72 #endif
73 }
74 
75 void CTreeCollisionModel2D::Update(const CGlPane& pane, const CVect2<float>& scale)
76 {
77  Clear();
78 
79  m_Scale = scale;
80 
81  UpdateScaled(pane, m_Scale);
82 }
83 
84 
86 {
87  if (m_Model == NULL)
88  return;
89 
90  CStopWatch t;
91  t.Start();
92 
93  Clear();
94 
95  m_Scale = scale;
96 
97 
98  vector<size_t>& node_indices = m_Model->GetNodeIndices();
100 
101  vector<size_t>::const_iterator iter;
102  for (iter=node_indices.begin(); iter!=node_indices.end(); ++iter) {
103  CVect2<float> ll, ur;
104  size_t idx = *iter;
105 
106  CPhyloTreeNode& n = (*tree)[idx];
107 
108  if (m_Model->GetRotateLabels()) {
109  bool visible;
110  float default_angle = n->GetAngle();
111  float scaled_angle = m_Model->GetCurrentRotationAngle(pane, n, visible);
112 
113  n->SetAngle(scaled_angle);
114  (*tree)[idx]->GetBoundingRect(m_Scale, ll, ur, m_Model->GetRotateLabels());
115  n->SetAngle(default_angle);
116  }
117  else {
118  (*tree)[idx]->GetBoundingRect(m_Scale, ll, ur, m_Model->GetRotateLabels());
119  }
120 
121  CVect2<int> posi_ll(int(floorf(ll[0] / m_ResolutionX)),
122  int(floorf(ll[1] / m_ResolutionY)));
123  CVect2<int> posi_ur(int(floorf(ur[0] / m_ResolutionX)),
124  int(floorf(ur[1] / m_ResolutionY)));
125 
126 
127  // Make sure we only look at sections inside our spatial subdivision (which
128  // may not include regions when geometry is larger than the un-zoomed viewing
129  // area)
130  posi_ll.X() = std::max(posi_ll.X(), m_MinIdx.X());
131  posi_ll.Y() = std::max(posi_ll.Y(), m_MinIdx.Y());
132  posi_ur.X() = std::min(posi_ur.X(), m_MaxIdx.X());
133  posi_ur.Y() = std::min(posi_ur.Y(), m_MaxIdx.Y());
134 
135  posi_ll -= m_MinIdx;
136  posi_ur -= m_MinIdx;
137 
138  // Guarantee no out-of-bounds errors:
139  posi_ll.X() = std::min(posi_ll.X(), m_Width - 1);
140  posi_ll.Y() = std::min(posi_ll.Y(), m_Height - 1);
141  posi_ur.X() = std::min(posi_ur.X(), m_Width - 1);
142  posi_ur.Y() = std::min(posi_ur.Y(), m_Height - 1);
143 
145  for (grid_pos.Y() = posi_ll.Y(); grid_pos.Y()<=posi_ur.Y(); ++grid_pos.Y()) {
146  for (grid_pos.X() = posi_ll.X(); grid_pos.X()<=posi_ur.X(); ++grid_pos.X()) {
147  Get(grid_pos).m_Labels.push_back(idx);
148  }
149  }
150  }
151 
152  m_ScaleUpdateTime = (float)t.Elapsed();
153 }
154 
155 CPhyloTree::TTreeIdx CTreeCollisionModel2D::TestForNode(float x, float y, bool labels_visible, bool rotated_labels)
156 {
158  if (m_Model == NULL)
159  return tree_idx;
160 
161  /// Get index for cell that holds (x,y)
162  TVeci idx(int(floorf(x/m_ResolutionX)),
163  int(floorf(y/m_ResolutionY)));
164 
165  idx -= m_MinIdx;
166 
167  /// Get the set of nodes (indices) in the cell that (x,y) falls into
168  std::vector<size_t> cell_nodes = GetSafe(idx).m_Labels;
169 
170  long best_vis_idx = -1;
171  float best_vis_label_dist = FLT_MAX;
172 
173  long best_hidden_idx = -1;
174  float best_hidden_label_dist = FLT_MAX;
175 
176  // iterate over all the nodes in the cell for (x,y) and check
177  // to see if one is close enough to (x,y) to select it
179 
180  for (size_t i=0; i<cell_nodes.size(); ++i) {
181  CPhyloTreeNode& node = (*tree)[cell_nodes[i]];
182 
183  float r;
184  CVect2<float> p = node->GetNodePosEx(CVect3<float>(m_Scale.X(), m_Scale.Y(), 1.0f),
185  m_SL.GetPointer(), r);
186  // For selection need a minimal size of about 3 pixel radius regardless of how large node is displayed
187  // (nodes may not be displayed giving them a 0 size)
188  if (r < 3.0f)
189  r = 3.0f;
190 
191  // The node size is in pixels. add a bit to make selection easier...
192  r += 2.0f;
193 
194  // A 'hit' should be within a couple of pixels...
195  float xdelta = (x-p.X()) * 1.0f/m_Scale.X();
196  float ydelta = (y-p.Y()) * 1.0f/m_Scale.Y();
197 
198  float dist = sqrtf( xdelta*xdelta + ydelta*ydelta );
199 
200  if (dist < r) {
201  bool vis_label = node->GetVisible() && labels_visible;
202 
203  // Favor nodes with visible labels over ones without:
204  if (vis_label && dist < best_vis_label_dist) {
205  best_vis_idx = cell_nodes[i];
206  best_vis_label_dist = dist;
207  }
208  else if (!vis_label && dist < best_hidden_label_dist) {
209  best_hidden_idx = cell_nodes[i];
210  best_hidden_label_dist = dist;
211  }
212  }
213  // Allow selection to occur by clicking on label too (when visible)
214  else if (node->GetVisible() && labels_visible) {
215  // Check if user clicked inside label rectangle
216  CVect2<float> ll;
217  CVect2<float> ur;
218 
219  if (node->PointInTextBox(m_Scale, CVect2<float>(x,y), rotated_labels)) {
220  // How good of a hit? pretty binary if you click inside the label. Just
221  // evaluate is if you clicked on the edge of the node.
222  best_vis_idx = cell_nodes[i];
223  best_vis_label_dist = node->GetNodeSize();
224  }
225  }
226  }
227 
228  if (best_vis_idx > -1) {
229  tree_idx = best_vis_idx;
230  }
231  else if (best_hidden_idx != -1) {
232  tree_idx = best_hidden_idx;
233  }
234 
235  return tree_idx;
236 }
237 
238 vector<CPhyloTree::TTreeIdx> CTreeCollisionModel2D::SelectNodes(float x1, float y1, float x2, float y2)
239 {
240  vector<CPhyloTree::TTreeIdx> sel_nodes;
241 
242  if (m_Model == NULL)
243  return sel_nodes;
244 
245  // Get index for lower-left corner cell in which (x1,y1) falls.
246  TVeci idx1(int(floorf(x1/m_ResolutionX)),
247  int(floorf(y1/m_ResolutionY)));
248  idx1 -= m_MinIdx;
249 
250  // Get index for upper-right corner cell in which (x2,y2) falls
251  TVeci idx2(int(floorf(x2/m_ResolutionX)),
252  int(floorf(y2/m_ResolutionY)));
253  idx2 -= m_MinIdx;
254 
255  // Iterate over all the cells (idx1-idx2)
256  // and for each cell iterate over all the nodes in it too
257  // see if they fall within (x1,x2)-(y1,y2)
258 
260 
261  for (int x = idx1.X(); x <= idx2.X(); ++x) {
262  for (int y = idx1.Y(); y <= idx2.Y(); ++y) {
263  TVeci idx(x,y);
264 
265  std::vector<size_t> cell_nodes = GetSafe(idx).m_Labels;
266 
267  // Find collisions between nodes hashed in this entry
268  for (size_t i = 0; i<cell_nodes.size(); ++i) {
269  CPhyloTreeNode& node = (*tree)[cell_nodes[i]];
270  CVect2<float> p = node->XY() - node->GetNodeOffset();
271 
272  // A 'hit' will include the center of the node in the bounding box
273  if (p.X() >= x1 && p.X() <= x2 &&
274  p.Y() >= y1 && p.Y() <= y2) {
275 
276  sel_nodes.push_back(cell_nodes[i]);
277  }
278  }
279  }
280  }
281 
282  // A node may overalp more than one cell in the sptial data structure, so
283  // we eliminate duplicates here
284  sort(sel_nodes.begin(), sel_nodes.end());
285  sel_nodes.erase(std::unique(sel_nodes.begin(), sel_nodes.end()), sel_nodes.end());
286 
287  return sel_nodes;
288 }
289 
291 {
292  m_Model = m;
293 
294  Update(pane, m_Scale);
295 }
296 
298 {
299  m_SL.Reset(&sl);
300 }
301 
303  const CVect2<float>& ur1,
304  const CVect2<float>& ll2,
305  const CVect2<float>& ur2)
306 {
307  bool xoverlap = !( (ll2.X() > ur1.X() || ur2.X() < ll1.X()) );
308  bool yoverlap = !( (ll2.Y() > ur1.Y() || ur2.Y() < ll1.Y()) );
309 
310  return (xoverlap && yoverlap);
311 }
312 
315  const CVect2<float>& s)
316  : m_Tree(tree)
317  , m_Scale(s) {}
318 
319  bool operator()(size_t lhs, size_t rhs)
320  {
321  return ((*m_Tree)[lhs]->GetMinX(m_Scale) <
322  (*m_Tree)[rhs]->GetMinX(m_Scale));
323  }
324 
327 };
328 
329 
331 {
332  if (m_Model == NULL)
333  return;
334 
335  CStopWatch t;
336  t.Start();
337 
338  // Lower left and upper right corners of currently visible rectangle
339  CVect2<float> ll((float)r.Left(), (float)r.Bottom());
340  CVect2<float> ur((float)r.Right(), (float)r.Top());
341 
342  // Indices in the datastructure for lower-left and upper right corners of
343  // current rectangle
344  CVect2<int> posi_ll(int(floorf(ll[0]/m_ResolutionX)) - m_MinIdx.X(),
345  int(floorf(ll[1]/m_ResolutionY)) - m_MinIdx.Y());
346  CVect2<int> posi_ur(int(floorf(ur[0]/m_ResolutionX)) - m_MinIdx.X(),
347  int(floorf(ur[1]/m_ResolutionY)) - m_MinIdx.Y());
348 
349 
350  m_VisMinIdx = posi_ll;
351  m_VisMaxIdx = posi_ur;
352 
353  // Guarantee no out-of-bounds errors:
354  posi_ll.X() = std::min(posi_ll.X(), m_Width-1);
355  posi_ll.X() = std::max(posi_ll.X(), 0);
356 
357  posi_ll.Y() = std::min(posi_ll.Y(), m_Height-1);
358  posi_ll.Y() = std::max(posi_ll.Y(), 0);
359 
360  posi_ur.X() = std::min(posi_ur.X(), m_Width-1);
361  posi_ur.X() = std::max(posi_ur.X(), 0);
362 
363  posi_ur.Y() = std::min(posi_ur.Y(), m_Height-1);
364  posi_ur.Y() = std::max(posi_ur.Y(), 0);
365 
366  // Indices in the datastructure for lower-left and upper right corners of
367  // rectangle visible at previous update
368  CVect2<int> prev_posi_ll(int(floorf(m_PrevVisMin[0]/m_ResolutionX)) - m_MinIdx.X(),
369  int(floorf(m_PrevVisMin[1]/m_ResolutionY)) - m_MinIdx.Y());
370  CVect2<int> prev_posi_ur(int(floorf(m_PrevVisMax[0]/m_ResolutionX)) - m_MinIdx.X(),
371  int(floorf(m_PrevVisMax[1]/m_ResolutionY)) - m_MinIdx.Y());
372 
373  // Guarantee no out-of-bounds errors:
374  prev_posi_ll.X() = std::min(prev_posi_ll.X(), m_Width-1);
375  prev_posi_ll.X() = std::max(prev_posi_ll.X(), 0);
376 
377  prev_posi_ll.Y() = std::min(prev_posi_ll.Y(), m_Height-1);
378  prev_posi_ll.Y() = std::max(prev_posi_ll.Y(), 0);
379 
380  prev_posi_ur.X() = std::min(prev_posi_ur.X(), m_Width-1);
381  prev_posi_ur.X() = std::max(prev_posi_ur.X(), 0);
382 
383  prev_posi_ur.Y() = std::min(prev_posi_ur.Y(), m_Height-1);
384  prev_posi_ur.Y() = std::max(prev_posi_ur.Y(), 0);
385 
387 
388  // Since an individual element may be in multiple grid cells, we
389  // iterate twice - once to turn off visibility for any element that
390  // overlaps a grid cell visible on the previous update, then again
391  // to turn on visibility for all overlapped cells.
392 
393  // A last interation finds overlaps between labels and picks labels to
394  // not draw.
395 
396  // Iterate over the whole grid subregion that was previously displayed
397  // and update all labels to be 'not visible' in that region.
398  for (int x = prev_posi_ll.X(); x <= prev_posi_ur.X(); ++x) {
399  for (int y = prev_posi_ll.Y(); y <= prev_posi_ur.Y(); ++y) {
400  TVeci idx(x,y);
401 
402  std::vector<size_t>& cell_nodes = Get(idx).m_Labels;
403  // Set individual labels to be not visible
404  for (size_t i=0; i<cell_nodes.size(); ++i) {
405  (*tree)[cell_nodes[i]]->SetVisible(false);
406  }
407  }
408  }
409 
410  // Iterate over the currently-visible grid which subdivides
411  // the space occupied by the tree into individual cells,
412  // turning visibility on for all non-empty labels in the region
413  for (int x = posi_ll.X(); x <= posi_ur.X(); ++x) {
414  for (int y = posi_ll.Y(); y <= posi_ur.Y(); ++y) {
415  TVeci idx(x,y);
416  std::vector<size_t>& cell_nodes = Get(idx).m_Labels;
417 
418  // Maintain sorted order here (could be moved to sync, but this will
419  // be fast for subsequent (already sorted..) updates...
420  // Sorting is desired so that we favor in overlaps the node starting
421  // further to the left (picking a standard makes display more consistent).
423  std::sort(cell_nodes.begin(), cell_nodes.end(), cmp);
424 
425  /// Could also be more efficient here to update bounding rect data
426  /// now rather than do it in inner AND outer loops below. (but we
427  /// have to add data to label class, making array larger...
428 
429  // Turn on visibility for non-blank cells
430  for (size_t i=0; i<cell_nodes.size(); ++i) {
431  if ((*tree)[cell_nodes[i]]->GetDisplayLabel() != "")
432  (*tree)[cell_nodes[i]]->SetVisible(true);
433  }
434  }
435  }
436 
437  // Find overlaps between visible labels and when that happens,
438  // set the second label to not be visible (second label, due to sorting,
439  // should be to the right of the first label).
440  // We do not do this for rotated labels as that would require overlap checking
441  // with non-axis-aligned bounding boxes and curerntly we only store a labels
442  // min/max x&&y extents.
443  if (!m_Model->GetRotateLabels()) {
444  for (int x = posi_ll.X(); x <= posi_ur.X(); ++x) {
445  for (int y = posi_ll.Y(); y <= posi_ur.Y(); ++y) {
446  TVeci idx(x,y);
447 
448  std::vector<size_t> cell_nodes = Get(idx).m_Labels;
449 
450  // Find collisions between nodes hashed in this entry
451  for (size_t i=0; i<cell_nodes.size(); ++i) {
452  CPhyloTreeNode& l1 = (*tree)[cell_nodes[i]];
453 
454  // labels can be blank - e.g. if it is not a leaf and rendering is turned off
455  // for interior nodes
456  CVect2<float> ll1, ur1;
457  bool label1_visible = (l1->GetVisible() && l1->GetDisplayLabel().length() > 0);
458  if (label1_visible)
459  l1->GetLabelRect(m_Scale, ll1, ur1, m_Model->GetRotateLabels());
460 
461  CVect2<float> nll1, nur1, nll2, nur2;
462  float scaled_nodesize_x1 = l1->GetNodeDisplaySize()*m_Scale.X();
463  float scaled_nodesize_y1 = l1->GetNodeDisplaySize()*m_Scale.Y();
464 
465  nll1.X() = l1->X()-scaled_nodesize_x1;
466  nll1.Y() = l1->Y()-scaled_nodesize_y1;
467  nur1.X() = l1->X()+scaled_nodesize_x1;
468  nur1.Y() = l1->Y()+scaled_nodesize_y1;
469 
470  for (size_t j=i+1; j<cell_nodes.size(); ++j) {
471  CPhyloTreeNode& l2 = (*tree)[cell_nodes[j]];
472  bool label2_visible = (l2->GetVisible() && l2->GetDisplayLabel().length() > 0);
473 
474  // If labels overlap, set second label (on the right of the first) to not visible
475  if (label2_visible) {
476  CVect2<float> ll2, ur2;
477  l2->GetLabelRect(m_Scale, ll2, ur2, m_Model->GetRotateLabels());
478  if (label1_visible && RectIntersect(ll1, ur1, ll2, ur2)) {
479  l2->SetVisible(false);
480  }
481  // check if second (to the right) label overlaps first node
482  else if (RectIntersect(ll2, ur2, nll1, nur1)) {
483  l2->SetVisible(false);
484  }
485  }
486 
487  // check if first label overlaps second node
488  if (label1_visible) {
489  float scaled_nodesize_x2 = l1->GetNodeDisplaySize()*m_Scale.X();
490  float scaled_nodesize_y2 = l1->GetNodeDisplaySize()*m_Scale.Y();
491  nll2.X() = l2->X()-scaled_nodesize_x2;
492  nll2.Y() = l2->Y()-scaled_nodesize_y2;
493  nur2.X() = l2->X()+scaled_nodesize_x2;
494  nur2.Y() = l2->Y()+scaled_nodesize_y2;
495 
496  if (RectIntersect(ll1, ur1, nll2, nur2)) {
497  l1->SetVisible(false);
498  }
499  }
500  }
501  }
502  }
503  }
504  }
505 
506  m_PrevVisMin = ll;
507  m_PrevVisMax = ur;
508 
509  m_VisUpdateTime = t.Elapsed();
510 }
511 
512 
513 
static CAttribMenu & GetInstance()
Return a static instance of CAttribMenu.
Definition: attrib_menu.cpp:50
class CAttribMenuItem
CAttribFloatMenuItem * AddFloat(const std::string &name, float *user_value=NULL, float initial_value=0.5f, float min_value=0.0f, float max_value=1.0f, float stepsize=0.01f)
CAttribIntMenuItem * AddIntReadOnly(const std::string &name, int *user_value)
CAttribMenu * AddSubMenuUnique(const std::string &name, void *user_value=NULL)
Convienance function to add a submenu to this menu.
CAttribFloatMenuItem * AddFloatReadOnly(const std::string &name, float *user_value)
Add entries to the menu which display the users value but do not update it.
bool RemoveMenuR(const std::string &name, void *user_value=NULL)
Search the menu(s) recursively for menu 'name' with the specified user data 'user_value'.
class CGlPane
Definition: glpane.hpp:62
Tree subclass also has functions and data needed for rendering and selection.
Definition: phylo_tree.hpp:52
class CSpatialHash2D Class for simple 2D spatial organization that allows for some collision checking...
CVect2< int > m_VisMinIdx
Range of visible indices from previous call to UpdateVisibility.
int m_Width
Width and heigt of table (m_MaxIdx-m_MinIdx)
TElemType & Get(const TVeci &item)
float m_ResolutionX
Divisor for dividing model-space resolution into table indices.
CVect2< float > m_PrevVisMin
Visible rectangle area from previous call to UpdateVisibility.
TElemType GetSafe(const TVeci &item) const
Return an empty TElemType if index is out of range.
TVeci m_MinIdx
Min/Max indicies in the table.
CVect2< float > m_Scale
Current scaling factor of model for viewing in x and y.
CStopWatch –.
Definition: ncbitime.hpp:1938
void Update(const CGlPane &pane, const CVect2< float > &scale)
Update all geometry (needed when topology changes)
CRef< CPhyloTreeScheme > m_SL
void UpdateScaled(const CGlPane &pane, const CVect2< float > &scale)
Only update scaled geometry (needed when zoom changes)
void Sync(const CGlPane &pane, CTreeGraphicsModel *m)
Insert data from model (labels/nodes)
CTreeGraphicsModel * m_Model
Underlying graphics model.
vector< size_t > SelectNodes(float x1, float y1, float x2, float y2)
Return all nodes within the region (x1,y1) - (x2,y2)
virtual void UpdateVisibility(const TModelRect &r)
Find collisions between labels in visible regions to determine visiblity.
size_t TestForNode(float x, float y, bool labels_visible, bool rotated_labels=false)
Return node at position (x,y), if any.
void SetScheme(CPhyloTreeScheme &sl)
Set rendering scheme for tree (has info needed for node sizes)
static bool RectIntersect(const CVect2< float > &ll1, const CVect2< float > &ur1, const CVect2< float > &ll2, const CVect2< float > &ur2)
Utility function returns true if rectangle one (ll1-ur1) intersects rectangle 2 (ll2-ur2)
class CTreeGraphicsModel Model for rendering tree graphics data.
vector< size_t > & GetNodeIndices()
Get all the nodes (indicies point to nodes in phylo tree)
CPhyloTree * GetTree()
Get the tree (to which the node indices belong)
float GetCurrentRotationAngle(const CGlPane &pane, const CPhyloTreeNode &n, bool &visible) const
Return node's label rotation angle for current zoom level.
static TTreeIdx Null()
Return the index value that represents a NULL node.
Definition: tree_model.hpp:678
int size() const
#define NULL
Definition: ncbistd.hpp:225
T & X()
Definition: vect2.hpp:107
T & Y()
Definition: vect2.hpp:109
TObjectType * GetPointer(void) THROWS_NONE
Get pointer,.
Definition: ncbiobj.hpp:998
void Reset(void)
Reset reference object.
Definition: ncbiobj.hpp:773
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
int i
yy_size_t n
constexpr auto sort(_Init &&init)
EIPRangeType t
Definition: ncbi_localip.c:101
The NCBI C++/STL use hints.
Defines: CTimeFormat - storage class for time format.
T max(T x_, T y_)
T min(T x_, T y_)
double r(size_t dimension_, const Int4 *score_, const double *prob_, double theta_)
vector< size_t > m_Labels
CVect2< float > m_Scale
CompareLabelX(CPhyloTree *tree, const CVect2< float > &s)
bool operator()(size_t lhs, size_t rhs)
Modified on Sat Dec 02 09:22:51 2023 by modify_doxy.py rev. 669887