void RemoveLeaf(IntervalNode <TData> leaf) { Debug.Assert(leaf.IsLeaf); var unbalancedNode = FindTopUnbalancedNode(leaf); if (unbalancedNode != null) { RebuildUnderNodeWithoutLeaf(unbalancedNode, leaf); UpdateParent(unbalancedNode); } else { //replace the parent with the sibling and update bounding boxes and counts var parent = leaf.Parent; if (parent == null) { Debug.Assert(rootNode == leaf); rootNode = new IntervalNode <TData>(); } else { TransferFromSibling(parent, leaf.IsLeftChild ? parent.Right : parent.Left); UpdateParent(parent); } } Debug.Assert(TreeIsCorrect(RootNode)); }
/// <summary> /// returns all leaf nodes for which the interval was hit and the delegate is happy with the object /// </summary> /// <param name="intervalPar"></param> /// <param name="hitTestAccept"></param> /// <returns></returns> public IEnumerable <TData> AllHitItems(Interval intervalPar, Func <TData, bool> hitTestAccept) { var stack = new Stack <IntervalNode <TData> >(); stack.Push(this); while (stack.Count > 0) { IntervalNode <TData> node = stack.Pop(); if (node.Interval.Intersects(intervalPar)) { if (node.IsLeaf) { if ((null == hitTestAccept) || hitTestAccept(node.UserData)) { yield return(node.UserData); } } else { stack.Push(node.left); stack.Push(node.right); } } } }
internal static void CrossIntervalNodes <TA, TB>(IntervalNode <TA> a, IntervalNode <TB> b, Action <TA, TB> action) { if (!a.interval.Intersects(b.interval)) { return; } if (a.Left == null) //a is a leat { if (b.Left == null) //b is a leaf { action(a.UserData, b.UserData); } else { CrossIntervalNodes(a, b.Left, action); CrossIntervalNodes(a, b.Right, action); } } else //a is not a leaf { if (b.Left != null) { CrossIntervalNodes(a.Left, b.Left, action); CrossIntervalNodes(a.Left, b.Right, action); CrossIntervalNodes(a.Right, b.Left, action); CrossIntervalNodes(a.Right, b.Right, action); } else // b is a leaf { CrossIntervalNodes(a.Left, b, action); CrossIntervalNodes(a.Right, b, action); } } }
static void AddNodeToTreeRecursive(IntervalNode <TData> newNode, IntervalNode <TData> existingNode) { if (existingNode.IsLeaf) { existingNode.Left = new IntervalNode <TData>(existingNode.UserData, existingNode.Interval); existingNode.Right = newNode; existingNode.Count = 2; existingNode.UserData = default(TData); } else { existingNode.Count++; Interval leftBox; Interval rightBox; if (2 * existingNode.Left.Count < existingNode.Right.Count) { //keep the balance AddNodeToTreeRecursive(newNode, existingNode.Left); existingNode.Left.Interval = new Interval(existingNode.Left.Interval, newNode.Interval); } else if (2 * existingNode.Right.Count < existingNode.Left.Count) { //keep the balance AddNodeToTreeRecursive(newNode, existingNode.Right); existingNode.Right.Interval = new Interval(existingNode.Right.Interval, newNode.Interval); } else //decide basing on the boxes { leftBox = new Interval(existingNode.Left.Interval, newNode.Interval); var delLeft = leftBox.Length - existingNode.Left.Interval.Length; rightBox = new Interval(existingNode.Right.Interval, newNode.Interval); var delRight = rightBox.Length - existingNode.Right.Interval.Length; if (delLeft < delRight) { AddNodeToTreeRecursive(newNode, existingNode.Left); existingNode.Left.Interval = leftBox; } else if (delLeft > delRight) { AddNodeToTreeRecursive(newNode, existingNode.Right); existingNode.Right.Interval = rightBox; } else //the deltas are the same; add to the smallest { if (leftBox.Length < rightBox.Length) { AddNodeToTreeRecursive(newNode, existingNode.Left); existingNode.Left.Interval = leftBox; } else { AddNodeToTreeRecursive(newNode, existingNode.Right); existingNode.Right.Interval = rightBox; } } } } existingNode.Interval = new Interval(existingNode.Left.Interval, existingNode.Right.Interval); }
static void TransferFromSibling(IntervalNode <TData> parent, IntervalNode <TData> sibling) { parent.UserData = sibling.UserData; parent.Left = sibling.Left; parent.Right = sibling.Right; parent.Count--; parent.Interval = sibling.Interval; }
static void UpdateParent(IntervalNode <TData> parent) { for (var node = parent.Parent; node != null; node = node.Parent) { node.Count--; node.Interval = new Interval(node.Left.Interval, node.Right.Interval); } }
static bool HandleEqualityCheck <TA>(IntervalNode <TA> a, Func <TA, TA, bool> func) { if (a.Left == null) { return(false); //we don't do anything for two equal leafs } return(FindIntersectionWithProperty(a.Left, a.Left, func) || FindIntersectionWithProperty(a.Left, a.Right, func) || FindIntersectionWithProperty(a.Right, a.Right, func)); }
/// <summary> /// we need to avoid calling action twice for the same pair /// </summary> /// <typeparam name="TA"></typeparam> /// <param name="a"></param> /// <param name="action"></param> static void HandleEquality <TA>(IntervalNode <TA> a, Action <TA, TA> action) { if (a.Left == null) { return; //we don't do anything for two equal leafs } CrossIntervalNodes <TA>(a.Left, a.Left, action); CrossIntervalNodes <TA>(a.Left, a.Right, action); CrossIntervalNodes <TA>(a.Right, a.Right, action); }
static IntervalNode <TData> FindTopUnbalancedNode(IntervalNode <TData> node) { for (var parent = node.Parent; parent != null; parent = parent.Parent) { if (!Balanced(parent)) { return(parent); } } return(null); }
static void RebuildUnderNodeWithoutLeaf(IntervalNode <TData> nodeForRebuild, IntervalNode <TData> leaf) { Debug.Assert(leaf.IsLeaf); Debug.Assert(!nodeForRebuild.IsLeaf); var newNode = IntervalNode <TData> .CreateIntervalNodeOnEnumeration( nodeForRebuild.GetAllLeafNodes().Where(n => !(n.Equals(leaf)))); nodeForRebuild.Count = newNode.Count; nodeForRebuild.Left = newNode.Left; nodeForRebuild.Right = newNode.Right; nodeForRebuild.Interval = new Interval(newNode.Left.interval, newNode.Right.interval); }
static public void TraverseHierarchy(IntervalNode <TData> node, Action <IntervalNode <TData> > visitor) { ValidateArg.IsNotNull(node, "node"); ValidateArg.IsNotNull(visitor, "visitor"); visitor(node); if (node.Left != null) { TraverseHierarchy(node.Left, visitor); } if (node.Right != null) { TraverseHierarchy(node.Right, visitor); } }
static bool TreeIsCorrect(IntervalNode <TData> node) { if (node == null) { return(true); } bool ret = node.Left != null && node.Right != null || node.Left == null && node.Right == null; if (!ret) { return(false); } return(TreeIsCorrect(node.Left) && TreeIsCorrect(node.Right)); }
internal void Add(IntervalNode <TData> node) { if (rootNode == null) { rootNode = node; } else if (Count <= 2) { rootNode = IntervalNode <TData> .CreateIntervalNodeOnEnumeration(rootNode.GetAllLeafNodes().Concat(new[] { node })); } else { AddNodeToTreeRecursive(node, rootNode); } }
/// <summary> /// /// </summary> /// <returns></returns> public IntervalNode <TData> Clone() { var ret = new IntervalNode <TData>(Count) { UserData = UserData, Interval = Interval }; if (Left != null) { ret.Left = Left.Clone(); } if (Right != null) { ret.Right = Right.Clone(); } return(ret); }
static public IntervalNode <TData> CreateIntervalNodeOnListOfNodes(IList <IntervalNode <TData> > nodes) { ValidateArg.IsNotNull(nodes, "nodes"); if (nodes.Count == 0) { return(null); } if (nodes.Count == 1) { return(nodes[0]); } //Finding the seeds var b0 = nodes[0].Interval; //the first seed int seed0 = 1; int seed1 = ChooseSeeds(nodes, ref b0, ref seed0); //We have two seeds at hand. Build two groups. var gr0 = new List <IntervalNode <TData> >(); var gr1 = new List <IntervalNode <TData> >(); gr0.Add(nodes[seed0]); gr1.Add(nodes[seed1]); var box0 = nodes[seed0].Interval; var box1 = nodes[seed1].Interval; //divide nodes on two groups DivideNodes(nodes, seed0, seed1, gr0, gr1, ref box0, ref box1, GroupSplitThreshold); var ret = new IntervalNode <TData>(nodes.Count) { Interval = new Interval(box0, box1), Left = CreateIntervalNodeOnListOfNodes(gr0), Right = CreateIntervalNodeOnListOfNodes(gr1) }; return(ret); }
static HitTestBehavior VisitTreeStatic(IntervalNode <TData> intervalNode, Func <TData, HitTestBehavior> hitTest, Interval hitInterval) { if (intervalNode.Interval.Intersects(hitInterval)) { if (hitTest(intervalNode.UserData) == HitTestBehavior.Continue) { if (intervalNode.Left != null) { // If intervalNode.Left is not null, intervalNode.Right won't be either. if (VisitTreeStatic(intervalNode.Left, hitTest, hitInterval) == HitTestBehavior.Continue && VisitTreeStatic(intervalNode.Right, hitTest, hitInterval) == HitTestBehavior.Continue) { return(HitTestBehavior.Continue); } return(HitTestBehavior.Stop); } return(HitTestBehavior.Continue); } return(HitTestBehavior.Stop); } return(HitTestBehavior.Continue); }
public IEnumerable <IntervalNode <TData> > GetLeafIntervalNodesIntersectingInterval(Interval intervalPar) { var stack = new Stack <IntervalNode <TData> >(); stack.Push(this); while (stack.Count > 0) { IntervalNode <TData> node = stack.Pop(); if (node.Interval.Intersects(intervalPar)) { if (node.IsLeaf) { yield return(node); } else { stack.Push(node.left); stack.Push(node.right); } } } }
internal static void CrossIntervalNodes <TA>(IntervalNode <TA> a, IntervalNode <TA> b, Action <TA, TA> action) { if (!a.interval.Intersects(b.interval)) { return; } if (Equals(a, b)) { HandleEquality(a, action); } else if (a.Left == null) { if (b.Left == null) { action(a.UserData, b.UserData); } else { CrossIntervalNodes <TA>(a, b.Left, action); CrossIntervalNodes <TA>(a, b.Right, action); } } else { if (b.Left != null) { CrossIntervalNodes <TA>(a.Left, b.Left, action); CrossIntervalNodes <TA>(a.Left, b.Right, action); CrossIntervalNodes <TA>(a.Right, b.Left, action); CrossIntervalNodes <TA>(a.Right, b.Right, action); } else { CrossIntervalNodes <TA>(a.Left, b, action); CrossIntervalNodes <TA>(a.Right, b, action); } } }
/// <summary> /// rebuild the whole tree /// </summary> public void Rebuild() { rootNode = IntervalNode <TData> .CreateIntervalNodeOnEnumeration(rootNode.GetAllLeafNodes()); }
/// <summary> /// Create a query tree for a given root node /// </summary> /// <param name="rootNode"></param> public IntervalRTree(IntervalNode <TData> rootNode) { this.rootNode = rootNode; }
static bool Balanced(IntervalNode <TData> rectangleNode) { return(2 * rectangleNode.Left.Count >= rectangleNode.Right.Count && 2 * rectangleNode.Right.Count >= rectangleNode.Left.Count); }
/// <summary> /// returns true if "property" holds for some pair /// </summary> /// <typeparam name="TA"></typeparam> /// <param name="a"></param> /// <param name="b"></param> /// <param name="property"></param> /// <returns></returns> internal static bool FindIntersectionWithProperty <TA>(IntervalNode <TA> a, IntervalNode <TA> b, Func <TA, TA, bool> property) { if (!a.interval.Intersects(b.interval)) { return(false); } if (Equals(a, b)) { return(HandleEqualityCheck(a, property)); } if (a.Left == null) { if (b.Left == null) { return(property(a.UserData, b.UserData)); } if (FindIntersectionWithProperty(a, b.Left, property)) { return(true); } if (FindIntersectionWithProperty(a, b.Right, property)) { return(true); } } else { if (b.Left != null) { if (FindIntersectionWithProperty(a.Left, b.Left, property)) { return(true); } if (FindIntersectionWithProperty(a.Left, b.Right, property)) { return(true); } if (FindIntersectionWithProperty(a.Right, b.Left, property)) { return(true); } if (FindIntersectionWithProperty(a.Right, b.Right, property)) { return(true); } } else { if (FindIntersectionWithProperty(a.Left, b, property)) { return(true); } if (FindIntersectionWithProperty(a.Right, b, property)) { return(true); } } } return(false); }
public IntervalRTree(IEnumerable <KeyValuePair <Interval, TData> > rectsAndData) { rootNode = IntervalNode <TData> .CreateIntervalNodeOnEnumeration(GetNodeRects(rectsAndData)); }