QuadTreeBroadPhase.cs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. using System;
  2. using System.Collections.Generic;
  3. using FarseerPhysics;
  4. using FarseerPhysics.Collision;
  5. using FarseerPhysics.Dynamics;
  6. using Microsoft.Xna.Framework;
  7. public class QuadTreeBroadPhase : IBroadPhase
  8. {
  9. private const int TreeUpdateThresh = 10000;
  10. private int _currID;
  11. private Dictionary<int, Element<FixtureProxy>> _idRegister;
  12. private List<Element<FixtureProxy>> _moveBuffer;
  13. private List<Pair> _pairBuffer;
  14. private QuadTree<FixtureProxy> _quadTree;
  15. private int _treeMoveNum;
  16. /// <summary>
  17. /// Creates a new quad tree broadphase with the specified span.
  18. /// </summary>
  19. /// <param name="span">the maximum span of the tree (world size)</param>
  20. public QuadTreeBroadPhase(AABB span)
  21. {
  22. _quadTree = new QuadTree<FixtureProxy>(span, 5, 10);
  23. _idRegister = new Dictionary<int, Element<FixtureProxy>>();
  24. _moveBuffer = new List<Element<FixtureProxy>>();
  25. _pairBuffer = new List<Pair>();
  26. }
  27. #region IBroadPhase Members
  28. ///<summary>
  29. /// The number of proxies
  30. ///</summary>
  31. public int ProxyCount
  32. {
  33. get { return _idRegister.Count; }
  34. }
  35. public void GetFatAABB(int proxyID, out AABB aabb)
  36. {
  37. if (_idRegister.ContainsKey(proxyID))
  38. aabb = _idRegister[proxyID].Span;
  39. else
  40. throw new KeyNotFoundException("proxyID not found in register");
  41. }
  42. public void UpdatePairs(BroadphaseDelegate callback)
  43. {
  44. _pairBuffer.Clear();
  45. foreach (Element<FixtureProxy> qtnode in _moveBuffer)
  46. {
  47. // Query tree, create pairs and add them pair buffer.
  48. Query(proxyID => PairBufferQueryCallback(proxyID, qtnode.Value.ProxyId), ref qtnode.Span);
  49. }
  50. _moveBuffer.Clear();
  51. // Sort the pair buffer to expose duplicates.
  52. _pairBuffer.Sort();
  53. // Send the pairs back to the client.
  54. int i = 0;
  55. while (i < _pairBuffer.Count)
  56. {
  57. Pair primaryPair = _pairBuffer[i];
  58. FixtureProxy userDataA = GetProxy(primaryPair.ProxyIdA);
  59. FixtureProxy userDataB = GetProxy(primaryPair.ProxyIdB);
  60. callback(ref userDataA, ref userDataB);
  61. ++i;
  62. // Skip any duplicate pairs.
  63. while (i < _pairBuffer.Count && _pairBuffer[i].ProxyIdA == primaryPair.ProxyIdA &&
  64. _pairBuffer[i].ProxyIdB == primaryPair.ProxyIdB)
  65. ++i;
  66. }
  67. }
  68. /// <summary>
  69. /// Test overlap of fat AABBs.
  70. /// </summary>
  71. /// <param name="proxyIdA">The proxy id A.</param>
  72. /// <param name="proxyIdB">The proxy id B.</param>
  73. /// <returns></returns>
  74. public bool TestOverlap(int proxyIdA, int proxyIdB)
  75. {
  76. AABB aabb1;
  77. AABB aabb2;
  78. GetFatAABB(proxyIdA, out aabb1);
  79. GetFatAABB(proxyIdB, out aabb2);
  80. return AABB.TestOverlap(ref aabb1, ref aabb2);
  81. }
  82. public int AddProxy(ref FixtureProxy proxy)
  83. {
  84. int proxyID = _currID++;
  85. proxy.ProxyId = proxyID;
  86. AABB aabb = Fatten(ref proxy.AABB);
  87. Element<FixtureProxy> qtnode = new Element<FixtureProxy>(proxy, aabb);
  88. _idRegister.Add(proxyID, qtnode);
  89. _quadTree.AddNode(qtnode);
  90. return proxyID;
  91. }
  92. public void RemoveProxy(int proxyId)
  93. {
  94. if (_idRegister.ContainsKey(proxyId))
  95. {
  96. Element<FixtureProxy> qtnode = _idRegister[proxyId];
  97. UnbufferMove(qtnode);
  98. _idRegister.Remove(proxyId);
  99. _quadTree.RemoveNode(qtnode);
  100. }
  101. else
  102. throw new KeyNotFoundException("proxyID not found in register");
  103. }
  104. public void MoveProxy(int proxyId, ref AABB aabb, Vector2 displacement)
  105. {
  106. AABB fatAABB;
  107. GetFatAABB(proxyId, out fatAABB);
  108. //exit if movement is within fat aabb
  109. if (fatAABB.Contains(ref aabb))
  110. return;
  111. // Extend AABB.
  112. AABB b = aabb;
  113. Vector2 r = new Vector2(Settings.AABBExtension, Settings.AABBExtension);
  114. b.LowerBound = b.LowerBound - r;
  115. b.UpperBound = b.UpperBound + r;
  116. // Predict AABB displacement.
  117. Vector2 d = Settings.AABBMultiplier * displacement;
  118. if (d.X < 0.0f)
  119. b.LowerBound.X += d.X;
  120. else
  121. b.UpperBound.X += d.X;
  122. if (d.Y < 0.0f)
  123. b.LowerBound.Y += d.Y;
  124. else
  125. b.UpperBound.Y += d.Y;
  126. Element<FixtureProxy> qtnode = _idRegister[proxyId];
  127. qtnode.Value.AABB = b; //not neccesary for QTree, but might be accessed externally
  128. qtnode.Span = b;
  129. ReinsertNode(qtnode);
  130. BufferMove(qtnode);
  131. }
  132. public FixtureProxy GetProxy(int proxyId)
  133. {
  134. if (_idRegister.ContainsKey(proxyId))
  135. return _idRegister[proxyId].Value;
  136. else
  137. throw new KeyNotFoundException("proxyID not found in register");
  138. }
  139. public void TouchProxy(int proxyId)
  140. {
  141. if (_idRegister.ContainsKey(proxyId))
  142. BufferMove(_idRegister[proxyId]);
  143. else
  144. throw new KeyNotFoundException("proxyID not found in register");
  145. }
  146. public void Query(Func<int, bool> callback, ref AABB query)
  147. {
  148. _quadTree.QueryAABB(TransformPredicate(callback), ref query);
  149. }
  150. public void RayCast(Func<RayCastInput, int, float> callback, ref RayCastInput input)
  151. {
  152. _quadTree.RayCast(TransformRayCallback(callback), ref input);
  153. }
  154. #endregion
  155. private AABB Fatten(ref AABB aabb)
  156. {
  157. Vector2 r = new Vector2(Settings.AABBExtension, Settings.AABBExtension);
  158. return new AABB(aabb.LowerBound - r, aabb.UpperBound + r);
  159. }
  160. private Func<Element<FixtureProxy>, bool> TransformPredicate(Func<int, bool> idPredicate)
  161. {
  162. Func<Element<FixtureProxy>, bool> qtPred = qtnode => idPredicate(qtnode.Value.ProxyId);
  163. return qtPred;
  164. }
  165. private Func<RayCastInput, Element<FixtureProxy>, float> TransformRayCallback(
  166. Func<RayCastInput, int, float> callback)
  167. {
  168. Func<RayCastInput, Element<FixtureProxy>, float> newCallback =
  169. (input, qtnode) => callback(input, qtnode.Value.ProxyId);
  170. return newCallback;
  171. }
  172. private bool PairBufferQueryCallback(int proxyID, int baseID)
  173. {
  174. // A proxy cannot form a pair with itself.
  175. if (proxyID == baseID)
  176. return true;
  177. Pair p = new Pair();
  178. p.ProxyIdA = Math.Min(proxyID, baseID);
  179. p.ProxyIdB = Math.Max(proxyID, baseID);
  180. _pairBuffer.Add(p);
  181. return true;
  182. }
  183. private void ReconstructTree()
  184. {
  185. //this is faster than _quadTree.Reconstruct(), since the quadtree method runs a recusive query to find all nodes.
  186. _quadTree.Clear();
  187. foreach (Element<FixtureProxy> elem in _idRegister.Values)
  188. _quadTree.AddNode(elem);
  189. }
  190. private void ReinsertNode(Element<FixtureProxy> qtnode)
  191. {
  192. _quadTree.RemoveNode(qtnode);
  193. _quadTree.AddNode(qtnode);
  194. if (++_treeMoveNum > TreeUpdateThresh)
  195. {
  196. ReconstructTree();
  197. _treeMoveNum = 0;
  198. }
  199. }
  200. private void BufferMove(Element<FixtureProxy> proxy)
  201. {
  202. _moveBuffer.Add(proxy);
  203. }
  204. private void UnbufferMove(Element<FixtureProxy> proxy)
  205. {
  206. _moveBuffer.Remove(proxy);
  207. }
  208. }