/// <summary> /// This is a recursive method which is responsible for integration the specified /// node inside the tree. /// </summary> private void IntegrateTerminalNodeRecurse(SphereTreeNode <T> nodeToIntegrate, SphereTreeNode <T> parentNode) { // If this node still has room for children, we will add the integration node here. This 'if' statement // will also handle the special case in which only the root node currently exists inside the tree. if (parentNode.NumberOfChildren < _numberOfChildNodesPerNode) { // Add the node as a child of the parent node and ensure that the root node encapsulates it parentNode.AddChild(nodeToIntegrate); //parentNode.EncapsulateChildNode(nodeToIntegrate); parentNode.RecomputeCenterAndRadius(); } else { // If there is no more room, we will proceed by choosing one of the parent's children which // is closest to the node that we want to integrate. We choose the closest node because when // the node will be added as a child of it, we want the parent to grow as little as possible. List <SphereTreeNode <T> > children = parentNode.Children; SphereTreeNode <T> closestChild = FindClosestNode(children, nodeToIntegrate); if (closestChild == null) { return; } // If the closest child is not a terminal node, recurse. if (!closestChild.IsTerminal) { IntegrateTerminalNodeRecurse(nodeToIntegrate, closestChild); } else { SphereTreeNode <T> newParentNode = new SphereTreeNode <T>(closestChild.Sphere, this, default(T)); newParentNode.SetFlag(SphereTreeNodeFlags.SuperSphere); // Replace 'closestChild' with the new parent node and add both 'closestChild' and 'nodeToIntegrate' as children of it parentNode.RemoveChild(closestChild); parentNode.AddChild(newParentNode); newParentNode.AddChild(nodeToIntegrate); newParentNode.AddChild(closestChild); // Encapsulate the children inside the new node //newParentNode.EncapsulateChildNode(closestChild); //newParentNode.EncapsulateChildNode(nodeToIntegrate); // Ensure that the new node is fully contained inside the parent node //parentNode.EncapsulateChildNode(newParentNode); newParentNode.RecomputeCenterAndRadius(); parentNode.RecomputeCenterAndRadius(); } } }
/// <summary> /// The client code must call this function during each frame update in order /// to ensure that any pending node updates are performed. /// </summary> public void PerformPendingUpdates() { // First, ensure that all nodes are recomputed accordingly while (_nodesPendingRecomputation.Count != 0) { SphereTreeNode <T> node = _nodesPendingRecomputation.Dequeue(); // Note: If the node has any children left, we will recompute its volume. Otherwise, // we will remove the node from the tree. if (node.HasChildren) { node.RecomputeCenterAndRadius(); } else { RemoveNode(node); } } // At this point, all super sphere nodes have had their volume updated accordingly. // In the next step, we will integrate any necessary terminal nodes. while (_terminalNodesPendingIntegration.Count != 0) { SphereTreeNode <T> node = _terminalNodesPendingIntegration.Dequeue(); IntegrateTerminalNode(node); } }