internal override bool Remove(BroadPhaseEntry entry, out LeafNode leafNode, out Node replacementNode) { replacementNode = null; if (element == entry) { leafNode = this; return(true); } leafNode = null; return(false); }
internal override bool RemoveFast(BroadPhaseEntry entry, out LeafNode leafNode, out Node replacementNode) { //The fastremove leaf node procedure is identical to the brute force approach. //We don't need to perform any bounding box test here; if they're equal, they're equal! replacementNode = null; if (element == entry) { leafNode = this; return(true); } leafNode = null; return(false); }
internal override bool TryToInsert(LeafNode node, out Node treeNode) { InternalNode newTreeNode = InternalNode.nodePool.Take(); BoundingBox.CreateMerged(ref BoundingBox, ref node.BoundingBox, out newTreeNode.BoundingBox); Vector3 offset; Vector3.Subtract(ref newTreeNode.BoundingBox.Max, ref newTreeNode.BoundingBox.Min, out offset); newTreeNode.currentVolume = offset.X * offset.Y * offset.Z; //newTreeNode.maximumVolume = newTreeNode.currentVolume * InternalNode.MaximumVolumeScale; newTreeNode.childA = this; newTreeNode.childB = node; treeNode = newTreeNode; return(true); }
internal override bool RemoveFast(BroadPhaseEntry entry, out LeafNode leafNode, out Node replacementNode) { //Only bother checking deeper in the path if the entry and child have overlapping bounding boxes. bool intersects; childA.BoundingBox.Intersects(ref entry.boundingBox, out intersects); if (intersects && childA.RemoveFast(entry, out leafNode, out replacementNode)) { if (childA.IsLeaf) { replacementNode = childB; } else { //It was not a leaf node, but a child found the leaf. //Change the child to the replacement node. childA = replacementNode; replacementNode = this; //We don't need to be replaced! } return(true); } childB.BoundingBox.Intersects(ref entry.boundingBox, out intersects); if (intersects && childB.RemoveFast(entry, out leafNode, out replacementNode)) { if (childB.IsLeaf) { replacementNode = childA; } else { //It was not a leaf node, but a child found the leaf. //Change the child to the replacement node. childB = replacementNode; replacementNode = this; //We don't need to be replaced! } return(true); } replacementNode = this; leafNode = null; return(false); }
/// <summary> /// Adds an entry to the hierarchy. /// </summary> /// <param name="entry">Entry to add.</param> public override void Add(BroadPhaseEntry entry) { base.Add(entry); //Entities do not set up their own bounding box before getting stuck in here. If they're all zeroed out, the tree will be horrible. Vector3 offset; Vector3.Subtract(ref entry.boundingBox.Max, ref entry.boundingBox.Min, out offset); if (offset.X * offset.Y * offset.Z == 0) { entry.UpdateBoundingBox(); } //Could buffer additions to get a better construction in the tree. LeafNode node = leafNodes.Take(); node.Initialize(entry); if (root == null) { //Empty tree. This is the first and only node. root = node; } else { if (root.IsLeaf) //Root is alone. { root.TryToInsert(node, out root); } else { BoundingBox.CreateMerged(ref node.BoundingBox, ref root.BoundingBox, out root.BoundingBox); InternalNode internalNode = (InternalNode)root; Vector3.Subtract(ref root.BoundingBox.Max, ref root.BoundingBox.Min, out offset); internalNode.currentVolume = offset.X * offset.Y * offset.Z; //internalNode.maximumVolume = internalNode.currentVolume * InternalNode.MaximumVolumeScale; //The caller is responsible for the merge. Node treeNode = root; while (!treeNode.TryToInsert(node, out treeNode)) { ; //TryToInsert returns the next node, if any, and updates node bounding box. } } } }
internal override bool Remove(BroadPhaseEntry entry, out LeafNode leafNode, out Node replacementNode) { if (childA.Remove(entry, out leafNode, out replacementNode)) { if (childA.IsLeaf) { replacementNode = childB; } else { //It was not a leaf node, but a child found the leaf. //Change the child to the replacement node. childA = replacementNode; replacementNode = this; //We don't need to be replaced! } return(true); } if (childB.Remove(entry, out leafNode, out replacementNode)) { if (childB.IsLeaf) { replacementNode = childA; } else { //It was not a leaf node, but a child found the leaf. //Change the child to the replacement node. childB = replacementNode; replacementNode = this; //We don't need to be replaced! } return(true); } replacementNode = this; return(false); }
internal abstract bool RemoveFast(BroadPhaseEntry entry, out LeafNode leafNode, out Node replacementNode);
internal abstract bool TryToInsert(LeafNode node, out Node treeNode);
internal override bool TryToInsert(LeafNode node, out Node treeNode) { //Since we are an internal node, we know we have two children. //Regardless of what kind of nodes they are, figure out which would be a better choice to merge the new node with. //Use the path which produces the smallest 'volume.' BoundingBox mergedA, mergedB; BoundingBox.CreateMerged(ref childA.BoundingBox, ref node.BoundingBox, out mergedA); BoundingBox.CreateMerged(ref childB.BoundingBox, ref node.BoundingBox, out mergedB); Vector3 offset; float originalAVolume, originalBVolume; Vector3.Subtract(ref childA.BoundingBox.Max, ref childA.BoundingBox.Min, out offset); originalAVolume = offset.X * offset.Y * offset.Z; Vector3.Subtract(ref childB.BoundingBox.Max, ref childB.BoundingBox.Min, out offset); originalBVolume = offset.X * offset.Y * offset.Z; float mergedAVolume, mergedBVolume; Vector3.Subtract(ref mergedA.Max, ref mergedA.Min, out offset); mergedAVolume = offset.X * offset.Y * offset.Z; Vector3.Subtract(ref mergedB.Max, ref mergedB.Min, out offset); mergedBVolume = offset.X * offset.Y * offset.Z; //Could use factor increase or absolute difference if (mergedAVolume - originalAVolume < mergedBVolume - originalBVolume) { //merging A produces a better result. if (childA.IsLeaf) { InternalNode newChildA = nodePool.Take(); newChildA.BoundingBox = mergedA; newChildA.childA = childA; newChildA.childB = node; newChildA.currentVolume = mergedAVolume; //newChildA.maximumVolume = newChildA.currentVolume * MaximumVolumeScale; childA = newChildA; treeNode = null; return(true); } childA.BoundingBox = mergedA; InternalNode internalNode = (InternalNode)childA; internalNode.currentVolume = mergedAVolume; //internalNode.maximumVolume = internalNode.currentVolume * MaximumVolumeScale; treeNode = childA; return(false); } //merging B produces a better result. if (childB.IsLeaf) { //Target is a leaf! Return. InternalNode newChildB = nodePool.Take(); newChildB.BoundingBox = mergedB; newChildB.childA = node; newChildB.childB = childB; newChildB.currentVolume = mergedBVolume; //newChildB.maximumVolume = newChildB.currentVolume * MaximumVolumeScale; childB = newChildB; treeNode = null; return(true); } { childB.BoundingBox = mergedB; treeNode = childB; InternalNode internalNode = (InternalNode)childB; internalNode.currentVolume = mergedBVolume; //internalNode.maximumVolume = internalNode.currentVolume * MaximumVolumeScale; return(false); } }