DynamicTreeBroadPhase.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. /*
  2. * Farseer Physics Engine based on Box2D.XNA port:
  3. * Copyright (c) 2010 Ian Qvist
  4. *
  5. * Box2D.XNA port of Box2D:
  6. * Copyright (c) 2009 Brandon Furtwangler, Nathan Furtwangler
  7. *
  8. * Original source Box2D:
  9. * Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
  10. *
  11. * This software is provided 'as-is', without any express or implied
  12. * warranty. In no event will the authors be held liable for any damages
  13. * arising from the use of this software.
  14. * Permission is granted to anyone to use this software for any purpose,
  15. * including commercial applications, and to alter it and redistribute it
  16. * freely, subject to the following restrictions:
  17. * 1. The origin of this software must not be misrepresented; you must not
  18. * claim that you wrote the original software. If you use this software
  19. * in a product, an acknowledgment in the product documentation would be
  20. * appreciated but is not required.
  21. * 2. Altered source versions must be plainly marked as such, and must not be
  22. * misrepresented as being the original software.
  23. * 3. This notice may not be removed or altered from any source distribution.
  24. */
  25. using System;
  26. using FarseerPhysics.Dynamics;
  27. using Microsoft.Xna.Framework;
  28. namespace FarseerPhysics.Collision
  29. {
  30. internal struct Pair : IComparable<Pair>
  31. {
  32. public int ProxyIdA;
  33. public int ProxyIdB;
  34. #region IComparable<Pair> Members
  35. public int CompareTo(Pair other)
  36. {
  37. if (ProxyIdA < other.ProxyIdA)
  38. {
  39. return -1;
  40. }
  41. if (ProxyIdA == other.ProxyIdA)
  42. {
  43. if (ProxyIdB < other.ProxyIdB)
  44. {
  45. return -1;
  46. }
  47. if (ProxyIdB == other.ProxyIdB)
  48. {
  49. return 0;
  50. }
  51. }
  52. return 1;
  53. }
  54. #endregion
  55. }
  56. /// <summary>
  57. /// The broad-phase is used for computing pairs and performing volume queries and ray casts.
  58. /// This broad-phase does not persist pairs. Instead, this reports potentially new pairs.
  59. /// It is up to the client to consume the new pairs and to track subsequent overlap.
  60. /// </summary>
  61. public class DynamicTreeBroadPhase : IBroadPhase
  62. {
  63. private int[] _moveBuffer;
  64. private int _moveCapacity;
  65. private int _moveCount;
  66. private Pair[] _pairBuffer;
  67. private int _pairCapacity;
  68. private int _pairCount;
  69. private int _proxyCount;
  70. private Func<int, bool> _queryCallback;
  71. private int _queryProxyId;
  72. private DynamicTree<FixtureProxy> _tree = new DynamicTree<FixtureProxy>();
  73. public DynamicTreeBroadPhase()
  74. {
  75. _queryCallback = new Func<int, bool>(QueryCallback);
  76. _pairCapacity = 16;
  77. _pairBuffer = new Pair[_pairCapacity];
  78. _moveCapacity = 16;
  79. _moveBuffer = new int[_moveCapacity];
  80. }
  81. #region IBroadPhase Members
  82. /// <summary>
  83. /// Get the number of proxies.
  84. /// </summary>
  85. /// <value>The proxy count.</value>
  86. public int ProxyCount
  87. {
  88. get { return _proxyCount; }
  89. }
  90. /// <summary>
  91. /// Create a proxy with an initial AABB. Pairs are not reported until
  92. /// UpdatePairs is called.
  93. /// </summary>
  94. /// <param name="aabb">The aabb.</param>
  95. /// <param name="proxy">The user data.</param>
  96. /// <returns></returns>
  97. public int AddProxy(ref FixtureProxy proxy)
  98. {
  99. int proxyId = _tree.AddProxy(ref proxy.AABB, proxy);
  100. ++_proxyCount;
  101. BufferMove(proxyId);
  102. return proxyId;
  103. }
  104. /// <summary>
  105. /// Destroy a proxy. It is up to the client to remove any pairs.
  106. /// </summary>
  107. /// <param name="proxyId">The proxy id.</param>
  108. public void RemoveProxy(int proxyId)
  109. {
  110. UnBufferMove(proxyId);
  111. --_proxyCount;
  112. _tree.RemoveProxy(proxyId);
  113. }
  114. public void MoveProxy(int proxyId, ref AABB aabb, Vector2 displacement)
  115. {
  116. bool buffer = _tree.MoveProxy(proxyId, ref aabb, displacement);
  117. if (buffer)
  118. {
  119. BufferMove(proxyId);
  120. }
  121. }
  122. /// <summary>
  123. /// Get the AABB for a proxy.
  124. /// </summary>
  125. /// <param name="proxyId">The proxy id.</param>
  126. /// <param name="aabb">The aabb.</param>
  127. public void GetFatAABB(int proxyId, out AABB aabb)
  128. {
  129. _tree.GetFatAABB(proxyId, out aabb);
  130. }
  131. /// <summary>
  132. /// Get user data from a proxy. Returns null if the id is invalid.
  133. /// </summary>
  134. /// <param name="proxyId">The proxy id.</param>
  135. /// <returns></returns>
  136. public FixtureProxy GetProxy(int proxyId)
  137. {
  138. return _tree.GetUserData(proxyId);
  139. }
  140. /// <summary>
  141. /// Test overlap of fat AABBs.
  142. /// </summary>
  143. /// <param name="proxyIdA">The proxy id A.</param>
  144. /// <param name="proxyIdB">The proxy id B.</param>
  145. /// <returns></returns>
  146. public bool TestOverlap(int proxyIdA, int proxyIdB)
  147. {
  148. AABB aabbA, aabbB;
  149. _tree.GetFatAABB(proxyIdA, out aabbA);
  150. _tree.GetFatAABB(proxyIdB, out aabbB);
  151. return AABB.TestOverlap(ref aabbA, ref aabbB);
  152. }
  153. /// <summary>
  154. /// Update the pairs. This results in pair callbacks. This can only add pairs.
  155. /// </summary>
  156. /// <param name="callback">The callback.</param>
  157. public void UpdatePairs(BroadphaseDelegate callback)
  158. {
  159. // Reset pair buffer
  160. _pairCount = 0;
  161. // Perform tree queries for all moving proxies.
  162. for (int j = 0; j < _moveCount; ++j)
  163. {
  164. _queryProxyId = _moveBuffer[j];
  165. if (_queryProxyId == -1)
  166. {
  167. continue;
  168. }
  169. // We have to query the tree with the fat AABB so that
  170. // we don't fail to create a pair that may touch later.
  171. AABB fatAABB;
  172. _tree.GetFatAABB(_queryProxyId, out fatAABB);
  173. // Query tree, create pairs and add them pair buffer.
  174. _tree.Query(_queryCallback, ref fatAABB);
  175. }
  176. // Reset move buffer
  177. _moveCount = 0;
  178. // Sort the pair buffer to expose duplicates.
  179. Array.Sort(_pairBuffer, 0, _pairCount);
  180. // Send the pairs back to the client.
  181. int i = 0;
  182. while (i < _pairCount)
  183. {
  184. Pair primaryPair = _pairBuffer[i];
  185. FixtureProxy userDataA = _tree.GetUserData(primaryPair.ProxyIdA);
  186. FixtureProxy userDataB = _tree.GetUserData(primaryPair.ProxyIdB);
  187. callback(ref userDataA, ref userDataB);
  188. ++i;
  189. // Skip any duplicate pairs.
  190. while (i < _pairCount)
  191. {
  192. Pair pair = _pairBuffer[i];
  193. if (pair.ProxyIdA != primaryPair.ProxyIdA || pair.ProxyIdB != primaryPair.ProxyIdB)
  194. {
  195. break;
  196. }
  197. ++i;
  198. }
  199. }
  200. // Try to keep the tree balanced.
  201. _tree.Rebalance(4);
  202. }
  203. /// <summary>
  204. /// Query an AABB for overlapping proxies. The callback class
  205. /// is called for each proxy that overlaps the supplied AABB.
  206. /// </summary>
  207. /// <param name="callback">The callback.</param>
  208. /// <param name="aabb">The aabb.</param>
  209. public void Query(Func<int, bool> callback, ref AABB aabb)
  210. {
  211. _tree.Query(callback, ref aabb);
  212. }
  213. /// <summary>
  214. /// Ray-cast against the proxies in the tree. This relies on the callback
  215. /// to perform a exact ray-cast in the case were the proxy contains a shape.
  216. /// The callback also performs the any collision filtering. This has performance
  217. /// roughly equal to k * log(n), where k is the number of collisions and n is the
  218. /// number of proxies in the tree.
  219. /// </summary>
  220. /// <param name="callback">A callback class that is called for each proxy that is hit by the ray.</param>
  221. /// <param name="input">The ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).</param>
  222. public void RayCast(Func<RayCastInput, int, float> callback, ref RayCastInput input)
  223. {
  224. _tree.RayCast(callback, ref input);
  225. }
  226. public void TouchProxy(int proxyId)
  227. {
  228. BufferMove(proxyId);
  229. }
  230. #endregion
  231. /// <summary>
  232. /// Compute the height of the embedded tree.
  233. /// </summary>
  234. /// <returns></returns>
  235. public int ComputeHeight()
  236. {
  237. return _tree.ComputeHeight();
  238. }
  239. private void BufferMove(int proxyId)
  240. {
  241. if (_moveCount == _moveCapacity)
  242. {
  243. int[] oldBuffer = _moveBuffer;
  244. _moveCapacity *= 2;
  245. _moveBuffer = new int[_moveCapacity];
  246. Array.Copy(oldBuffer, _moveBuffer, _moveCount);
  247. }
  248. _moveBuffer[_moveCount] = proxyId;
  249. ++_moveCount;
  250. }
  251. private void UnBufferMove(int proxyId)
  252. {
  253. for (int i = 0; i < _moveCount; ++i)
  254. {
  255. if (_moveBuffer[i] == proxyId)
  256. {
  257. _moveBuffer[i] = -1;
  258. return;
  259. }
  260. }
  261. }
  262. private bool QueryCallback(int proxyId)
  263. {
  264. // A proxy cannot form a pair with itself.
  265. if (proxyId == _queryProxyId)
  266. {
  267. return true;
  268. }
  269. // Grow the pair buffer as needed.
  270. if (_pairCount == _pairCapacity)
  271. {
  272. Pair[] oldBuffer = _pairBuffer;
  273. _pairCapacity *= 2;
  274. _pairBuffer = new Pair[_pairCapacity];
  275. Array.Copy(oldBuffer, _pairBuffer, _pairCount);
  276. }
  277. _pairBuffer[_pairCount].ProxyIdA = Math.Min(proxyId, _queryProxyId);
  278. _pairBuffer[_pairCount].ProxyIdB = Math.Max(proxyId, _queryProxyId);
  279. ++_pairCount;
  280. return true;
  281. }
  282. }
  283. }