OctTree.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using Microsoft.Xna.Framework;
  7. using System.Diagnostics;
  8. namespace DwarfCorp
  9. {
  10. public class OctTreeNode<T>
  11. {
  12. public BoundingBox Bounds;
  13. public OctTreeNode<T>[] Children;
  14. public List<Tuple<T, BoundingBox>> Items = new List<Tuple<T, BoundingBox>>();
  15. private Vector3 Mid;
  16. private object Lock = new object();
  17. public OctTreeNode(Vector3 Min, Vector3 Max)
  18. {
  19. Bounds = new BoundingBox(Min, Max);
  20. Mid = new Vector3((Min.X + Max.X) / 2,
  21. (Min.Y + Max.Y) / 2,
  22. (Min.Z + Max.Z) / 2);
  23. }
  24. private void Subdivide()
  25. {
  26. lock (Lock)
  27. {
  28. var Min = Bounds.Min;
  29. var Max = Bounds.Max;
  30. Children = new OctTreeNode<T>[8]
  31. {
  32. /*000*/ new OctTreeNode<T>(new Vector3(Min.X, Min.Y, Min.Z), new Vector3(Mid.X, Mid.Y, Mid.Z)),
  33. /*001*/ new OctTreeNode<T>(new Vector3(Mid.X, Min.Y, Min.Z), new Vector3(Max.X, Mid.Y, Mid.Z)),
  34. /*010*/ new OctTreeNode<T>(new Vector3(Min.X, Mid.Y, Min.Z), new Vector3(Mid.X, Max.Y, Mid.Z)),
  35. /*011*/ new OctTreeNode<T>(new Vector3(Mid.X, Mid.Y, Min.Z), new Vector3(Max.X, Max.Y, Mid.Z)),
  36. /*100*/ new OctTreeNode<T>(new Vector3(Min.X, Min.Y, Mid.Z), new Vector3(Mid.X, Mid.Y, Max.Z)),
  37. /*101*/ new OctTreeNode<T>(new Vector3(Mid.X, Min.Y, Mid.Z), new Vector3(Max.X, Mid.Y, Max.Z)),
  38. /*110*/ new OctTreeNode<T>(new Vector3(Min.X, Mid.Y, Mid.Z), new Vector3(Mid.X, Max.Y, Max.Z)),
  39. /*111*/ new OctTreeNode<T>(new Vector3(Mid.X, Mid.Y, Mid.Z), new Vector3(Max.X, Max.Y, Max.Z))
  40. };
  41. }
  42. }
  43. public void AddItem(T Item, BoundingBox Point)
  44. {
  45. AddToTree(Tuple.Create(Item, Point), 8);
  46. }
  47. private void AddToTree(Tuple<T, BoundingBox> Item, int SubdivideThreshold)
  48. {
  49. lock (Lock)
  50. {
  51. if (!Bounds.Intersects(Item.Item2)) return;
  52. if (Children != null)
  53. {
  54. for (var i = 0; i < 8; ++i)
  55. Children[i].AddToTree(Item, SubdivideThreshold);
  56. }
  57. else if (Items.Count == SubdivideThreshold && (Bounds.Max.X - Bounds.Min.X) > 8)
  58. {
  59. Subdivide();
  60. for (var i = 0; i < Items.Count; ++i)
  61. for (var c = 0; c < 8; ++c)
  62. Children[c].AddToTree(Items[i], SubdivideThreshold);
  63. for (var c = 0; c < 8; ++c)
  64. Children[c].AddToTree(Item, SubdivideThreshold);
  65. Items.Clear();
  66. }
  67. else
  68. {
  69. Items.Add(Item);
  70. }
  71. }
  72. }
  73. public void RemoveItem(T Item, BoundingBox Point)
  74. {
  75. RemoveFromTree(Tuple.Create(Item, Point));
  76. }
  77. private void RemoveFromTree(Tuple<T, BoundingBox> Item)
  78. {
  79. lock (Lock)
  80. {
  81. if (!Bounds.Intersects(Item.Item2)) return;
  82. if (Children == null)
  83. Items.RemoveAll(t => Object.ReferenceEquals(t.Item1, Item.Item1));
  84. else
  85. foreach (var child in Children)
  86. child.RemoveFromTree(Item);
  87. }
  88. }
  89. public IEnumerable<T> EnumerateItems(BoundingBox SearchBounds)
  90. {
  91. lock (Lock)
  92. {
  93. if (SearchBounds.Intersects(Bounds))
  94. {
  95. if (Children == null)
  96. {
  97. for (var i = 0; i < Items.Count; ++i)
  98. if (Items[i].Item2.Intersects(SearchBounds))
  99. yield return Items[i].Item1;
  100. }
  101. else
  102. {
  103. for (var i = 0; i < 8; ++i)
  104. foreach (var item in Children[i].EnumerateItems(SearchBounds))
  105. yield return item;
  106. }
  107. }
  108. }
  109. }
  110. public void EnumerateItems(BoundingBox SearchBounds, HashSet<T> Into)
  111. {
  112. lock (Lock)
  113. {
  114. if (SearchBounds.Intersects(Bounds))
  115. {
  116. if (Children == null)
  117. {
  118. for (var i = 0; i < Items.Count; ++i)
  119. if (Items[i].Item2.Intersects(SearchBounds))
  120. Into.Add(Items[i].Item1);
  121. }
  122. else
  123. {
  124. for (var i = 0; i < 8; ++i)
  125. Children[i].EnumerateItems(SearchBounds, Into);
  126. }
  127. }
  128. }
  129. }
  130. public IEnumerable<T> EnumerateItems(BoundingFrustum SearchBounds)
  131. {
  132. lock (Lock)
  133. {
  134. if (!SearchBounds.Intersects(Bounds)) yield break;
  135. if (Children == null)
  136. {
  137. foreach (var t in Items.Where(t => t.Item2.Intersects(SearchBounds)))
  138. yield return t.Item1;
  139. }
  140. else
  141. {
  142. for (var i = 0; i < 8; ++i)
  143. foreach (var item in Children[i].EnumerateItems(SearchBounds))
  144. yield return item;
  145. }
  146. }
  147. }
  148. }
  149. }