mirror of
https://github.com/BlackMATov/unity-iso-tools.git
synced 2025-12-13 15:52:03 +07:00
External IItem for QuadTree
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user