| 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 |
|---|