From c6de29bd5adc6ba97912b9d4073f8be69c3818e2 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Tue, 27 Dec 2016 19:29:32 +0700 Subject: [PATCH] External IItem for QuadTree --- .../IsoTools/Scripts/Internal/IsoQuadTree.cs | 151 ++++++++++-------- .../Scripts/Internal/IsoScreenSolver.cs | 26 ++- Assets/IsoTools/Scripts/IsoObject.cs | 35 ++-- 3 files changed, 121 insertions(+), 91 deletions(-) diff --git a/Assets/IsoTools/Scripts/Internal/IsoQuadTree.cs b/Assets/IsoTools/Scripts/Internal/IsoQuadTree.cs index f8d228d..2c2d2cb 100644 --- a/Assets/IsoTools/Scripts/Internal/IsoQuadTree.cs +++ b/Assets/IsoTools/Scripts/Internal/IsoQuadTree.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; - -namespace IsoTools.Internal { +namespace IsoTools.Internal { public class IsoQuadTree { // --------------------------------------------------------------------- @@ -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_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 _allItems = null; - IsoIPool _nodePool = null; - IsoIPool _itemPool = null; + Node _rootNode = null; + IsoIPool _nodePool = null; + IsoIPool _itemPool = null; // --------------------------------------------------------------------- // @@ -247,15 +254,12 @@ namespace IsoTools.Internal { public IsoQuadTree(int capacity) { _rootNode = null; - _allItems = new Dictionary(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; } diff --git a/Assets/IsoTools/Scripts/Internal/IsoScreenSolver.cs b/Assets/IsoTools/Scripts/Internal/IsoScreenSolver.cs index 06e1b5c..0d5a3fa 100644 --- a/Assets/IsoTools/Scripts/Internal/IsoScreenSolver.cs +++ b/Assets/IsoTools/Scripts/Internal/IsoScreenSolver.cs @@ -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; diff --git a/Assets/IsoTools/Scripts/IsoObject.cs b/Assets/IsoTools/Scripts/IsoObject.cs index 302456e..99827f7 100644 --- a/Assets/IsoTools/Scripts/IsoObject.cs +++ b/Assets/IsoTools/Scripts/IsoObject.cs @@ -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 Renderers = new List(); - public IsoAssocList SelfDepends = new IsoAssocList(47); - public IsoAssocList TheirDepends = new IsoAssocList(47); + public bool Dirty = true; + public bool Placed = true; + public IsoQuadTree.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 Renderers = new List(); + public IsoAssocList SelfDepends = new IsoAssocList(47); + public IsoAssocList TheirDepends = new IsoAssocList(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);