1 | // ============================================================= // |
---|
2 | // // |
---|
3 | // File : GroupIterator.hxx // |
---|
4 | // Purpose : Iterate over all groups of a tree // |
---|
5 | // // |
---|
6 | // Coded by Ralf Westram (coder@reallysoft.de) in March 2017 // |
---|
7 | // http://www.arb-home.de/ // |
---|
8 | // // |
---|
9 | // ============================================================= // |
---|
10 | |
---|
11 | #ifndef GROUPITERATOR_HXX |
---|
12 | #define GROUPITERATOR_HXX |
---|
13 | |
---|
14 | #ifndef TREENODE_H |
---|
15 | #include <TreeNode.h> |
---|
16 | #endif |
---|
17 | |
---|
18 | class GroupIterator { |
---|
19 | // This iterates over all clades shown in a tree. |
---|
20 | // i.e. if a normal and a keeled group fall together, the iterator only stops once! |
---|
21 | // |
---|
22 | // Bug?: does not stop at keeled leaf groups |
---|
23 | // (better leave as is: currently only stops at inner nodes) |
---|
24 | |
---|
25 | ARB_edge edge; |
---|
26 | bool reverse; |
---|
27 | |
---|
28 | inline bool at_group() const { |
---|
29 | return |
---|
30 | edge.get_type() != EDGE_TO_ROOT && |
---|
31 | !edge.dest()->is_leaf() && |
---|
32 | edge.dest()->is_clade(); |
---|
33 | } |
---|
34 | |
---|
35 | void inc() { |
---|
36 | ARB_edge start(edge); |
---|
37 | do edge = edge.counter_previous(); |
---|
38 | while (!at_group() && start != edge); |
---|
39 | } |
---|
40 | void dec() { |
---|
41 | ARB_edge start(edge); |
---|
42 | do edge = edge.counter_next(); |
---|
43 | while (!at_group() && start != edge); |
---|
44 | } |
---|
45 | |
---|
46 | public: |
---|
47 | // forward iterator |
---|
48 | // * starts with topmost and "rootmost" groups (i.e. child groups follow parent groups) |
---|
49 | // |
---|
50 | // reverse iterator |
---|
51 | // * start with lowermost and "leafmost" groups (i.e. parent groups follow child groups) |
---|
52 | // |
---|
53 | // if 'start' node is a group => iterator will point to that group (after construction). |
---|
54 | // Otherwise the iterator automatically increments to the "next" group. |
---|
55 | |
---|
56 | GroupIterator(AP_tree *start, bool forward = true) : |
---|
57 | edge(start->father |
---|
58 | ? parentEdge(start).inverse() |
---|
59 | : ARB_edge(start->get_rightson(), start->get_leftson(), ROOT_EDGE)), |
---|
60 | reverse(!forward) |
---|
61 | { |
---|
62 | td_assert(implicated(!start->is_leaf() && start->is_clade(), |
---|
63 | at_group() && node() == start)); |
---|
64 | if (!at_group()) next(); |
---|
65 | } |
---|
66 | |
---|
67 | GroupIterator& next() { reverse ? inc() : dec(); return *this; } |
---|
68 | GroupIterator& previous() { reverse ? dec() : inc(); return *this; } |
---|
69 | |
---|
70 | bool valid() const { return at_group(); } // false if GroupIterator created on tree w/o groups |
---|
71 | |
---|
72 | AP_tree *node() const { |
---|
73 | td_assert(valid()); |
---|
74 | return DOWNCAST(AP_tree*, edge.dest()); |
---|
75 | } |
---|
76 | |
---|
77 | int get_clade_level() const { |
---|
78 | td_assert(valid()); |
---|
79 | return node()->calc_clade_level(); // brute-force (maintain inside GroupIterator?) |
---|
80 | } |
---|
81 | }; |
---|
82 | |
---|
83 | |
---|
84 | #else |
---|
85 | #error GroupIterator.hxx included twice |
---|
86 | #endif // GROUPITERATOR_HXX |
---|