/// <summary> /// Reinserts or splits an overflown node. /// </summary> /// <param name="overflownNode">The overflown node.</param> /// <param name="canReinsert">Indicates whether the elements of the node can reinserted.</param> /// <param name="height">The height of the overflown node.</param> /// <returns></returns> private Boolean OverflowTreatment(RTreeNode overflownNode, Boolean canReinsert, Int32 height) { if (canReinsert) // reinsert { ReInsert(overflownNode, height); return(false); } else // split { RTreeNode first, second; SplitNode(overflownNode, out first, out second); if (overflownNode.Parent != null) { overflownNode.Parent.RemoveChild(overflownNode); overflownNode.Parent.AddChild(first); overflownNode.Parent.AddChild(second); } else // case when the root is split { _root = new RTreeNode(overflownNode.MaxChildren); _root.AddChild(first); _root.AddChild(second); _height++; return(false); } return(true); } }
/// <summary> /// Splits a node into two nodes. /// </summary> /// <param name="overflownNode">The overflown node.</param> /// <param name="firstNode">The first produced node.</param> /// <param name="secondNode">The second produced node.</param> protected virtual void SplitNode(RTreeNode overflownNode, out RTreeNode firstNode, out RTreeNode secondNode) { RTreeNode firstSeed, secondSeed; PickSeeds(overflownNode.Children, out firstSeed, out secondSeed); firstNode = (overflownNode.Parent != null) ? new RTreeNode(overflownNode.Parent) : new RTreeNode(overflownNode.MaxChildren); secondNode = (overflownNode.Parent != null) ? new RTreeNode(overflownNode.Parent) : new RTreeNode(overflownNode.MaxChildren); firstNode.AddChild(firstSeed); secondNode.AddChild(secondSeed); overflownNode.Children.Remove(firstSeed); overflownNode.Children.Remove(secondSeed); while (overflownNode.ChildrenCount > 0) { RTreeNode node = PickNext(overflownNode.Children); if (firstNode.ChildrenCount + overflownNode.ChildrenCount <= MinChildren) { firstNode.AddChild(node); } else if (secondNode.ChildrenCount + overflownNode.ChildrenCount <= MinChildren) { secondNode.AddChild(node); } else { Double firstEnlargement = firstNode.ComputeEnlargement(node.Envelope); Double secondEnlargement = secondNode.ComputeEnlargement(node.Envelope); if (firstEnlargement < secondEnlargement) { firstNode.AddChild(node); } else if (firstEnlargement > secondEnlargement) { secondNode.AddChild(node); } else { if (firstNode.Envelope.Surface < secondNode.Envelope.Surface) { firstNode.AddChild(node); } else { secondNode.AddChild(node); } } } } }
/// <summary> /// Adjusts the tree after insertion, and corrects the bounding envelope of the nodes. /// </summary> /// <param name="node">The node where the adjustment starts.</param> /// <param name="splitted">The second part of the node if the original node was split.</param> /// <param name="nodeToRemove">The original node which should be removed if the original node was split.</param> protected void AdjustTree(RTreeNode node, RTreeNode splitted = null, RTreeNode nodeToRemove = null) { RTreeNode n = node; RTreeNode nn = splitted; while (n.Parent != null) { RTreeNode parent = n.Parent; parent.CorrectBounding(n.Envelope); if (nn == null) { n = parent; } else { if (nodeToRemove != null) { parent.RemoveChild(nodeToRemove); parent.AddChild(n); } if (!parent.IsFull) { parent.AddChild(nn); n = parent; nn = null; } else { parent.AddChild(nn); SplitNode(parent, out n, out nn); nodeToRemove = parent; } } } // create new root node if the root is split if (nn != null) { _root = new RTreeNode(n.MaxChildren); _root.AddChild(n); _root.AddChild(nn); _height++; } }
/// <summary> /// Adds a node into the tree on a specified height. /// </summary> /// <param name="node">The node.</param> /// <param name="height">The height where the node should be inserted.</param> protected virtual void AddNode(RTreeNode node, Int32 height = -1) { RTreeNode nodeToInsert = ChooseNodeToAdd(node.Envelope, height); if (!nodeToInsert.IsFull) { if (nodeToInsert == _root && nodeToInsert.ChildrenCount == 0) { _height = 1; } nodeToInsert.AddChild(node); AdjustTree(nodeToInsert); } else { nodeToInsert.AddChild(node); RTreeNode firstNode, secondNode; SplitNode(nodeToInsert, out firstNode, out secondNode); AdjustTree(firstNode, secondNode, nodeToInsert); } }
/// <summary> /// Splits a node into two nodes. /// </summary> /// <param name="overflownNode">The overflown node.</param> /// <param name="firstNode">The first produced node.</param> /// <param name="secondNode">The second produced node.</param> protected override void SplitNode(RTreeNode overflownNode, out RTreeNode firstNode, out RTreeNode secondNode) { List <RTreeNode> alongChosenAxis = ChooseSplitAxis(overflownNode); Int32 minIndex = MinChildren; Double minOverlap = ComputeOverlap(Envelope.FromEnvelopes(alongChosenAxis.GetRange(0, MinChildren).Select(x => x.Envelope)), Envelope.FromEnvelopes(alongChosenAxis.GetRange(MinChildren, alongChosenAxis.Count - MinChildren).Select(x => x.Envelope))); // ChooseSplitIndex for (Int32 i = MinChildren + 1; i <= MaxChildren - MinChildren + 1; i++) { Double actOverlap = ComputeOverlap(Envelope.FromEnvelopes(alongChosenAxis.GetRange(0, i).Select(x => x.Envelope)), Envelope.FromEnvelopes(alongChosenAxis.GetRange(i, alongChosenAxis.Count - i).Select(x => x.Envelope))); if (minOverlap > actOverlap) { minOverlap = actOverlap; minIndex = i; } else if (minOverlap == actOverlap) { Double minArea = Envelope.FromEnvelopes(alongChosenAxis.GetRange(0, minIndex).Select(x => x.Envelope)).Surface + Envelope.FromEnvelopes(alongChosenAxis.GetRange(minIndex, alongChosenAxis.Count - minIndex).Select(x => x.Envelope)).Surface; Double actArea = Envelope.FromEnvelopes(alongChosenAxis.GetRange(0, i).Select(x => x.Envelope)).Surface + Envelope.FromEnvelopes(alongChosenAxis.GetRange(i, alongChosenAxis.Count - i).Select(x => x.Envelope)).Surface; if (minArea > actArea) { minIndex = i; } } } firstNode = (overflownNode.Parent != null) ? new RTreeNode(overflownNode.Parent) : new RTreeNode(overflownNode.MaxChildren); secondNode = (overflownNode.Parent != null) ? new RTreeNode(overflownNode.Parent) : new RTreeNode(overflownNode.MaxChildren); foreach (RTreeNode node in alongChosenAxis.GetRange(0, minIndex)) { firstNode.AddChild(node); } foreach (RTreeNode node in alongChosenAxis.GetRange(minIndex, alongChosenAxis.Count - minIndex)) { secondNode.AddChild(node); } }
/// <summary> /// Inserts a node into the tree on a specified height. /// </summary> /// <param name="node">The node.</param> /// <param name="height">The height where the node should be inserted.</param> /// <param name="startHeight">If the tree was grown during the reinsert, then the original height of the tree.</param> private void InsertInSpecifiedHeight(RTreeNode node, Int32 height, Int32 startHeight) { RTreeNode nodeToInsert = ChooseNodeToAdd(node.Envelope, height); if (nodeToInsert == _root && nodeToInsert.ChildrenCount == 0) { _height = 1; } if (height == -1) { height = Height - 1; startHeight = height; } nodeToInsert.AddChild(node); if (nodeToInsert.IsOverflown) { Boolean canReInsert; Boolean splitted; do { canReInsert = startHeight > 0 && !_visitedLevels[startHeight]; _visitedLevels[startHeight] = true; splitted = OverflowTreatment(nodeToInsert, canReInsert, height) && nodeToInsert.Parent.IsOverflown; nodeToInsert = nodeToInsert.Parent; height--; } while (splitted); } if (nodeToInsert != null) { AdjustTree(nodeToInsert); } }