///<summary> /// Adds an item to the QuadTree ///</summary> /// ///<param name="item">The object to add to the <see cref="T:System.Collections.Generic.ICollection`1" />.</param> ///<exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1" /> is read-only.</exception> public void Add(T item) { var wrappedObject = new QuadTreeObject <T>(item); _wrappedDictionary.Add(item, wrappedObject); _quadTreeRoot.insert(wrappedObject); }
void relocate(QuadTreeObject <T> item) { // Are we still inside our parent? if (quadRect.Contains(item.data.bounds)) { // Good, have we moved inside any of our children? if (_childTL != null) { var dest = getDestinationTree(item); if (item.owner != dest) { // Delete the item from this quad and add it to our child // Note: Do NOT clean during this call, it can potentially delete our destination quad var formerOwner = item.owner; delete(item, false); dest.insert(item); // Clean up ourselves formerOwner.cleanUpwards(); } } } else { // We don't fit here anymore, move up, if we can if (_parent != null) { _parent.relocate(item); } } }
/// <summary> /// Add an item to the object list. /// </summary> /// <param name="item">The item to add.</param> void add(QuadTreeObject <T> item) { if (_objects == null) { _objects = new List <QuadTreeObject <T> >(); } item.owner = this; _objects.Add(item); }
/// <summary> /// Moves the QuadTree object in the tree /// </summary> /// <param name="item">The item that has moved</param> internal void move(QuadTreeObject <T> item) { if (item.owner != null) { item.owner.relocate(item); } else { relocate(item); } }
/// <summary> /// Remove an item from the object list. /// </summary> /// <param name="item">The object to remove.</param> void remove(QuadTreeObject <T> item) { if (_objects != null) { int removeIndex = _objects.IndexOf(item); if (removeIndex >= 0) { _objects[removeIndex] = _objects[_objects.Count - 1]; _objects.RemoveAt(_objects.Count - 1); } } }
/// <summary> /// Deletes an item from this QuadTree. If the object is removed causes this Quad to have no objects in its children, it's children will be removed as well. /// </summary> /// <param name="item">The item to remove.</param> /// <param name="clean">Whether or not to clean the tree</param> internal void delete(QuadTreeObject <T> item, bool clean) { if (item.owner != null) { if (item.owner == this) { remove(item); if (clean) { cleanUpwards(); } } else { item.owner.delete(item, clean); } } }
/// <summary> /// Insert an item into this QuadTree object. /// </summary> /// <param name="item">The item to insert.</param> internal void insert(QuadTreeObject <T> item) { // If this quad doesn't contain the items rectangle, do nothing, unless we are the root if (!_rect.Contains(item.data.bounds)) { System.Diagnostics.Debug.Assert(_parent == null, "We are not the root, and this object doesn't fit here. How did we get here?"); if (_parent == null) { // This object is outside of the QuadTree bounds, we should add it at the root level add(item); } else { return; } } if (_objects == null || (_childTL == null && _objects.Count + 1 <= maxObjectsPerNode)) { // If there's room to add the object, just add it add(item); } else { // No quads, create them and bump objects down where appropriate if (_childTL == null) { subdivide(); } // Find out which tree this object should go in and add it there QuadTreeNode <T> destTree = getDestinationTree(item); if (destTree == this) { add(item); } else { destTree.insert(item); } } }
/// <summary> /// Get the child Quad that would contain an object. /// </summary> /// <param name="item">The object to get a child for.</param> /// <returns></returns> QuadTreeNode <T> getDestinationTree(QuadTreeObject <T> item) { // If a child can't contain an object, it will live in this Quad var destTree = this; if (_childTL.quadRect.Contains(item.data.bounds)) { destTree = _childTL; } else if (_childTR.quadRect.Contains(item.data.bounds)) { destTree = _childTR; } else if (_childBL.quadRect.Contains(item.data.bounds)) { destTree = _childBL; } else if (_childBR.quadRect.Contains(item.data.bounds)) { destTree = _childBR; } return(destTree); }