/// <summary> /// Searches for all data points below the input root for points that /// fall within the searchbox /// </summary> /// <param name="SearchBox">Area to search</param> /// <param name="aRoot">Node to start looking</param> /// <returns>List of all leafRecords that reside within the searchbox</returns> private List <LeafRecord <T> > search(RTreeRectangle SearchBox, NodeRecord <T> aRoot) { var matches = new List <LeafRecord <T> >(); if (!SearchBox.Overlaps(aRoot.BBox)) { // If there is no overlap, return nothing. return(matches); } else if (!aRoot.Node.IsLeaf()) { // If the node is not a leaf, recursively call this function // for each of its children. foreach (var childNode in aRoot.Node.GetRecords()) { NodeRecord <T> node = (NodeRecord <T>)childNode; matches = matches.Concat(search(SearchBox, node)).ToList(); } return(matches); } else { // If this node is a leaf, add each data point that resides in the // search box to the match list. foreach (var childNode in aRoot.Node.GetRecords()) { LeafRecord <T> node = (LeafRecord <T>)childNode; if (SearchBox.Overlaps(node.BBox)) { matches.Add(node); } } return(matches); } }
/// <summary> /// Finds the leaf node that contains the leaf record if able. /// </summary> /// <param name="item">Item to find</param> /// <param name="rRoot">Tree to search</param> /// <param name="rLeafPath">Path to node from root</param> /// <returns>true if leaf is found</returns> private bool findLeaf(LeafRecord <T> item, ref NodeRecord <T> rRoot, List <NodeRecord <T> > rLeafPath) { NodeRecord <T> node = rRoot; if (!node.Node.IsLeaf()) { foreach (var childNode in node.Node.GetRecords()) { if (childNode.BBox.Overlaps(item.BBox)) { node = (NodeRecord <T>)childNode; if (findLeaf(item, ref node, rLeafPath)) { rLeafPath.Insert(0, node); rRoot = node; return(true); } } } } else { foreach (var childNode in node.Node.GetRecords()) { LeafRecord <T> leaf = (LeafRecord <T>)childNode; if (leaf.IsEqual(item)) { return(true); } } } return(false); }
private void RDeletionTest() { Console.WriteLine("/////Deletion/////"); RTreeRectangle searchArea = new RTreeRectangle(); searchArea.X1 = -5; searchArea.Y1 = -1; searchArea.X2 = 0; searchArea.Y2 = 3; RTree <int> testTree = new RTree <int>(); // Outside testTree.Insert(99, 1, 0); testTree.Insert(100, 1, 6); var newleaf = new LeafRecord <int> { Data = 1, BBox = new RTreeRectangle() }; // Inside testTree.Insert(newleaf); testTree.Insert(2, -5, -1); testTree.Insert(3, 0, 3); testTree.Insert(4, -1, 2); testTree.Delete(newleaf); foreach (var leaf in testTree.Search(searchArea)) { Console.WriteLine(leaf.Data); } Console.WriteLine("/////Deletion Done/////"); }
/// <summary> /// Returns the node that the item should be added to. Additionally, /// it tracks each node it traversed to find the proper location. That list /// is called the leafPath and is used for split, and resize propagation. /// </summary> /// <param name="item">Item to insert</param> /// <param name="rLeafPath">Path from root to node where the item should be added.</param> /// <returns></returns> private NodeRecord <T> chooseLeaf(LeafRecord <T> item, List <NodeRecord <T> > rLeafPath) { // See Paper for naming // CL1. NodeRecord <T> N = root; rLeafPath.Add(N); while (true) { // CL2. if (N.Node.IsLeaf()) { return(N); } int minEnlargementArea = int.MaxValue; int minArea = int.MaxValue; // CL3. // Find the node that would require the least enlargement area to // add the new item. If there is a tie, use the node with the // smallest area. int enlargementArea; int nodeArea; foreach (var childNode in N.Node.GetRecords()) { NodeRecord <T> nodeRecord = (NodeRecord <T>)childNode; NodeRecord <T> F = nodeRecord; // See Paper for naming. enlargementArea = EnclosingArea(nodeRecord.BBox, item.BBox) - item.BBox.GetArea(); nodeArea = nodeRecord.BBox.GetArea(); if (enlargementArea < minEnlargementArea) { minEnlargementArea = enlargementArea; minArea = nodeArea; // CL4. N = F; } // Resolve ties using the node with the smallest size. else if (enlargementArea == minEnlargementArea) { if (nodeArea < minArea) { minArea = nodeArea; // CL4. N = F; } } } // N is now the child needing the least enlargement. rLeafPath.Add(N); } }
/// <summary> /// Inserts Data into the tree structure at point (X,Y) /// </summary> /// <param name="Data">Data to insert</param> /// <param name="X">X Coord of data</param> /// <param name="Y">Y Coord of data</param> public void Insert(T Data, int X, int Y) { LeafRecord <T> insert = new LeafRecord <T>(); insert.Data = Data; insert.BBox.X1 = X; insert.BBox.Y1 = Y; insert.BBox.X2 = X; insert.BBox.Y2 = Y; Insert(insert); }
/// <summary> /// Remove the input item from the list. /// </summary> /// <param name="item">Item to remove</param> public void Delete(LeafRecord <T> item) { NodeRecord <T> node = root; List <NodeRecord <T> > nodePath = new List <NodeRecord <T> >(); if (findLeaf(item, ref node, nodePath)) { nodePath.Insert(0, root); node.Node.GetRecords().Remove(item); condenseTree(node, nodePath); } }
/// <summary> /// Performs the insertion algorithm. /// </summary> /// <param name="item">Item to insert</param> public void Insert(LeafRecord <T> item) { List <NodeRecord <T> > leafPath = new List <NodeRecord <T> >(); // I1. // Track the nodes traversed to get to the point that we // want to add the node. This list of nodes will be used // to propagate changes up the tree. NodeRecord <T> insertNode = chooseLeaf(item, leafPath); NodeRecord <T> splitNode = null; // I2. // Attempts to insert the item in the given node. // If it fails, we split the node. Store the new // node in splitNode, so it can be propagated up // later. if (!insertNode.TryInsert(item)) { // Split. splitNode = insertNode.Split(item); } // I3. // Propagate resizing up the tree. Propagate split node // if necessary. if (adjustTree(leafPath, insertNode, ref splitNode)) { // I4. // Create a new root if the root was split. This new root is not a leaf. NodeRecord <T> newRoot = new NodeRecord <T>() { Node = new RTreeNode <T>(Leaf: false) }; newRoot.TryInsert(root); newRoot.TryInsert(splitNode); root = newRoot; } }
public bool IsEqual(LeafRecord <T> obj) { return(obj.BBox.IsEqual(BBox) && Data.Equals(obj.Data)); }