/// <summary> /// Adds a new entry at a specified level in the tree /// </summary> /// <param name="r">the rectangle added</param> /// <param name="level">the level of the tree to add it at</param> internal void AddInternal(Rectangle r, int level, NodeBase childNode) { // I1 [Find position for new record] Invoke ChooseLeaf to select a leaf node L in which to place r NodeInternal n = (NodeInternal)chooseNode(r, level); NodeInternal newInternal = null; // I2 [Add record to leaf node] If L has room for another entry, install E. Otherwise invoke SplitNode to obtain L and LL containing E and all the old entries of L if (n.entryCount < maxNodeEntries) { n.addEntry(ref r, childNode); } else { newInternal = n.splitNode(this, ref r, childNode); } // I3 [Propagate changes upwards] Invoke AdjustTree on L, also passing LL if a split was performed NodeBase newNode = n.adjustTree(this, newInternal); // I4 [Grow tree taller] If node split propagation caused the root to split, create a new root whose children are the two resulting nodes. if (newNode != null) { NodeBase oldRoot = rootNode; NodeInternal root = new NodeInternal(++treeHeight, maxNodeEntries); rootNode = root; root.addEntry(ref newNode.minimumBoundingRectangle, newNode); root.addEntry(ref oldRoot.minimumBoundingRectangle, oldRoot); } }
internal NodeInternal adjustTree(RTree rTree, NodeInternal nn) { // AT1 [Initialize] Set N=L. If L was split previously, set NN to be the resulting second node. // AT2 [Check if done] If N is the root, stop NodeInternal n = this; while (n.level != rTree.treeHeight) { // AT3 [Adjust covering rectangle in parent entry] Let P be the parent node of N, and let En be N's entry in P. Adjust EnI so that it tightly encloses all entry rectangles in N. NodeInternal parent = rTree.parents.Pop() as NodeInternal; int entry = rTree.parentsEntry.Pop(); if (parent.childNodes[entry] != n) { throw new UnexpectedException("Error: entry " + entry + " in node " + parent + " should point to node " + n + "; actually points to node " + parent.childNodes[entry]); } Rectangle r = (Rectangle)parent.entries[entry]; if (r.MinX != n.minimumBoundingRectangle.MinX || r.MinY != n.minimumBoundingRectangle.MinY || r.MaxX != n.minimumBoundingRectangle.MaxX || r.MaxY != n.minimumBoundingRectangle.MaxY) { r = n.minimumBoundingRectangle; Update(); parent.entries[entry] = r; parent.recalculateMBR(); } // AT4 [Propagate node split upward] If N has a partner NN resulting from an earlier split, create a new entry Enn with Ennp pointing to NN and // Enni enclosing all rectangles in NN. Add Enn to P if there is room. Otherwise, invoke splitNode to produce P and PP containing Enn and all P's old entries. NodeInternal newNode = null; if (nn != null) { if (parent.entryCount < rTree.maxNodeEntries) { parent.addEntry(ref nn.minimumBoundingRectangle, nn); } else { newNode = parent.splitNode(rTree, ref nn.minimumBoundingRectangle, nn); } } // AT5 [Move up to next level] Set N = P and set NN = PP if a split occurred. Repeat from AT2 n = parent; nn = newNode; parent = null; newNode = null; } return(nn); }