void ntree<tree_dim, world_dim, elem_t, common_data_t>:: rebalance() { // push all elements into the root node, calculate its bounding box // and call split_leaf_node if the element threshold is surpassed. clear_nodes(); Node& root = m_nodes.back(); if(!m_entries.empty()){ root.firstEntryInd = 0; root.lastEntryInd = m_entries.size() - 1; root.numEntries = m_entries.size(); for(size_t i = 0; i < m_entries.size(); ++i) m_entries[i].nextEntryInd = i+1; m_entries.back().nextEntryInd = s_invalidIndex; // the tight bounding box and the loose bounding box of the root node // should be the same. update_loose_bounding_box(root); root.tightBox = root.looseBox; if(root.numEntries >= m_desc.splitThreshold) split_leaf_node(0); } }
void ntree<tree_dim, world_dim, elem_t, common_data_t>:: split_leaf_node(size_t nodeIndex) { assert((m_nodes[nodeIndex].numEntries >= 2) && "Not enough elements in a node during split_leaf_node"); if(m_nodes[nodeIndex].childNodeInd[0] != s_invalidIndex) return; const size_t firstChild = m_nodes.size(); m_nodes.resize(firstChild + s_numChildren); // ATTENTION: Be careful not to resize m_nodes while using node, since this would invalidate the reference! Node& node = m_nodes[nodeIndex]; vector_t centerOfMass = calculate_center_of_mass(node); box_t childBoxes[s_numChildren]; traits::split_box(childBoxes, node.tightBox, centerOfMass); size_t numEntriesAssigned = 0; for(size_t entryInd = node.firstEntryInd; entryInd != s_invalidIndex;){ Entry& entry = m_entries[entryInd]; size_t nextEntryInd = entry.nextEntryInd; vector_t center; traits::calculate_center(center, entry.elem, m_commonData); for(size_t i_child = 0; i_child < s_numChildren; ++i_child){ if(traits::box_contains_point(childBoxes[i_child], center)){ add_entry_to_node(m_nodes[firstChild + i_child], entryInd); ++numEntriesAssigned; break; } } entryInd = nextEntryInd; } assert((numEntriesAssigned == node.numEntries) && "Couldn't find a matching child node for some elements during split_leaf_node:"); node.firstEntryInd = node.lastEntryInd = s_invalidIndex; node.numEntries = 0; for(size_t i_child = 0; i_child < s_numChildren; ++i_child){ node.childNodeInd[i_child] = firstChild + i_child; Node& childNode = m_nodes[firstChild + i_child]; childNode.level = node.level + 1; childNode.tightBox = childBoxes[i_child]; update_loose_bounding_box(childNode); } // since split_leaf_node resizes m_nodes and since this invalidates any references // to m_nodes, we perform the recursion in a last step for(size_t i_child = 0; i_child < s_numChildren; ++i_child){ size_t childNodeInd = firstChild + i_child; if(m_nodes[childNodeInd].numEntries >= m_desc.splitThreshold) split_leaf_node(childNodeInd); } }
void ntree<tree_dim, world_dim, elem_t, common_data_t>:: split_leaf_node(size_t nodeIndex) { if(m_nodes[nodeIndex].numEntries <= 1) return; if(m_nodes[nodeIndex].level >= m_desc.maxDepth){ if(m_warningsEnabled){ UG_LOG("WARNING in ntree::split_leaf_node(): maximum tree depth " << m_desc.maxDepth << " reached. No further splits are performed for " " this node. Note that too many elements per node may lead to performance issues.\n" << " Number of elements in this node: " << m_nodes[nodeIndex].numEntries << std::endl << " Corner coordinates of this node: " << m_nodes[nodeIndex].tightBox << std::endl); } return; } if(m_nodes[nodeIndex].childNodeInd[0] != s_invalidIndex) return; const size_t firstChild = m_nodes.size(); m_nodes.resize(firstChild + s_numChildren); // ATTENTION: Be careful not to resize m_nodes while using node, since this would invalidate the reference! Node& node = m_nodes[nodeIndex]; // calculate center of mass and use the traits class to split the box of // the current node into 's_numChildren' child boxes. Each child box thereby // spanned by one of the corners of the original box and 'centerOfMass'. vector_t centerOfMass = calculate_center_of_mass(node); box_t childBoxes[s_numChildren]; traits::split_box(childBoxes, node.tightBox, centerOfMass); // iterate over all entries in the current node and assign them to child nodes. size_t numEntriesAssigned = 0; for(size_t entryInd = node.firstEntryInd; entryInd != s_invalidIndex;){ Entry& entry = m_entries[entryInd]; size_t nextEntryInd = entry.nextEntryInd; size_t i_child; vector_t center; traits::calculate_center(center, entry.elem, m_commonData); for(i_child = 0; i_child < s_numChildren; ++i_child){ if(traits::box_contains_point(childBoxes[i_child], center)){ add_entry_to_node(m_nodes[firstChild + i_child], entryInd); ++numEntriesAssigned; break; } } /*-- For debugging only: --* if(i_child == s_numChildren){ UG_LOG ("ERROR in ntree::split_leaf_node(): Element with center @ " << center << " does not belong to any child of the box " << node.tightBox << std::endl); } *--*/ entryInd = nextEntryInd; } // all elements of the current box now should be assigned to child boxes. // we thus clear element lists and entry-count from the current node. UG_COND_THROW(numEntriesAssigned != node.numEntries, "Couldn't find a matching " "child node for some elements during split_leaf_node in " "ntree::split_leaf_node"); node.firstEntryInd = node.lastEntryInd = s_invalidIndex; node.numEntries = 0; for(size_t i_child = 0; i_child < s_numChildren; ++i_child){ node.childNodeInd[i_child] = firstChild + i_child; Node& childNode = m_nodes[firstChild + i_child]; childNode.level = node.level + 1; childNode.tightBox = childBoxes[i_child]; update_loose_bounding_box(childNode); } // since split_leaf_node resizes m_nodes and since this invalidates any references // to m_nodes, we perform the recursion in a last step for(size_t i_child = 0; i_child < s_numChildren; ++i_child){ size_t childNodeInd = firstChild + i_child; if(m_nodes[childNodeInd].numEntries >= m_desc.splitThreshold) split_leaf_node(childNodeInd); } }