External IItem for QuadTree

This commit is contained in:
2016-12-27 19:29:32 +07:00
parent 7c40167da8
commit c6de29bd5a
3 changed files with 121 additions and 91 deletions

View File

@@ -1,6 +1,4 @@
using System.Collections.Generic;
namespace IsoTools.Internal {
namespace IsoTools.Internal {
public class IsoQuadTree<T> {
// ---------------------------------------------------------------------
@@ -9,6 +7,9 @@ namespace IsoTools.Internal {
//
// ---------------------------------------------------------------------
public interface IItem {
}
public interface IBoundsLookUpper {
void LookUp(IsoRect bounds);
}
@@ -73,24 +74,16 @@ namespace IsoTools.Internal {
item = null;
return false;
}
bool has_any_nodes = false;
for ( int i = 0, e = Nodes.Length; i < e; ++i ) {
var node = Nodes[i];
if ( node != null ) {
has_any_nodes = true;
if ( node.AddItem(bounds, content, out item, node_pool, item_pool) ) {
return true;
}
}
}
if ( has_any_nodes || Items.Count >= MinChildCountPerNode ) {
for ( int i = 0, e = Nodes.Length; i < e; ++i ) {
var node = Nodes[i];
if ( node == null && NodeBounds[i].Contains(bounds) ) {
Nodes[i] = node = node_pool.Take().Init(this, NodeBounds[i]);
if ( node.AddItem(bounds, content, out item, node_pool, item_pool) ) {
return true;
}
} else if ( Items.Count >= MinChildCountPerNode && NodeBounds[i].Contains(bounds) ) {
Nodes[i] = node = node_pool.Take().Init(this, NodeBounds[i]);
if ( node.AddItem(bounds, content, out item, node_pool, item_pool) ) {
return true;
}
}
}
@@ -100,11 +93,26 @@ namespace IsoTools.Internal {
}
public void RemoveItem(Item item, IsoIPool<Item> item_pool) {
if ( Items.Remove(item) ) {
if ( item != null && item.Owner == this && Items.Remove(item) ) {
item_pool.Release(item.Clear());
} else {
throw new System.ArgumentException("IsoQuadTree logic error", "item");
}
}
public bool HasAnyItems() {
if ( Items.Count > 0 ) {
return true;
}
for ( int i = 0, e = Nodes.Length; i < e; ++i ) {
var node = Nodes[i];
if ( node != null && node.HasAnyItems() ) {
return true;
}
}
return false;
}
public void VisitAllBounds(IBoundsLookUpper look_upper) {
look_upper.LookUp(SelfBounds);
for ( int i = 0, e = Nodes.Length; i < e; ++i ) {
@@ -187,7 +195,7 @@ namespace IsoTools.Internal {
//
// ---------------------------------------------------------------------
class Item {
class Item : IItem {
public Node Owner = null;
public IsoRect Bounds = IsoRect.zero;
public T Content = default(T);
@@ -234,10 +242,9 @@ namespace IsoTools.Internal {
//
// ---------------------------------------------------------------------
Node _rootNode = null;
Dictionary<T, Item> _allItems = null;
IsoIPool<Node> _nodePool = null;
IsoIPool<Item> _itemPool = null;
Node _rootNode = null;
IsoIPool<Node> _nodePool = null;
IsoIPool<Item> _itemPool = null;
// ---------------------------------------------------------------------
//
@@ -247,15 +254,12 @@ namespace IsoTools.Internal {
public IsoQuadTree(int capacity) {
_rootNode = null;
_allItems = new Dictionary<T, Item>(capacity);
_nodePool = new NodePool(capacity);
_itemPool = new ItemPool(capacity);
}
public void AddItem(IsoRect bounds, T content) {
if ( _allItems.ContainsKey(content) ) {
MoveItem(bounds, content);
} else if ( bounds.x.size > 0.0f && bounds.y.size > 0.0f ) {
public IItem AddItem(IsoRect bounds, T content) {
if ( bounds.x.size > 0.0f && bounds.y.size > 0.0f ) {
if ( _rootNode == null ) {
var initial_side = IsoUtils.Vec2From(
IsoUtils.Vec2MaxF(bounds.size));
@@ -270,30 +274,40 @@ namespace IsoTools.Internal {
bounds.center.x < _rootNode.SelfBounds.center.x,
bounds.center.y < _rootNode.SelfBounds.center.y);
}
_allItems.Add(content, item);
_rootNode.CleanUpNodes(_nodePool, _itemPool);
return item;
} else {
return _itemPool.Take().Init(null, bounds, content);
}
}
public void RemoveItem(T content) {
Item item;
if ( _allItems.TryGetValue(content, out item) ) {
_allItems.Remove(content);
var item_node = item.Owner;
public void RemoveItem(IItem iitem) {
if ( iitem == null ) {
throw new System.ArgumentNullException("iitem");
}
var item = iitem as Item;
var item_node = item.Owner;
if ( item_node != null ) {
item_node.RemoveItem(item, _itemPool);
if ( item_node.Items.Count == 0 ) {
BackwardNodeCleanUp(item_node);
}
} else {
_itemPool.Release(item.Clear());
}
}
public void MoveItem(IsoRect bounds, T content) {
Item item;
if ( _allItems.TryGetValue(content, out item) ) {
var item_node = item.Owner;
public IItem MoveItem(IsoRect bounds, IItem iitem) {
if ( iitem == null ) {
throw new System.ArgumentNullException("iitem");
}
var item = iitem as Item;
var item_node = item.Owner;
if ( item_node != null ) {
if ( item_node.SelfBounds.Contains(bounds) && item_node.Items.Count <= MinChildCountPerNode ) {
item.Bounds = bounds;
return item;
} else {
var content = item.Content;
item_node.RemoveItem(item, _itemPool);
if ( item_node.Items.Count == 0 ) {
item_node = BackwardNodeCleanUp(item_node) ?? _rootNode;
@@ -302,17 +316,17 @@ namespace IsoTools.Internal {
Item new_item;
if ( item_node.SelfBounds.Contains(bounds) ) {
if ( item_node.AddItem(bounds, content, out new_item, _nodePool, _itemPool) ) {
_allItems[content] = new_item;
return;
return new_item;
}
}
item_node = item_node.Parent;
}
_allItems.Remove(content);
AddItem(bounds, content);
return AddItem(bounds, content);
}
} else {
AddItem(bounds, content);
var content = item.Content;
_itemPool.Release(item.Clear());
return AddItem(bounds, content);
}
}
@@ -322,7 +336,6 @@ namespace IsoTools.Internal {
_rootNode.Clear(_nodePool, _itemPool));
_rootNode = null;
}
_allItems.Clear();
}
public void VisitAllBounds(IBoundsLookUpper look_upper) {
@@ -334,6 +347,18 @@ namespace IsoTools.Internal {
}
}
public void VisitItemsByItem(IItem iitem, IContentLookUpper look_upper) {
if ( iitem == null ) {
throw new System.ArgumentNullException("iitem");
}
if ( look_upper == null ) {
throw new System.ArgumentNullException("look_upper");
}
var item = iitem as Item;
item.Owner.VisitItemsByBounds(item.Bounds, look_upper);
BackwardVisitNodes(item.Owner.Parent, item.Bounds, look_upper);
}
public void VisitItemsByBounds(IsoRect bounds, IContentLookUpper look_upper) {
if ( look_upper == null ) {
throw new System.ArgumentNullException("look_upper");
@@ -343,20 +368,6 @@ namespace IsoTools.Internal {
}
}
public void VisitItemsByContent(T content, IContentLookUpper look_upper) {
if ( content == null ) {
throw new System.ArgumentNullException("content");
}
if ( look_upper == null ) {
throw new System.ArgumentNullException("look_upper");
}
Item item;
if ( _allItems.TryGetValue(content, out item) ) {
item.Owner.VisitItemsByBounds(item.Bounds, look_upper);
BackwardVisitNodes(item.Owner.Parent, item.Bounds, look_upper);
}
}
// ---------------------------------------------------------------------
//
// Private
@@ -370,20 +381,26 @@ namespace IsoTools.Internal {
top ? -new_root_bounds.size.y : 0.0f);
new_root_bounds.Resize(new_root_bounds.size * 2.0f);
var new_root = _nodePool.Take().Init(null, new_root_bounds);
if ( left ) {
if ( top ) {
new_root.Nodes[3] = _rootNode;
if ( _rootNode.HasAnyItems() ) {
if ( left ) {
if ( top ) {
new_root.Nodes[3] = _rootNode;
} else {
new_root.Nodes[1] = _rootNode;
}
} else {
new_root.Nodes[1] = _rootNode;
if ( top ) {
new_root.Nodes[2] = _rootNode;
} else {
new_root.Nodes[0] = _rootNode;
}
}
_rootNode.Parent = new_root;
} else {
if ( top ) {
new_root.Nodes[2] = _rootNode;
} else {
new_root.Nodes[0] = _rootNode;
}
_nodePool.Release(
_rootNode.Clear(_nodePool, _itemPool));
_rootNode = null;
}
_rootNode.Parent = new_root;
_rootNode = new_root;
}

View File

@@ -56,7 +56,10 @@ namespace IsoTools.Internal {
IsoScreenSolver screen_solver, IsoObject iso_object)
{
_isoObject = iso_object;
screen_solver._quadTree.VisitItemsByContent(iso_object, this);
if ( iso_object.Internal.QTItem != null ) {
screen_solver._quadTree.VisitItemsByItem(
iso_object.Internal.QTItem, this);
}
_isoObject = null;
}
}
@@ -149,8 +152,8 @@ namespace IsoTools.Internal {
// ---------------------------------------------------------------------
public void OnAddInstance(IsoObject iso_object) {
_quadTree.AddItem(
iso_object.Internal.ScreenBounds,
iso_object.Internal.QTItem = _quadTree.AddItem(
iso_object.Internal.QTBounds,
iso_object);
_minIsoXY = IsoUtils.Vec2Min(_minIsoXY, iso_object.position);
}
@@ -158,14 +161,23 @@ namespace IsoTools.Internal {
public void OnRemoveInstance(IsoObject iso_object) {
_oldVisibles.Remove(iso_object);
_curVisibles.Remove(iso_object);
_quadTree.RemoveItem(iso_object);
if ( iso_object.Internal.QTItem != null ) {
_quadTree.RemoveItem(iso_object.Internal.QTItem);
iso_object.Internal.QTItem = null;
}
ClearIsoObjectDepends(iso_object);
}
public bool OnMarkDirtyInstance(IsoObject iso_object) {
_quadTree.MoveItem(
iso_object.Internal.ScreenBounds,
iso_object);
if ( iso_object.Internal.QTItem != null ) {
iso_object.Internal.QTItem = _quadTree.MoveItem(
iso_object.Internal.QTBounds,
iso_object.Internal.QTItem);
} else {
iso_object.Internal.QTItem = _quadTree.AddItem(
iso_object.Internal.QTBounds,
iso_object);
}
_minIsoXY = IsoUtils.Vec2Min(_minIsoXY, iso_object.position);
if ( !iso_object.Internal.Dirty ) {
iso_object.Internal.Dirty = true;

View File

@@ -191,16 +191,17 @@ namespace IsoTools {
// ---------------------------------------------------------------------
public class InternalState {
public bool Dirty = true;
public bool Placed = true;
public IsoRect ScreenBounds = IsoRect.zero;
public IsoMinMax MinMax3d = IsoMinMax.zero;
public float Offset3d = 0.0f;
public Transform Transform = null;
public Vector2 LastTrans = Vector2.zero;
public List<Renderer> Renderers = new List<Renderer>();
public IsoAssocList<IsoObject> SelfDepends = new IsoAssocList<IsoObject>(47);
public IsoAssocList<IsoObject> TheirDepends = new IsoAssocList<IsoObject>(47);
public bool Dirty = true;
public bool Placed = true;
public IsoQuadTree<IsoObject>.IItem QTItem = null;
public IsoRect QTBounds = IsoRect.zero;
public IsoMinMax MinMax3d = IsoMinMax.zero;
public float Offset3d = 0.0f;
public Transform Transform = null;
public Vector2 LastTrans = Vector2.zero;
public List<Renderer> Renderers = new List<Renderer>();
public IsoAssocList<IsoObject> SelfDepends = new IsoAssocList<IsoObject>(47);
public IsoAssocList<IsoObject> TheirDepends = new IsoAssocList<IsoObject>(47);
}
public InternalState Internal = new InternalState();
@@ -255,9 +256,9 @@ namespace IsoTools {
var r = iso_world.IsoToScreen(position + IsoUtils.Vec3FromX(size.x)).x;
var b = iso_world.IsoToScreen(position).y;
var t = iso_world.IsoToScreen(position + size).y;
Internal.ScreenBounds.Set(l, b, r, t);
Internal.QTBounds.Set(l, b, r, t);
} else {
Internal.ScreenBounds.Set(0.0f, 0.0f, 0.0f, 0.0f);
Internal.QTBounds.Set(0.0f, 0.0f, 0.0f, 0.0f);
}
}
@@ -338,7 +339,7 @@ namespace IsoTools {
}
if ( iso_world.isShowScreenBounds ) {
IsoUtils.DrawRect(
Internal.ScreenBounds,
Internal.QTBounds,
Color.green);
}
}
@@ -349,16 +350,16 @@ namespace IsoTools {
if ( iso_world && iso_world.isShowDepends ) {
for ( int i = 0, e = Internal.SelfDepends.Count; i < e; ++i ) {
IsoUtils.DrawLine(
Internal.ScreenBounds.center,
Internal.SelfDepends[i].Internal.ScreenBounds.center,
Internal.QTBounds.center,
Internal.SelfDepends[i].Internal.QTBounds.center,
Color.yellow,
Color.cyan,
0.25f);
}
for ( int i = 0, e = Internal.TheirDepends.Count; i < e; ++i ) {
IsoUtils.DrawLine(
Internal.ScreenBounds.center,
Internal.TheirDepends[i].Internal.ScreenBounds.center,
Internal.QTBounds.center,
Internal.TheirDepends[i].Internal.QTBounds.center,
Color.yellow,
Color.cyan,
0.75f);