NaiveOctTree.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. //#define USEBIN
  2. using System;
  3. using System.Collections.Generic;
  4. using Microsoft.Xna.Framework;
  5. namespace ABTest.Oct
  6. {
  7. public class NaiveOctTreeNode<T>
  8. {
  9. public BoundingBox Bounds;
  10. public NaiveOctTreeNode<T>[] Children;
  11. public List<Tuple<T, Vector3>> Items = new List<Tuple<T, Vector3>>(8);
  12. public Vector3 Mid;
  13. public NaiveOctTreeNode(Vector3 Min, Vector3 Max)
  14. {
  15. this.Bounds = new BoundingBox(Min, Max);
  16. Mid = (Min + Max) / 2.0f;
  17. }
  18. private void Subdivide()
  19. {
  20. var Min = Bounds.Min;
  21. var Max = Bounds.Max;
  22. Children = new NaiveOctTreeNode<T>[8]
  23. {
  24. /*000*/ new NaiveOctTreeNode<T>(new Vector3(Min.X, Min.Y, Min.Z), new Vector3(Mid.X, Mid.Y, Mid.Z)),
  25. /*001*/ new NaiveOctTreeNode<T>(new Vector3(Mid.X, Min.Y, Min.Z), new Vector3(Max.X, Mid.Y, Mid.Z)),
  26. /*010*/ new NaiveOctTreeNode<T>(new Vector3(Min.X, Mid.Y, Min.Z), new Vector3(Mid.X, Max.Y, Mid.Z)),
  27. /*011*/ new NaiveOctTreeNode<T>(new Vector3(Mid.X, Mid.Y, Min.Z), new Vector3(Max.X, Max.Y, Mid.Z)),
  28. /*100*/ new NaiveOctTreeNode<T>(new Vector3(Min.X, Min.Y, Mid.Z), new Vector3(Mid.X, Mid.Y, Max.Z)),
  29. /*101*/ new NaiveOctTreeNode<T>(new Vector3(Mid.X, Min.Y, Mid.Z), new Vector3(Max.X, Mid.Y, Max.Z)),
  30. /*110*/ new NaiveOctTreeNode<T>(new Vector3(Min.X, Mid.Y, Mid.Z), new Vector3(Mid.X, Max.Y, Max.Z)),
  31. /*111*/ new NaiveOctTreeNode<T>(new Vector3(Mid.X, Mid.Y, Mid.Z), new Vector3(Max.X, Max.Y, Max.Z))
  32. };
  33. }
  34. #if USEBIN
  35. private int Bin(Vector3 P)
  36. {
  37. var x = (P.X < Mid.X) ? 0 : 1;
  38. var y = (P.Y < Mid.Y) ? 0 : 2;
  39. var z = (P.Z < Mid.Z) ? 0 : 4;
  40. return x + y + z;
  41. }
  42. #endif
  43. public void AddItem(T Item, Vector3 Point)
  44. {
  45. if (Bounds.Contains(Point) != ContainmentType.Disjoint)
  46. AddToTree(Tuple.Create(Item, Point), 8);
  47. }
  48. private void AddToTree(Tuple<T, Vector3> Item, int SubdivideThreshold)
  49. {
  50. #if USEBIN == false
  51. // This is not needed for the Bin version as Bin keeps us in the right spot.
  52. if (Bounds.Contains(Item.Item2) == ContainmentType.Disjoint) return;
  53. #endif
  54. if (Children != null)
  55. {
  56. #if USEBIN
  57. Children[Bin(Item.Item2)].AddToTree(Item, SubdivideThreshold);
  58. #else
  59. for (var i = 0; i < 8; ++i)
  60. Children[i].AddToTree(Item, SubdivideThreshold);
  61. #endif
  62. }
  63. else if (Items.Count == SubdivideThreshold && (Bounds.Max.X - Bounds.Min.X) > 4)
  64. {
  65. Subdivide();
  66. #if USEBIN
  67. for (var i = 0; i < Items.Count; ++i)
  68. Children[Bin(Items[i].Item2)].AddToTree(Items[i], SubdivideThreshold);
  69. Children[Bin(Item.Item2)].AddToTree(Item, SubdivideThreshold);
  70. #else
  71. for (var i = 0; i < Items.Count; ++i)
  72. for (var c = 0; c < 8; ++c)
  73. Children[c].AddToTree(Items[i], SubdivideThreshold);
  74. for (var c = 0; c < 8; ++c)
  75. Children[c].AddToTree(Item, SubdivideThreshold);
  76. #endif
  77. }
  78. else
  79. {
  80. Items.Add(Item);
  81. }
  82. }
  83. public void FindItems(BoundingBox SearchBounds, HashSet<T> results)
  84. {
  85. ContainmentType c = SearchBounds.Contains(Bounds);
  86. if (c == ContainmentType.Disjoint) return;
  87. if (c == ContainmentType.Intersects)
  88. FindItemsInBox(SearchBounds, results, c);
  89. else
  90. AddAllItems(SearchBounds, results);
  91. }
  92. private void FindItemsInBox(BoundingBox SearchBounds, HashSet<T> results, ContainmentType cType)
  93. {
  94. if (Children == null)
  95. {
  96. for (var i = 0; i < Items.Count; ++i)
  97. if (SearchBounds.Contains(Items[i].Item2) != ContainmentType.Disjoint)
  98. results.Add(Items[i].Item1);
  99. }
  100. else
  101. {
  102. for (var i = 0; i < 8; ++i)
  103. {
  104. ContainmentType c = SearchBounds.Contains(Children[i].Bounds);
  105. if (c == ContainmentType.Disjoint) continue;
  106. if (c == ContainmentType.Intersects)
  107. Children[i].FindItemsInBox(SearchBounds, results, c);
  108. else
  109. Children[i].AddAllItems(SearchBounds, results);
  110. }
  111. }
  112. }
  113. private void AddAllItems(BoundingBox SearchBounds, HashSet<T> results)
  114. {
  115. if (Children == null)
  116. {
  117. for (var i = 0; i < Items.Count; ++i)
  118. {
  119. results.Add(Items[i].Item1);
  120. }
  121. }
  122. else
  123. {
  124. for (var i = 0; i < 8; ++i)
  125. Children[i].AddAllItems(SearchBounds, results);
  126. }
  127. }
  128. }
  129. }