/// <summary> /// Removes the specified node from the tree. The client code should only /// ever call this method on nodes returned from 'AddNode'. /// </summary> public void RemoveNode(SphereTreeNode <T> node) { // The root node can never be removed if (node.IsFlagBitSet(BVHNodeFlags.Root)) { return; } // Keep moving up the hierarchy and remove all nodes which don't // have any child nodes any more. There's no point in keeping these // around as they're nothing but noise inside the tree. SphereTreeNode <T> parent = node.Parent; node.SetParent(null); while (parent != null && parent.NumChildren == 0 && !parent.IsFlagBitSet(BVHNodeFlags.Root)) { SphereTreeNode <T> newParent = parent.Parent; parent.SetParent(null); parent = newParent; } // We have been removing nodes, so we need to make sure that the parent // at which we stopped the removal process has its volume recalculated. parent.EncapsulateChildrenBottomUp(); }
/// <summary> /// Must be called whenever a node's bounding sphere has changed. /// </summary> public void OnNodeSphereUpdated(SphereTreeNode <T> node) { // Just make sure this is a terminal node. Otherwise, ignore. if (!node.IsFlagBitSet(BVHNodeFlags.Terminal)) { return; } // Check if the node is now outside of its parent if (node.IsOutsideParent()) { // The node is outside of its parent. In this case, the first step // is to detach it from its parent. SphereTreeNode <T> parent = node.Parent; node.SetParent(null); // Now if the parent no longer has any children, we remove it from the // tree. Otherwise, we make sure it properly encapsulates its children. if (parent.NumChildren == 0) { RemoveNode(parent); } else { parent.EncapsulateChildrenBottomUp(); } // The node needs to be reintegrated inside the tree IntegrateNodeRecurse(node, _root); } }
/// <summary> /// Integrates 'node' inside the tree. This is a recursive method which will /// search for the best place where to place this node inside the tree. /// </summary> /// <param name="parent"> /// Keeps track of the current parent node we are processing., Allow us to keep /// going down the tree hierarchy. /// </param> private void IntegrateNodeRecurse(SphereTreeNode <T> node, SphereTreeNode <T> parent) { // Are we dealing with a terminal node? if (!parent.IsFlagBitSet(BVHNodeFlags.Terminal)) { // This is not a terminal node. First thing to do is check if this node has // room for one more child. If it does, we add the node here. Otherwise, we // keep searching. if (parent.NumChildren < _numChildrenPerNode) { node.SetFlagsBits(BVHNodeFlags.Terminal); node.SetParent(parent); parent.EncapsulateChildrenBottomUp(); } else { // Find the child closest to 'node' and recurse down that path SphereTreeNode <T> closestChild = parent.ClosestChild(node); if (closestChild != null) { IntegrateNodeRecurse(node, closestChild); } } } else { // We have reached a terminal node. We have no choice but to create a new non-terminal // node to take the place of the terminal one and then attach the integration node and // the old terminal node as children of this new node. SphereTreeNode <T> newParentNode = new SphereTreeNode <T>(default(T), parent.Sphere); newParentNode.SetParent(parent.Parent); parent.SetParent(newParentNode); node.SetParent(newParentNode); node.SetFlagsBits(BVHNodeFlags.Terminal); newParentNode.EncapsulateChildrenBottomUp(); } }