void copyTree(VisualNode* node_t, NodeTree& tree_t, const VisualNode* node_s, const NodeTree& tree_s) { auto& na_t = tree_t.getNA(); const auto& na_s = tree_s.getNA(); stack<VisualNode*> stk_t; stack<const VisualNode*> stk_s; stk_s.push(node_s); stk_t.push(node_t); while (stk_s.size() > 0) { const VisualNode* n = stk_s.top(); stk_s.pop(); VisualNode* next = stk_t.top(); stk_t.pop(); auto kids = n->getNumberOfChildren(); next->setNumberOfChildren(kids, na_t); next->setStatus(n->getStatus()); next->dirtyUp(na_t); for (auto i = 0u; i < kids; ++i) { stk_s.push(n->getChild(na_s, i)); stk_t.push(next->getChild(na_t, i)); } } }
void applyToEachNodePO(NodeTree& nt, const NodeAction& action) { /// PO-traversal requires two stacks std::stack<VisualNode*> stk_1; std::stack<VisualNode*> stk_2; auto* root = nt.getRoot(); auto& na = nt.getNA(); stk_1.push(root); while (stk_1.size() > 0) { auto* node = stk_1.top(); stk_1.pop(); stk_2.push(node); for (auto i = 0u; i < node->getNumberOfChildren(); ++i) { auto kid = node->getChild(na, i); stk_1.push(kid); } } while (stk_2.size() > 0) { auto* node = stk_2.top(); stk_2.pop(); action(node); } }
void applyToEachNode(NodeTree& nt, const NodeAction& action) { auto& na = nt.getNA(); for (int i = 0; i < na.size(); ++i) { action(na[i]); } }
void highlightSubtrees(NodeTree& nt, const std::vector<VisualNode*>& nodes) { QMutexLocker lock(&nt.getMutex()); auto& na = nt.getNA(); auto* root = nt.getRoot(); root->unhideAll(na); { QMutexLocker lock(&nt.getLayoutMutex()); root->layout(na); } // unhighlight all applyToEachNode(nt, [](VisualNode* n) { n->setHighlighted(false); }); for (auto node : nodes) { node->setHighlighted(true); } // TODO: hide not highlighted // HideNotHighlightedCursor hnhc(root, na); // PostorderNodeVisitor<HideNotHighlightedCursor>(hnhc).run(); nt.treeModified(); }
int calculateMaxDepth(const NodeTree& nt) { const auto& na = nt.getNA(); const auto* root = nt.getRoot(); return calcDepth(na, root); }
int calculateDepth(const NodeTree& nt, const VisualNode& node) { int count = 0; auto it = &node; auto& na = nt.getNA(); while ( (it = it->getParent(na)) ) { count++; } return count; }
void addChildren(VisualNode* node, NodeTree& nt, int kids) { auto& na = nt.getNA(); node->setNumberOfChildren(kids, na); node->dirtyUp(na); auto& stats = nt.getStatistics(); stats.undetermined += kids; int depth = tree_utils::calculateDepth(nt, *node) + 1; int new_depth = depth + 1; stats.maxDepth = std::max(stats.maxDepth, new_depth); };
void applyToEachNode(NodeTree& nt, VisualNode* node, const NodeAction& action) { auto& na = nt.getNA(); std::stack<VisualNode*> stk; stk.push(node); while(stk.size() > 0) { auto* curr_node = stk.top(); stk.pop(); action(curr_node); for (auto i = 0u; i < curr_node->getNumberOfChildren(); ++i) { auto child = curr_node->getChild(na, i); stk.push(child); } } }
//-------------------------------------------- //-------- FINDING IDENTICAL SUBTREES -------- //-------------------------------------------- // TODO/NOTE(maxim): This algorithm isn't supposed to work // (new groups pushed to the end), but I've failed // to find any cases where it produces a wrong result GroupsOfNodes_t findIdenticalShapes(NodeTree& nt) { /// ------ 0) group by height ------ std::vector<Group> groups = groupByHeight(nt); /// ------ 1) assign a group id to each node ------- std::unordered_map<const VisualNode*, PosInGroups> node2groupID; for (auto group_idx = 1u; group_idx < groups.size(); ++group_idx) { auto& group = groups[group_idx]; for (auto i = 0u; i < group.items.size(); ++i) { auto* node = group.items[i].node; node2groupID[node].g_id = group_idx; node2groupID[node].inner_idx = i; } } // printGroups(groups); // qDebug() << " "; /// ------ 2) select the first block (with height 1) for (auto group_id = 0u; group_id < groups.size(); ++group_id) { for (auto alt = 0; alt < 2; ++alt) { auto& block = groups[group_id]; std::vector<int> groups_to_split; // qDebug() << "left children:"; for (auto& e : block.items) { if (e.alt == alt) { /// 3.1) get its parent auto& na = nt.getNA(); auto parent = e.node->getParent(na); // std::cerr << parent->debug_id << " "; /// 3.2 )find it in groups auto location = detail::findNodeInGroups(groups, node2groupID, parent); // std::cerr << parent->debug_id << " in group: " << location.first << "\n"; /// group g_idx will potentially need splitting auto g_idx = location.first; groups_to_split.push_back(g_idx); /// NOTE(maxim): has duplicate elements (?) detail::separateNode(groups[g_idx], node2groupID, location.second); // qDebug() << "node: " << e.node->debug_id; // qDebug() << "separate: " << parent->debug_id; /// split only affected groups } } // qDebug() << "groups before:"; // printGroups(groups); detail::splitGroups(groups, groups_to_split, node2groupID); // qDebug() << "groups after:"; // printGroups(groups); // qDebug() << " "; groups_to_split.clear(); // qDebug() << "groups: " << groups; } } /// ----- sort the groups ----- #ifdef MAXIM_DEBUG sort(begin(groups), end(groups), [](const Group& lhs, const Group& rhs) { if (lhs.items.size() == 0 && rhs.items.size() == 0) { return false; } if (lhs.items.size() == 0) { return false; } if (rhs.items.size() == 0) { return true; } return lhs.items[0].node->debug_id < rhs.items[0].node->debug_id; }); #endif /// convert groups to a vector of vectors of Nodes std::vector<std::vector<VisualNode*>> result(groups.size()); for (auto i = 0u; i < groups.size(); ++i) { auto& items = groups[i].items; result[i].reserve(items.size()); // qDebug() << "copying " << items.size() << " elements"; for (auto j = 0u; j < items.size(); ++j) { result[i].push_back(items[j].node); } } return result; }