/// <summary> /// Insert an item into the tree this is the root of. /// </summary> /// <param name="itemInterval"></param> /// <param name="item"></param> public void Insert( Interval itemInterval, object item ) { int index = GetSubnodeIndex( itemInterval, _origin ); // if index is -1, itemEnv must contain the origin. if ( index == -1 ) { Add( item ); return; } // the item must be contained in one interval, so insert it into the // tree for that interval (which may not yet exist) Node node = _subnode[index]; // If the subnode doesn't exist or this item is not contained in it, // have to expand the tree upward to contain the item. if ( node == null || !node.Interval.Contains(itemInterval) ) { Node largerNode = Node.CreateExpanded( node, itemInterval ); _subnode[index] = largerNode; } // At this point we have a subnode which exists and must contain // contains the env for the item. Insert the item into the tree. InsertContained( _subnode[index], itemInterval, item ); }
/// <summary> /// Return a square envelope containing the argement envelope, whose extent is a power of two and /// which is based at a power of 2. /// </summary> /// <param name="itemInterval"></param> public void ComputeKey( Interval itemInterval ) { _level = Key.ComputeLevel( itemInterval ); _interval = new Interval(); ComputeInterval( _level, itemInterval ); // MD - would be nice to have a non-iterative form of this algorithm while ( !_interval.Contains( itemInterval ) ) { _level += 1; ComputeInterval( _level, itemInterval ); } }
public ArrayList AddAllItemsFromOverlapping( Interval interval, ArrayList resultItems ) { if ( !IsSearchMatch( interval ) ) { return _items; } resultItems.AddRange( _items ); for (int i = 0; i < 2; i++) { if ( _subnode[i] != null ) { _subnode[i].AddAllItemsFromOverlapping( interval, resultItems ); } } return _items; }
/// <summary> /// Returns the subnode containing the envelope. Creates the node if it does not already exist. /// </summary> /// <param name="searchInterval"></param> /// <returns></returns> public Node GetNode( Interval searchInterval ) { int subnodeIndex = GetSubnodeIndex( searchInterval, _centre ); // if index is -1 searchEnv is not contained in a subnode if ( subnodeIndex != -1 ) { // create the node if it does not exist Node node = GetSubnode( subnodeIndex ); // recursively search the found/created node return node.GetNode( searchInterval ); } else { return this; } }
/// <summary> /// Returns the smallest existing node containing the envelope. /// </summary> /// <param name="searchInterval"></param> /// <returns></returns> public NodeBase Find( Interval searchInterval ) { int subnodeIndex = GetSubnodeIndex( searchInterval, _centre ); if ( subnodeIndex == -1 ) { return this; } if ( _subnode[subnodeIndex] != null ) { // query lies in subnode, so search it Node node = _subnode[subnodeIndex]; return node.Find( searchInterval ); } // no existing subnode, so return this one anyway return this; }
/// <summary> /// Initializes a new instance of the Key class. /// </summary> public Key( Interval interval ) { ComputeKey( interval ); }
public Interval(Interval interval) { Initialize( interval.Min, interval.Max ); }
public bool Overlaps( Interval interval ) { return Overlaps( interval.Min, interval.Max ); }
protected override bool IsSearchMatch( Interval itemInterval ) { return itemInterval.Overlaps( _interval ); }
public static Node CreateExpanded( Node node, Interval addInterval ) { Interval expandInt = new Interval( addInterval ); if ( node != null ) expandInt.ExpandToInclude( node.Interval ); Node largerNode = CreateNode( expandInt ); if ( node != null ) largerNode.Insert( node ); return largerNode; }
public void Query(Interval interval, ArrayList foundItems) { _root.AddAllItemsFromOverlapping( interval, foundItems ); }
/// <summary> /// Min and max may be the same value. /// </summary> /// <param name="interval"></param> /// <returns></returns> public ArrayList Query( Interval interval ) { // the items that are matched are all items in intervals // which overlap the query interval ArrayList foundItems = new ArrayList(); Query( interval, foundItems ); return foundItems; }
/// <summary> /// Insert an item which is known to be contained in the tree rooted at the given Noed. /// Lower levels of the tree will be created it necessary to hold the item. /// </summary> /// <param name="tree"></param> /// <param name="itemInterval"></param> /// <param name="item"></param> private void InsertContained( Node tree, Interval itemInterval, object item ) { Debug.Assert( tree.Interval.Contains( itemInterval) ); // Do NOT create a new node for zero-area intervals - this would lead // to infinite recursion. Instead, use a heuristic of simply returning // the smallest existing node containing the query bool isZeroArea = IntervalSize.IsZeroWidth( itemInterval.Min, itemInterval.Max ); NodeBase node; if ( isZeroArea ) { node = tree.Find( itemInterval ); } else { node = tree.GetNode( itemInterval ); } node.Add( item ); }
/// <summary> /// The root node matches all searches. /// </summary> /// <param name="interval"></param> /// <returns></returns> protected override bool IsSearchMatch( Interval interval ) { return true; }
private void ComputeInterval( int level, Interval itemInterval ) { double size = DoubleBits.PowerOf2( level ); //double size = pow2.power(level); _pt = Math.Floor( itemInterval.Min / size) * size; _interval.Initialize( _pt, _pt + size ); }
private Node CreateSubnode( int index ) { // create a new subnode in the appropriate interval double min = 0.0; double max = 0.0; switch (index) { case 0: min = _interval.Min; max = _centre; break; case 1: min = _centre; max = _interval.Max; break; } Interval subInt = new Interval( min, max ); Node node = new Node (subInt, _level - 1); return node; }
public static Node CreateNode( Interval itemInterval ) { Key key = new Key( itemInterval ); //System.out.println("input: " + env + " binaryEnv: " + key.getEnvelope()); Node node = new Node( key.Interval, key.Level ); return node; }
private void CollectStats( Interval interval ) { double del = interval.GetWidth(); if (del < _minExtent && del > 0.0) { _minExtent = del; } }
/// <summary> /// Initializes a new instance of the Node class. /// </summary> public Node( Interval interval, int level ) { _interval = interval; _level = level; _centre = ( interval.Min + interval.Max ) / 2; }
/// <summary> /// Ensure that the Interval for the inserted item has non-zero extents. /// Use the current minExtent to pad it, if necessary. /// </summary> /// <param name="itemInterval"></param> /// <param name="minExtent"></param> /// <returns></returns> public static Interval EnsureExtent( Interval itemInterval, double minExtent ) { double min = itemInterval.Min; double max = itemInterval.Max; // has a non-zero extent if (min != max) return itemInterval; // pad extent if (min == max) { min = min - minExtent / 2.0; max = min + minExtent / 2.0; } return new Interval(min, max); }
public void Insert( Interval itemInterval, object item ) { CollectStats( itemInterval ); Interval insertInterval = EnsureExtent( itemInterval, _minExtent ); _root.Insert( insertInterval, item ); /* DEBUG int newSize = size(); System.out.println("BinTree: size = " + newSize + " node size = " + nodeSize()); if (newSize <= oldSize) { System.out.println("Lost item!"); root.insert(insertInterval, item); System.out.println("reinsertion size = " + size()); }*/ }
/// <summary> /// Returns the index of the subnode that wholely contains the given interval. /// If none does, returns -1. /// </summary> /// <param name="interval"></param> /// <param name="centre"></param> /// <returns></returns> public static int GetSubnodeIndex( Interval interval, double centre ) { int subnodeIndex = -1; if (interval.Min >= centre) subnodeIndex = 1; if (interval.Max <= centre) subnodeIndex = 0; return subnodeIndex; }
public bool Contains( Interval interval ) { return Contains( interval.Min, interval.Max ); }
protected abstract bool IsSearchMatch( Interval interval );
public void ExpandToInclude( Interval interval ) { if ( interval.Max > _max ) _max = interval.Max; if ( interval.Min < _min ) _min = interval.Min; }
public static int ComputeLevel( Interval interval ) { double dx = interval.GetWidth(); //int level = BinaryPower.exponent(dx) + 1; int level = DoubleBits.Exponent(dx) + 1; return level; }