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

Go to the SVN repository for this file.

1 /* $Id: phylo_tree_slanted_cladogram.cpp 43692 2019-08-14 18:15:15Z katargir $
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>
34 
35 
37 
38 //////////////////////////////////////////////////////////////////////
39 //
40 //////////////////////////////////////////////////////////////////////
41 
42 
44 {
45  m_DistMode = false;
46 }
47 
49  : IPhyloTreeRender(w, h)
50 {
51  m_DistMode = false;
52 }
53 
54 
56 {
57 }
58 
59 
61 {
62  m_Leafs = ds.GetSize();
63  m_Width = ds.GetWidth();
64 
65  m_yStep = m_DimY / ((m_Leafs>1)?(m_Leafs-1):2);
66  m_xStep = m_yStep;
67 
71 
72  CBoundaryPoints boundary_pts;
73  m_DistMode = false;
74  x_Calculate(ds.GetTree());
75 
76  if (ds.GetNormDistance() > 0){
78  }
79  else {
80  m_NormDistance = 1.0;
81  }
82 
83  // changing raster - x_Calculate for sure changed size in unpredictable way
84  TModelRect newRect = ds.GetBoundRect();
85 
86  m_RasterRect.Init(newRect.Left(),
87  newRect.Bottom(),
88  newRect.Right(),
89  newRect.Top());
90 
93 
96 }
97 
99 {
100  // Set drawing options that are specific to slanted cladogram
101  CGlVboNode* edge_node = ds.GetModel().FindGeomNode("TreeEdges");
102  CGlVboNode* narrow_edge_node = ds.GetModel().FindGeomNode("NarrowTreeEdges");
103  CGlVboNode* filler_points_node = m_DS->GetModel().FindGeomNode("FillerPoints");
104 
105  if (edge_node != NULL && narrow_edge_node != NULL) {
106  edge_node->GetState().Enable(GL_LINE_SMOOTH);
107  edge_node->GetState().Enable(GL_BLEND);
108  edge_node->GetState().BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
109 
110  narrow_edge_node->GetState().Enable(GL_LINE_SMOOTH);
111  narrow_edge_node->GetState().Enable(GL_BLEND);
112  narrow_edge_node->GetState().BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
113  }
114 
115  if (filler_points_node != NULL)
116  filler_points_node->SetVisible(false);
117 }
118 
120 {
121  CGlVboNode* edge_node = m_DS->GetModel().FindGeomNode("TreeEdges");
122  CGlVboNode* narrow_edge_node = m_DS->GetModel().FindGeomNode("NarrowTreeEdges");
123  CGlVboNode* point_node = m_DS->GetModel().FindGeomNode("NodePoints");
124  _ASSERT(edge_node != NULL && narrow_edge_node != NULL);
125 
126  //
127  GLsizei edge_count = (GLsizei)ds.GetNumEdges();
128  GLsizei node_count = (GLsizei)ds.GetNumNodes();
129 
130  CStopWatch timer;
131  timer.Start();
132 
133  if (edge_count > 0) {
134  vector<float> color_coords;
135  color_coords.reserve(node_count);
136 
137  vector<CVect2<float> > edge_node_coords;
138  edge_node_coords.reserve(edge_count * 2);
139 
140  vector<CVect4<unsigned char> > edge_node_colors;
141  edge_node_colors.reserve(edge_count * 2);
142 
143  x_DrawTreeVbo(edge_node_coords, edge_node_colors, color_coords, ds.GetTree());
144 
145  point_node->SetTexCoordBuffer1D(color_coords);
146 
147  edge_node->SetVertexBuffer2D(edge_node_coords);
148  edge_node->SetColorBufferUC(edge_node_colors);
149 
150  point_node->ClearPositions();
151  point_node->SetVisible(true);
152 
153  edge_node->SetDefaultPosition();
154  edge_node->SetVisible(true);
155  narrow_edge_node->SetDefaultPosition();
156  narrow_edge_node->SetVisible(true);
157  }
158  else if (node_count == 1) {
159  edge_node->SetVisible(false);
160  narrow_edge_node->SetVisible(false);
161 
162  vector<float> color_coords;
163  x_RenderNodeVbo(&ds.GetTree()->GetRoot(), ds.GetTree()->GetRootIdx(), color_coords);
164  point_node->SetTexCoordBuffer1D(color_coords);
165 
166  point_node->ClearPositions();
167  point_node->SetVisible(true);
168  }
169  else {
170  edge_node->SetVisible(false);
171  narrow_edge_node->SetVisible(false);
172  point_node->SetVisible(false);
173  }
174 }
175 
177 {
178 public:
180 
181 public:
184  : m_Clad(clad)
185  , m_ComputeBoundary(0)
186  {
188  m_Clad->InitExtents();
189 
190  m_yStep = m_Clad->GetDimY() / ((double)m_Clad->GetTreeHeight());
191  m_xStep = m_yStep;
192  m_SubtreeWidth = 0.0;
194 
197  m_LastStepY = 0.0;
198  }
199 
201  TTreeIdx node_idx, int delta)
202  {
203  if (delta == 1) {
205  }
206 
207  CPhyloTree::TNodeType& node = tree[node_idx];
208  if (delta==1 || delta==0){
209 
211  m_ComputeBoundary += 1;
212 
213  node.GetValue().SetAngle(0); // for correct labeling
214 
215  m_Clad->InitLabel(&tree, node);
216  if (node.IsLeafEx()) {
217  double step_size = 2.0*double(m_Clad->GetNodeLayoutSize(&node))*m_yStep;
218 
219  // Need to keep track of the yextent (top to bottom range)
220  // assigned to each node. For a leaf that is just the nodes y value
221  m_SubtreeWidth += m_LastStepY / 2.0 + step_size / 2.0;
222  double ypos = m_Clad->GetDimY() - m_SubtreeWidth;
223  m_SubtreeExtentY[node_idx].X() = ypos;
224  m_SubtreeExtentY[node_idx].Y() = ypos;
225 
226  node.GetValue().Y() = ypos;
227  node.GetValue().X() = m_Clad->GetDimX(); // all leafs on the right
228 
229  m_LastStepY = step_size;
230 
231  m_Clad->CalculateExtents(&tree, node);
232 
233  CBoundaryPoints node_boundary_pts;
234  m_Clad->x_ComputeNodeBoundary(&tree, node, node_boundary_pts, "SlantedCladogram");
236  m_ComputeBoundary -= 1;
237 
238  if (m_ComputeBoundary > 0) {
239  m_BoundaryPoints.top().AddBoundedPoints(node_boundary_pts);
240  }
241  }
242  }
243  else if (delta == -1) {
244  // We are skipping nodes with one child unless they are the root. Their
245  // positions are computed when we get to their first multi-child parent
246  if (node.GetChildren().size() != 1 || node.GetParent() == CPhyloTree::Null()) {
247  bool single_children = false;
248 
249  // Compute the maximum and minimum y values of this node's immediate
250  // children and save those in m_SubtreeExtentY. If any of the children
251  // only have 1 child of their own, descend into that subtree since we
252  // will need to compute the positions of any nodes that only have 1 child
253  // because they can't be positioned the normal way (as the average of
254  // their children's positions)
256  for (iter = node.SubNodeBeginEx(); iter < node.SubNodeEndEx(); ++iter) {
257  size_t child_idx =*iter;
258 
259  // Always make sure we take collapsed nodes into account
260  // here (collapsed nodes have 0 children)
261  size_t num_children = 0;
262  if (tree.GetNode(child_idx).Expanded())
263  num_children = tree.GetNode(child_idx).GetChildren().size();
264 
265  // If any of the child nodes have themselves only 1 child node, follow down
266  // until we find a leaf or a node with more than one child and use that
267  // nodes position to properly space the current node.
268  while (num_children == 1) {
269  single_children = true;
270  // Get single child node of current child node
271  CPhyloTreeNode& n = tree.GetNode(child_idx);
272  child_idx = n.GetChildren()[0];
273 
274  num_children = 0;
275  if (tree.GetNode(child_idx).Expanded())
276  num_children = tree.GetNode(child_idx).GetChildren().size();
277  }
278 
279  m_SubtreeExtentY[node_idx].X() = std::max(m_SubtreeExtentY[node_idx].X(), m_SubtreeExtentY[child_idx].X());
280  m_SubtreeExtentY[node_idx].Y() = std::min(m_SubtreeExtentY[node_idx].Y(), m_SubtreeExtentY[child_idx].Y());
281  }
282 
283  double yrange = m_SubtreeExtentY[node_idx].X() - m_SubtreeExtentY[node_idx].Y();
284 
285  // Set the nodes x && y position. Special case needed for root
286  // to handle possibility that it only has 1 child.
287  node.GetValue().Y() = m_SubtreeExtentY[node_idx].Y() + yrange / 2.0;
288  if (node.GetParent() == CPhyloTree::Null()) {
289  double root_offset = 0.0;
290  if (node.Expanded() && node.GetChildren().size() == 1)
291  ++root_offset;
292  node.GetValue().X() = m_Clad->GetDimX() - (yrange + root_offset*2.0*m_yStep);
293  }
294  else {
295  node.GetValue().X() = m_Clad->GetDimX() - yrange;
296  }
297 
298  m_Clad->CalculateExtents(&tree, node);
299 
300  // Calculate the positions iteratively of any single children
301  // of the current node. Positions will be interpolated between
302  // the position of the current node whose position we just
303  // computed and the first child node that is either a leaf
304  // or has more than one child (because leaves and nodes with more
305  // than one child will have a position defined already)
306  if (single_children) {
308  for (iter = node.SubNodeBeginEx(); iter < node.SubNodeEndEx(); ++iter) {
309  size_t child_idx = *iter;
310 
311  size_t num_children = 0;
312  if (tree.GetNode(child_idx).Expanded())
313  num_children = tree.GetNode(child_idx).GetChildren().size();
314 
315  double num_single_children = 0.0;
316 
317  while (num_children == 1) {
318  ++num_single_children;
319 
320  // Get single child node of current child node
321  CPhyloTreeNode& n = tree.GetNode(child_idx);
322  child_idx = n.GetChildren()[0];
323  num_children = 0;
324  if (tree.GetNode(child_idx).Expanded())
325  num_children = tree.GetNode(child_idx).GetChildren().size();
326 
328  if (n.GetValue().GetBoundedDisplay() == CPhyloNodeData::eBounded) {
329  m_ComputeBoundary += 1;
330  }
331  }
332 
333  // If we have single-child nodes between current node and ultimate child_idx
334  // (child_idx being the first node that has > 1 children OR is a leaf).
335  if (child_idx != *iter) {
336  size_t intermediate_idx = *iter;
337  ++num_single_children;
338  double child_num = num_single_children - 1.0;
339 
340  double x2 = tree.GetNode(child_idx).GetValue().X();
341  double x1 = node.GetValue().X();
342  double y2 = tree.GetNode(child_idx).GetValue().Y();
343  double y1 = node.GetValue().Y();
344 
345  while (intermediate_idx != child_idx) {
346  child_idx = (tree)[child_idx].GetParent();
347  CPhyloTreeNode& n = tree.GetNode(child_idx);
348 
349  // Set single child position as interpolated between current node and position
350  // of leaf node or last single child node (child_idx).
351  n.GetValue().Y() = y2*(child_num / num_single_children) +
352  y1*(num_single_children - child_num) / num_single_children;
353  n.GetValue().X() = x2*(child_num / num_single_children) +
354  x1*(num_single_children - child_num) / num_single_children;
355 
356  // Add boundary information for current node in case
357  // nodes have bounding area
358  CBoundaryPoints pts = m_BoundaryPoints.top();
359  m_BoundaryPoints.pop();
361  m_Clad->x_ComputeNodeBoundary(&tree, n, pts, "SlantedCladogram");
362 
363  if (n.GetValue().GetBoundedDisplay() == CPhyloNodeData::eBounded) {
364  m_ComputeBoundary -= 1;
365  }
366 
367  if (m_ComputeBoundary > 0) {
368  m_BoundaryPoints.top().AddBoundedPoints(pts);
369  }
370 
371  --child_num;
373  }
374  }
375  }
376  }
377 
378  // Each node that computes a boundary has to add in the points (and text rectangles)
379  // for all nodes below it in the tree
380  CBoundaryPoints pts = m_BoundaryPoints.top();
381  m_BoundaryPoints.pop();
382  m_Clad->x_ComputeNodeBoundary(&tree, node, pts, "SlantedCladogram");
383 
385  m_ComputeBoundary -= 1;
386  }
387 
388  if (m_ComputeBoundary > 0) {
389  m_BoundaryPoints.top().AddBoundedPoints(pts);
390  }
391  }
392  // If node has 1 child, just handle boundary info. position will
393  // be computed later.
394  else {
395  CBoundaryPoints pts = m_BoundaryPoints.top();
396  m_BoundaryPoints.pop();
397 
399  m_ComputeBoundary -= 1;
400  }
401  if (m_ComputeBoundary > 0) {
403  m_BoundaryPoints.top().AddBoundedPoints(pts);
404  }
405  }
406  }
407 
408  return eTreeTraverse;
409  }
410 
411  double GetYStep() const { return m_yStepDefault; }
412 
413 private:
416  stack<CBoundaryPoints> m_BoundaryPoints;
417  double m_xStep, m_yStep;
420  double m_LastStepY;
421 
422  // boundary points to remember value for single-child nodes because they
423  // are processed out-of-order (they are processed when the root or
424  // their first multi-child parent is encountered)
426 
427  /// for each node the width in pixels of the nodes underneath that node
428  /// the y value is the lower bound and x is the upper bound
429  vector<CVect2<double> > m_SubtreeExtentY;
430 };
431 
433 {
434  CCalcSlantedTree calc_tree(this, m_DS);
435 
436  TreeDepthFirstEx(*tree, calc_tree);
437  m_yStep = calc_tree.GetYStep();
438 }
439 
441 {
442 public:
444 
445 public:
447  const CPhyloTreeScheme* sl,
448  vector<CVect2<float> >& edge_node_coords,
449  vector<CVect4<unsigned char> >& edge_node_colors,
450  vector<float>& color_coords)
451  : m_Clad(clad)
452  , m_SL(clad->GetScheme())
453  , m_EdgeNodeCoords(edge_node_coords)
454  , m_EdgeNodeColors(edge_node_colors)
455  , m_ColorCoords(color_coords)
456  , m_NodeSingleSelection(clad->GetSingleSelection())
457  {
458  }
459 
461  TTreeIdx node_idx, int delta)
462  {
463  if (delta==1 || delta==0) {
464  CPhyloTree::TNodeType& node = tree[node_idx];
465  m_Clad->x_RenderNodeVbo(&node, node_idx, m_ColorCoords);
466 
467  // draw edges from node to parent
468  if (node.HasParent()){
469  CPhyloTree::TNodeType& parent = (tree)[node.GetParent()];
470 
471  m_Clad->x_RenderLineVbo(node_idx,
472  &node,
473  &parent,
476  parent.GetValue().X(),
477  parent.GetValue().Y(),
478  node.GetValue().X(),
479  node.GetValue().Y());
480  }
481  }
482  return eTreeTraverse;
483  }
484 
485 private:
488  vector<CVect2<float> >& m_EdgeNodeCoords;
489  vector<CVect4<unsigned char> >& m_EdgeNodeColors;
490  vector<float>& m_ColorCoords;
491 
492  // When user only wants to display a single, current selection from
493  // the selection set (including traced and commmon nodes).
495 };
496 
497 void CPhyloSlantedCladogram::x_DrawTreeVbo(vector<CVect2<float> >& edge_node_coords,
498  vector<CVect4<unsigned char> >& edge_node_colors,
499  vector<float>& color_coords,
500  CPhyloTree* tree)
501 {
502  CDrawSlantedTreeVbo draw_tree(this, m_SL.GetNCPointer(),
503  edge_node_coords, edge_node_colors,
504  color_coords);
505 
506  TreeDepthFirstEx(*tree, draw_tree);
507 }
508 
509 
511 {
512  return "Slanted Cladogram";
513 }
514 
void AddBoundedPoints(CBoundaryPoints &pts)
Add the boundary areas of the subtree to this boundary area.
vector< CVect2< double > > m_SubtreeExtentY
for each node the width in pixels of the nodes underneath that node the y value is the lower bound an...
CCalcSlantedTree(CPhyloSlantedCladogram *clad, CPhyloTreeDataSource *ds)
stack< CBoundaryPoints > m_BoundaryPoints
ETreeTraverseCode operator()(CPhyloTree &tree, TTreeIdx node_idx, int delta)
CPhyloSlantedCladogram * m_Clad
CDrawSlantedTreeVbo(CPhyloSlantedCladogram *clad, const CPhyloTreeScheme *sl, vector< CVect2< float > > &edge_node_coords, vector< CVect4< unsigned char > > &edge_node_colors, vector< float > &color_coords)
vector< CVect4< unsigned char > > & m_EdgeNodeColors
CPhyloTree::TSelState & m_NodeSingleSelection
ETreeTraverseCode operator()(CPhyloTree &tree, TTreeIdx node_idx, int delta)
CPhyloSlantedCladogram * m_Clad
vector< CVect2< float > > & m_EdgeNodeCoords
const CPhyloTreeScheme & m_SL
CGlVboNode A rendering node that holds a vertex buffer object.
Definition: glvbonode.hpp:64
TBoundingState GetBoundedDisplay() const
void SetAngle(float angle)
virtual void x_SetGlRenderOptions(CPhyloTreeDataSource &ds)
Set OpenGL rendering options that depend on layout chosen.
void x_Layout(CPhyloTreeDataSource &ds)
void x_RenderVbo(CPhyloTreeDataSource &ds)
void x_DrawTreeVbo(vector< CVect2< float > > &edge_node_coords, vector< CVect4< unsigned char > > &edge_node_colors, vector< float > &color_coords, CPhyloTree *tree)
CPhyloTree * GetTree()
unsigned int GetNumEdges(void)
unsigned int GetNumNodes(void)
double GetNormDistance(void)
CTreeGraphicsModel & GetModel()
Get model for rendering.
TModelRect GetBoundRect()
bool Expanded() const
Return true if node is currently not collapsed.
TNodeList_I SubNodeEndEx()
TNodeList_I SubNodeBeginEx()
Return the child nodes only if visible.
bool IsLeafEx() const
Return true if node is a leaf or is collapsed.
GLdouble GetLeafNodeSize() const
GLdouble GetNodeSize() const
Tree subclass also has functions and data needed for rendering and selection.
Definition: phylo_tree.hpp:52
vector< TSelStateValue > TSelState
Definition: phylo_tree.hpp:57
CStopWatch –.
Definition: ncbitime.hpp:1937
TTreeIdx GetParent() const
Get node's parent.
Definition: tree_model.hpp:82
TNodeList & GetChildren()
Return the indices of this node's child nodes.
Definition: tree_model.hpp:126
TNodeList::iterator TNodeList_I
Definition: tree_model.hpp:63
TData & GetValue()
Return the value object for the node.
Definition: tree_model.hpp:159
bool HasParent() const
Check if the node has a parent.
Definition: tree_model.hpp:90
static TTreeIdx Null()
Return the index value that represents a NULL node.
Definition: tree_model.hpp:678
size_t GetSize() const
Get the number of nodes currently in the array.
Definition: tree_model.hpp:218
TNodeType & GetRoot()
Return a reference to the root node of the tree.
Definition: tree_model.hpp:254
TTreeIdx GetRootIdx() const
Return the index of the root node.
Definition: tree_model.hpp:267
float m_TreePixels
Sum of size (height) of all leaf nodes in pixels, without considering labels (accomodates nodes that ...
CRef< CPhyloTreeScheme > m_SL
virtual float GetNodeLayoutSize(const CPhyloTreeNode *node) const
This is the height of the node for layout purposes.
virtual void x_ComputeNodeBoundary(CPhyloTree *tree, CPhyloTree::TNodeType &node, CBoundaryPoints &boundary_pts, const string &layout_type)
void InitExtents()
Set extents to default values so CalculateExtents can be called.
void InitLabel(CPhyloTree *tree, CPhyloTree::TNodeType &node)
Initialize (for current layout) label text and extent (label rectangle)
const double GetDimX(void)
float GetTreeHeight() const
Get sum of pixel size of all leaf nodes.
void x_RenderNodeVbo(CPhyloTreeNode *node, TTreeIdx node_idx, vector< float > &color_coords, const CVect2< float > delta=CVect2< float >(0.0f, 0.0f))
const double GetDimY(void)
CGlPane * m_pPane
event handling
void x_RenderLineVbo(TTreeIdx child_node_idx, CPhyloTreeNode *child_node, CPhyloTreeNode *parent_node, vector< CVect2< float > > &line_coords, vector< CVect4< unsigned char > > &line_colors, double x1, double y1, double x2, double y2)
float m_LabelPixels
Height of tree in pixels when labels are displayed.
ELayoutStatus m_ValidLayout
void CalculateExtents(CPhyloTree *tree, CPhyloTree::TNodeType &node)
CPhyloTreeDataSource * m_DS
CPhyloTreeScheme & GetScheme(void)
void ComputeViewingLimits(CGlPane &pane, bool force_square=false, bool init_collision_info=true)
Compute the optimal viewing pane size so that the tree occupies the entire viewing area,...
int size() const
#define NULL
Definition: ncbistd.hpp:225
void ClearPositions()
void SetModelLimitsRect(const TModelRect &R)
Definition: glpane.hpp:342
void SetTexCoordBuffer1D(const vector< float > &data)
Definition: glvbonode.cpp:131
void SetVertexBuffer2D(const vector< CVect2< float > > &data)
Definition: glvbonode.cpp:75
void SetDefaultPosition()
Set 1 transformation and have it be the identity matrix.
void Init()
Definition: glrect.hpp:62
T Top() const
Definition: glrect.hpp:84
T Bottom() const
Definition: glrect.hpp:82
T Right() const
Definition: glrect.hpp:83
virtual void Enable(GLenum glstate)
glEnable() all options in m_Enabled
Definition: glstate.cpp:356
CGlState & GetState()
T Left() const
Definition: glrect.hpp:81
void SetVisibleRect(const TModelRect &R)
Definition: glpane.cpp:113
void SetColorBufferUC(const vector< CVect4< unsigned char > > &data)
Definition: glvbonode.cpp:117
void SetVisible(bool b)
Set/get node visibility.
virtual void BlendFunc(GLenum sfactor, GLenum dfactor)
Options to be used when GL_BLEND is enabled.
Definition: glstate.cpp:562
CGlVboNode * FindGeomNode(const string &name)
Find a geometry (vertex buffer object) node by name.
Definition: glmodel2d.cpp:88
TObjectType * GetNCPointer(void) const THROWS_NONE
Get pointer,.
Definition: ncbiobj.hpp:1174
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
void Start(void)
Start the timer.
Definition: ncbitime.hpp:2764
ETreeTraverseCode
Tree traverse code returned by the traverse predicate function.
Definition: ncbi_tree.hpp:51
@ eTreeTraverse
Keep traversal.
Definition: ncbi_tree.hpp:52
yy_size_t n
T max(T x_, T y_)
T min(T x_, T y_)
Int4 delta(size_t dimension_, const Int4 *score_)
void TreeDepthFirstEx(TTreeModel &tree_model, typename TTreeModel::TTreeIdx node_idx, Fun &func)
Depth-first tree traversal that skips collapsed nodes.
Definition: phylo_tree.hpp:429
#define _ASSERT
Fun TreeDepthFirst(TTreeModel &tree_model, typename TTreeModel::TTreeIdx node_idx, Fun func)
Depth-first tree traversal algorithm.
Definition: tree_model.hpp:355
Modified on Fri Sep 20 14:58:04 2024 by modify_doxy.py rev. 669887