using Quadtree.Items;
using System.Collections.Generic;
using UnityEngine;
namespace Quadtree
{
///
/// Main class of the Quadtree structure - it represents the root of the tree.
///
public class QuadtreeRoot : IQuadtreeRoot
where TItem : IItem
where TNode : INode, new()
{
public bool Initialized { get; set; }
public TNode CurrentRootNode { get; internal set; }
public float MinimumPossibleNodeSize => _minimumPossibleNodeSize;
///
protected float _minimumPossibleNodeSize = 1f;
public bool DisplayNumberOfItemsInGizmos => _displayNumberOfItemsInGizmos;
///
protected bool _displayNumberOfItemsInGizmos = false;
///
/// Determines side of root node expansion if necessary.
///
protected bool ExpansionRight = true;
///
/// Initializes Quadtree - creates initial root node and builds the tree (if allowed).
///
public QuadtreeRoot(Vector3 center, Vector3 size)
{
CurrentRootNode = new TNode
{
TreeRoot = this,
ParentNode = default,
Bounds = new Bounds(center, size),
};
Initialized = true;
}
public void Insert(TItem item)
{
// get item bounds
var itemBounds = item.GetBounds();
// expand root node if necessary
while (!CurrentRootNode.Contains(itemBounds))
Expand();
// insert item into the tree
CurrentRootNode.Insert(item);
}
public void Expand()
{
// the subnodes will be of the same size as current root node
var subBoundsSize = CurrentRootNode.Bounds.size;
var centerOffset = subBoundsSize * .5f;
// center if expanding to left
var center = CurrentRootNode.Bounds.min;
if (ExpansionRight)
{
// center if expanding to right
center = CurrentRootNode.Bounds.max;
}
var subNodes = new List(4);
var newRootNode = new TNode
{
TreeRoot = this,
ParentNode = default,
Bounds = new Bounds(center, subBoundsSize * 2f),
SubNodes = subNodes,
};
CurrentRootNode.ParentNode = newRootNode;
// top left node [-x +y]
centerOffset.x *= -1f;
subNodes.Insert((int)IntraLocation.UPPER_LEFT, new TNode
{
TreeRoot = this,
ParentNode = newRootNode,
Bounds = new Bounds(center + centerOffset, subBoundsSize),
});
// top right node [+x +y]
centerOffset.x *= -1f;
subNodes.Insert((int)IntraLocation.UPPER_RIGHT, !ExpansionRight
? CurrentRootNode
: new TNode
{
TreeRoot = this,
ParentNode = newRootNode,
Bounds = new Bounds(center + centerOffset, subBoundsSize),
});
// bottom right node [+x -y]
centerOffset.z *= -1f;
subNodes.Insert((int)IntraLocation.LOWER_RIGHT, new TNode
{
TreeRoot = this,
ParentNode = newRootNode,
Bounds = new Bounds(center + centerOffset, subBoundsSize),
});
// bottom left node [-x -y]
centerOffset.x *= -1f;
subNodes.Insert((int)IntraLocation.LOWER_LEFT, ExpansionRight
? CurrentRootNode
: new TNode
{
TreeRoot = this,
ParentNode = newRootNode,
Bounds = new Bounds(center + centerOffset, subBoundsSize),
});
// assign new root node
CurrentRootNode = newRootNode;
// toggle expansion side for next expansion
ExpansionRight = !ExpansionRight;
}
public List Find(Bounds bounds)
{
IList itemList = new List();
CurrentRootNode.FindAndAddItems(bounds, ref itemList);
return (List)itemList;
}
public void Remove(TItem item)
{
CurrentRootNode.Remove(item);
}
public void Clear()
{
CurrentRootNode.Clear();
}
}
}