2
0

IntegerOctTree.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  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 ABTest.SpacialHash;
  8. using System.Diagnostics;
  9. namespace ABTest.IntegerOct
  10. {
  11. public class BoundingBox
  12. {
  13. public Point3 Min;
  14. public Point3 Max;
  15. public int Width { get { return Max.X - Min.X; } }
  16. public int Height { get { return Max.Y - Min.Y; } }
  17. public int Depth { get { return Max.Z - Min.Z; } }
  18. public BoundingBox(Point3 Min, Point3 Max)
  19. {
  20. this.Min = Min;
  21. this.Max = Max;
  22. }
  23. public BoundingBox(Microsoft.Xna.Framework.BoundingBox Box)
  24. {
  25. this.Min = new Point3((int)Math.Floor(Box.Min.X), (int)Math.Floor(Box.Min.Y), (int)Math.Floor(Box.Min.Z));
  26. this.Max = new Point3((int)Math.Ceiling(Box.Max.X), (int)Math.Ceiling(Box.Max.Y), (int)Math.Ceiling(Box.Max.Z));
  27. }
  28. /// <summary>
  29. /// Inclusive at both boundaries
  30. /// </summary>
  31. /// <param name="P"></param>
  32. /// <returns></returns>
  33. public bool Contains(Point3 P)
  34. {
  35. return P.X >= Min.X && P.X <= Max.X &&
  36. P.Y >= Min.Y && P.Y <= Max.Y &&
  37. P.Z >= Min.Z && P.Z <= Max.Z;
  38. }
  39. public bool Intersects(BoundingBox Other)
  40. {
  41. if (Min.X > Other.Max.X || Max.X < Other.Min.X) return false;
  42. if (Min.Y > Other.Max.Y || Max.Y < Other.Min.Y) return false;
  43. if (Min.Z > Other.Max.Z || Max.Z < Other.Min.Z) return false;
  44. return true;
  45. }
  46. }
  47. public class IntegerOctTreeNode<T>
  48. {
  49. public BoundingBox Bounds;
  50. public IntegerOctTreeNode<T>[] Children;
  51. public List<Tuple<T, Point3>> Items = new List<Tuple<T, Point3>>();
  52. private Point3 Mid;
  53. public IntegerOctTreeNode(Point3 Min, Point3 Max)
  54. {
  55. Bounds = new BoundingBox(Min, Max);
  56. Bounds.Max.X = Bounds.Min.X + NextPowerOfTwo(Bounds.Width);
  57. Bounds.Max.Y = Bounds.Min.Y + NextPowerOfTwo(Bounds.Height);
  58. Bounds.Max.Z = Bounds.Min.Z + NextPowerOfTwo(Bounds.Depth);
  59. Mid = new Point3(Min.X + Bounds.Width / 2, Min.Y + Bounds.Height / 2, Min.Z + Bounds.Depth / 2);
  60. Debug.Assert(NextPowerOfTwo(Mid.X - Min.X) == (Mid.X - Min.X));
  61. }
  62. private int NextPowerOfTwo(int N)
  63. {
  64. var r = 1;
  65. while (r < N)
  66. r <<= 1;
  67. return r;
  68. }
  69. private void Subdivide()
  70. {
  71. var Min = Bounds.Min;
  72. var Max = Bounds.Max;
  73. Children = new IntegerOctTreeNode<T>[8]
  74. {
  75. /*000*/ new IntegerOctTreeNode<T>(new Point3(Min.X, Min.Y, Min.Z), new Point3(Mid.X, Mid.Y, Mid.Z)),
  76. /*001*/ new IntegerOctTreeNode<T>(new Point3(Mid.X, Min.Y, Min.Z), new Point3(Max.X, Mid.Y, Mid.Z)),
  77. /*010*/ new IntegerOctTreeNode<T>(new Point3(Min.X, Mid.Y, Min.Z), new Point3(Mid.X, Max.Y, Mid.Z)),
  78. /*011*/ new IntegerOctTreeNode<T>(new Point3(Mid.X, Mid.Y, Min.Z), new Point3(Max.X, Max.Y, Mid.Z)),
  79. /*100*/ new IntegerOctTreeNode<T>(new Point3(Min.X, Min.Y, Mid.Z), new Point3(Mid.X, Mid.Y, Max.Z)),
  80. /*101*/ new IntegerOctTreeNode<T>(new Point3(Mid.X, Min.Y, Mid.Z), new Point3(Max.X, Mid.Y, Max.Z)),
  81. /*110*/ new IntegerOctTreeNode<T>(new Point3(Min.X, Mid.Y, Mid.Z), new Point3(Mid.X, Max.Y, Max.Z)),
  82. /*111*/ new IntegerOctTreeNode<T>(new Point3(Mid.X, Mid.Y, Mid.Z), new Point3(Max.X, Max.Y, Max.Z))
  83. };
  84. }
  85. private int Bin(Point3 P)
  86. {
  87. var x = (P.X < Mid.X) ? 0 : 1;
  88. var y = (P.Y < Mid.Y) ? 0 : 2;
  89. var z = (P.Z < Mid.Z) ? 0 : 4;
  90. return x + y + z;
  91. }
  92. public void AddItem(T Item, Point3 Point)
  93. {
  94. AddToTree(Tuple.Create(Item, Point), 8);
  95. }
  96. private void AddToTree(Tuple<T, Point3> Item, int SubdivideThreshold)
  97. {
  98. if (!Bounds.Contains(Item.Item2)) return;
  99. if (Children != null)
  100. {
  101. Children[Bin(Item.Item2)].AddToTree(Item, SubdivideThreshold);
  102. }
  103. else if (Items.Count == SubdivideThreshold && Bounds.Width > 8)
  104. {
  105. Subdivide();
  106. for (var i = 0; i < Items.Count; ++i)
  107. Children[Bin(Items[i].Item2)].AddToTree(Items[i], SubdivideThreshold);
  108. Children[Bin(Item.Item2)].AddToTree(Item, SubdivideThreshold);
  109. Items.Clear();
  110. }
  111. else
  112. {
  113. Items.Add(Item);
  114. }
  115. }
  116. public void FindItemsInBox(BoundingBox SearchBounds, HashSet<T> results)
  117. {
  118. if (SearchBounds.Intersects(Bounds))
  119. {
  120. if (Children == null)
  121. {
  122. for (var i = 0; i < Items.Count; ++i)
  123. {
  124. var P = Items[i].Item2;
  125. if (P.X >= SearchBounds.Min.X && P.X <= SearchBounds.Max.X &&
  126. P.Y >= SearchBounds.Min.Y && P.Y <= SearchBounds.Max.Y &&
  127. P.Z >= SearchBounds.Min.Z && P.Z <= SearchBounds.Max.Z)
  128. results.Add(Items[i].Item1);
  129. }
  130. }
  131. else
  132. {
  133. for (var i = 0; i < 8; ++i)
  134. Children[i].FindItemsInBox(SearchBounds, results);
  135. }
  136. }
  137. }
  138. }
  139. }