public void MarkRebalanceIfNeeded(KdTreeNode <T> node) { if (!node.rebalance.Added && IsNodeUnbalanced(node)) { EnqueueRebalanceOnce(node); } }
private void TraverseOverlapping(KdTreeNode <T> node, AaRect rect, Action <T> action) { if (node.type == NodeType.Leaf) { var holder = node.leaf.holder; while (holder != null) { if (AaRect.Overlaps(rect, holder.fitRect)) { action(holder.body); } holder = holder.sibling.next; } } else { var pos = node.DetermineInnerNodePosition(rect); if (pos != ChildPosition.More) { TraverseOverlapping(node.inner.nodeLess, rect, action); } if (pos != ChildPosition.Less) { TraverseOverlapping(node.inner.nodeMore, rect, action); } TraverseOverlapping(node.inner.nodeBoth, rect, action); } }
private void ConvertToInnerMaybe(KdTree <T> tree) { if (count <= 1) { return; } bool successX = AttemptAxis(Axis.X, tree.tempHolderList, out var middleCountX, out var pivotX); bool successY = AttemptAxis(Axis.Y, tree.tempHolderList, out var middleCountY, out var pivotY); Axis foundAxis; int middleCount; float pivot; if (successX && (!successY || middleCountX < middleCountY)) { middleCount = middleCountX; foundAxis = Axis.X; pivot = pivotX; } else if (successY) { middleCount = middleCountY; foundAxis = Axis.Y; pivot = pivotY; } else { return; } if (middleCount >= count * 2 / 3) { return; } type = NodeType.Inner; inner.axis = foundAxis; inner.pivot = pivot; inner.nodeBoth = tree.MakeLeafNode(this); inner.nodeLess = tree.MakeLeafNode(this); inner.nodeMore = tree.MakeLeafNode(this); var holder = leaf.holder; leaf.holder = null; while (holder != null) { var nextHolder = holder.sibling.next; KdTreeNode <T> newParent = DetermineInnerNode(holder); holder.AddToHolderList(newParent); newParent.count++; holder = nextHolder; } PostProcessNewChildNode(tree, inner.nodeLess); PostProcessNewChildNode(tree, inner.nodeBoth); PostProcessNewChildNode(tree, inner.nodeMore); }
private bool IsNodeUnbalanced(KdTreeNode <T> node) { if (node.type == NodeType.Inner) { int sideThreshold = node.count * 2 / 3; int middleThreshold = node.count * 1 / 3; if (node.count <= 1) { return(true); } if (node.inner.nodeLess.count > sideThreshold) { return(true); } if (node.inner.nodeMore.count > sideThreshold) { return(true); } if (node.inner.nodeBoth.count > middleThreshold) { return(true); } return(false); } return(node.count > 2); }
private void AddAndRefreshInternal(KdTreeHolder <T> holder) { AssertConsistency(); KdTreeNode <T> fittingLeaf = DetermineFittingLeaf(holder); AddInternal(holder, fittingLeaf); RefreshAndMarkParents(fittingLeaf); AssertConsistency(); }
private void RefreshAndMarkParents(KdTreeNode <T> node) { while (node != null) { node.RefreshBounds(); MarkRebalanceIfNeeded(node); node = node.parent; } }
internal void DisposeNode(KdTreeNode <T> node) { RemoveFromRebalanceQueue(node); node.parent = null; node.inner.nodeLess = null; node.inner.nodeBoth = null; node.inner.nodeMore = null; node.leaf.holder = null; allocationCacheNode.Add(node); }
private void AddInternal(KdTreeHolder <T> holder, KdTreeNode <T> newParent) { holder.AddToHolderList(newParent); var node = newParent; while (node != null) { node.count++; node = node.parent; } }
internal KdTreeNode <T> MakeLeafNode(KdTreeNode <T> parent) { var node = Pop(allocationCacheNode) ?? new KdTreeNode <T>(); node.type = NodeType.Leaf; node.leaf.holder = null; node.parent = parent; node.count = 0; node.bounds = null; node.refresh = 0; return(node); }
public void AddToHolderList(KdTreeNode <T> newParent) { KdTreeHolder <T> oldfirst = newParent.leaf.holder; newParent.leaf.holder = this; if (oldfirst != null) { oldfirst.sibling.prev = this; } parent = newParent; sibling.next = oldfirst; sibling.prev = null; }
private bool EnqueueRebalanceOnce(KdTreeNode <T> node) { if (node.rebalance.Added) { return(false); } node.rebalance = new RebalanceLink <T>() { prev = rebalanceQueueSentinel.rebalance.prev, next = rebalanceQueueSentinel }; node.rebalance.prev.rebalance.next = node; node.rebalance.next.rebalance.prev = node; return(true); }
private void RemoveFromRebalanceQueue(KdTreeNode <T> node) { var oldprev = node.rebalance.prev; var oldnext = node.rebalance.next; if (oldprev != null) { oldprev.rebalance.next = oldnext; } if (oldnext != null) { oldnext.rebalance.prev = oldprev; } node.rebalance.prev = null; node.rebalance.next = null; }
public void RemoveFromHolderList() { var oldprev = sibling.prev; var oldnext = sibling.next; if (oldprev != null) { oldprev.sibling.next = sibling.next; } else { parent.leaf.holder = oldnext; } if (oldnext != null) { oldnext.sibling.prev = sibling.prev; } sibling.prev = null; sibling.next = null; parent = null; }
private void UpdateAndRefreshInternal(KdTreeHolder <T> holder) { AssertConsistency(); if (!holder.Update(this)) { return; } KdTreeNode <T> oldLeaf = holder.parent; KdTreeNode <T> newLeaf = DetermineFittingLeaf(holder); if (oldLeaf == newLeaf) { RefreshAndMarkParents(oldLeaf); return; } AssertConsistency(); RemoveInternal(holder); AddInternal(holder, newLeaf); RefreshAndMarkParents(oldLeaf); RefreshAndMarkParents(newLeaf); AssertConsistency(); }
private void DisposeChildrenAndMoveHolders(KdTreeNode <T> newLeaf, KdTree <T> tree) { switch (type) { case NodeType.Inner: { DisposeAndMoveHolders(ref inner.nodeLess, newLeaf, tree); DisposeAndMoveHolders(ref inner.nodeBoth, newLeaf, tree); DisposeAndMoveHolders(ref inner.nodeMore, newLeaf, tree); } break; case NodeType.Leaf: { var holder = leaf.holder; leaf.holder = null; while (holder != null) { var next = holder.sibling.next; holder.AddToHolderList(newLeaf); holder = next; } } break; } }
public KdTree() { rebalanceQueueSentinel = new KdTreeNode <T>(); rebalanceQueueSentinel.rebalance.prev = rebalanceQueueSentinel; rebalanceQueueSentinel.rebalance.next = rebalanceQueueSentinel; }
private void PostProcessNewChildNode(KdTree <T> tree, KdTreeNode <T> node) { node.RefreshBounds(); tree.MarkRebalanceIfNeeded(node); }
private void DisposeAndMoveHolders(ref KdTreeNode <T> node, KdTreeNode <T> newLeaf, KdTree <T> tree) { node.DisposeChildrenAndMoveHolders(newLeaf, tree); tree.DisposeNode(node); node = null; }