DynamicTreeBroadPhase.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  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. public int CompareTo(Pair other)
  35. {
  36. if (ProxyIdA < other.ProxyIdA)
  37. {
  38. return -1;
  39. }
  40. if (ProxyIdA == other.ProxyIdA)
  41. {
  42. if (ProxyIdB < other.ProxyIdB)
  43. {
  44. return -1;
  45. }
  46. if (ProxyIdB == other.ProxyIdB)
  47. {
  48. return 0;
  49. }
  50. }
  51. return 1;
  52. }
  53. }
  54. /// <summary>
  55. /// The broad-phase is used for computing pairs and performing volume queries and ray casts.
  56. /// This broad-phase does not persist pairs. Instead, this reports potentially new pairs.
  57. /// It is up to the client to consume the new pairs and to track subsequent overlap.
  58. /// </summary>
  59. public class DynamicTreeBroadPhase : IBroadPhase
  60. {
  61. private int[] _moveBuffer;
  62. private int _moveCapacity;
  63. private int _moveCount;
  64. private Pair[] _pairBuffer;
  65. private int _pairCapacity;
  66. private int _pairCount;
  67. private int _proxyCount;
  68. private Func<int, bool> _queryCallback;
  69. private int _queryProxyId;
  70. private DynamicTree<FixtureProxy> _tree = new DynamicTree<FixtureProxy>();
  71. public DynamicTreeBroadPhase()
  72. {
  73. _queryCallback = new Func<int, bool>(QueryCallback);
  74. _pairCapacity = 16;
  75. _pairBuffer = new Pair[_pairCapacity];
  76. _moveCapacity = 16;
  77. _moveBuffer = new int[_moveCapacity];
  78. }
  79. /// <summary>
  80. /// Get the number of proxies.
  81. /// </summary>
  82. /// <value>The proxy count.</value>
  83. public int ProxyCount
  84. {
  85. get { return _proxyCount; }
  86. }
  87. /// <summary>
  88. /// Create a proxy with an initial AABB. Pairs are not reported until
  89. /// UpdatePairs is called.
  90. /// </summary>
  91. /// <param name="aabb">The aabb.</param>
  92. /// <param name="proxy">The user data.</param>
  93. /// <returns></returns>
  94. public int AddProxy(ref FixtureProxy proxy)
  95. {
  96. int proxyId = _tree.AddProxy(ref proxy.AABB, proxy);
  97. ++_proxyCount;
  98. BufferMove(proxyId);
  99. return proxyId;
  100. }
  101. /// <summary>
  102. /// Destroy a proxy. It is up to the client to remove any pairs.
  103. /// </summary>
  104. /// <param name="proxyId">The proxy id.</param>
  105. public void RemoveProxy(int proxyId)
  106. {
  107. UnBufferMove(proxyId);
  108. --_proxyCount;
  109. _tree.RemoveProxy(proxyId);
  110. }
  111. public void MoveProxy(int proxyId, ref AABB aabb, Vector2 displacement)
  112. {
  113. bool buffer = _tree.MoveProxy(proxyId, ref aabb, displacement);
  114. if (buffer)
  115. {
  116. BufferMove(proxyId);
  117. }
  118. }
  119. /// <summary>
  120. /// Get the AABB for a proxy.
  121. /// </summary>
  122. /// <param name="proxyId">The proxy id.</param>
  123. /// <param name="aabb">The aabb.</param>
  124. public void GetFatAABB(int proxyId, out AABB aabb)
  125. {
  126. _tree.GetFatAABB(proxyId, out aabb);
  127. }
  128. /// <summary>
  129. /// Get user data from a proxy. Returns null if the id is invalid.
  130. /// </summary>
  131. /// <param name="proxyId">The proxy id.</param>
  132. /// <returns></returns>
  133. public FixtureProxy GetProxy(int proxyId)
  134. {
  135. return _tree.GetUserData(proxyId);
  136. }
  137. /// <summary>
  138. /// Test overlap of fat AABBs.
  139. /// </summary>
  140. /// <param name="proxyIdA">The proxy id A.</param>
  141. /// <param name="proxyIdB">The proxy id B.</param>
  142. /// <returns></returns>
  143. public bool TestOverlap(int proxyIdA, int proxyIdB)
  144. {
  145. AABB aabbA, aabbB;
  146. _tree.GetFatAABB(proxyIdA, out aabbA);
  147. _tree.GetFatAABB(proxyIdB, out aabbB);
  148. return AABB.TestOverlap(ref aabbA, ref aabbB);
  149. }
  150. /// <summary>
  151. /// Update the pairs. This results in pair callbacks. This can only add pairs.
  152. /// </summary>
  153. /// <param name="callback">The callback.</param>
  154. public void UpdatePairs(BroadphaseDelegate callback)
  155. {
  156. // Reset pair buffer
  157. _pairCount = 0;
  158. // Perform tree queries for all moving proxies.
  159. for (int j = 0; j < _moveCount; ++j)
  160. {
  161. _queryProxyId = _moveBuffer[j];
  162. if (_queryProxyId == -1)
  163. {
  164. continue;
  165. }
  166. // We have to query the tree with the fat AABB so that
  167. // we don't fail to create a pair that may touch later.
  168. AABB fatAABB;
  169. _tree.GetFatAABB(_queryProxyId, out fatAABB);
  170. // Query tree, create pairs and add them pair buffer.
  171. _tree.Query(_queryCallback, ref fatAABB);
  172. }
  173. // Reset move buffer
  174. _moveCount = 0;
  175. // Sort the pair buffer to expose duplicates.
  176. Array.Sort(_pairBuffer, 0, _pairCount);
  177. // Send the pairs back to the client.
  178. int i = 0;
  179. while (i < _pairCount)
  180. {
  181. Pair primaryPair = _pairBuffer[i];
  182. FixtureProxy userDataA = _tree.GetUserData(primaryPair.ProxyIdA);
  183. FixtureProxy userDataB = _tree.GetUserData(primaryPair.ProxyIdB);
  184. callback(ref userDataA, ref userDataB);
  185. ++i;
  186. // Skip any duplicate pairs.
  187. while (i < _pairCount)
  188. {
  189. Pair pair = _pairBuffer[i];
  190. if (pair.ProxyIdA != primaryPair.ProxyIdA || pair.ProxyIdB != primaryPair.ProxyIdB)
  191. {
  192. break;
  193. }
  194. ++i;
  195. }
  196. }
  197. // Try to keep the tree balanced.
  198. _tree.Rebalance(4);
  199. }
  200. /// <summary>
  201. /// Query an AABB for overlapping proxies. The callback class
  202. /// is called for each proxy that overlaps the supplied AABB.
  203. /// </summary>
  204. /// <param name="callback">The callback.</param>
  205. /// <param name="aabb">The aabb.</param>
  206. public void Query(Func<int, bool> callback, ref AABB aabb)
  207. {
  208. _tree.Query(callback, ref aabb);
  209. }
  210. /// <summary>
  211. /// Ray-cast against the proxies in the tree. This relies on the callback
  212. /// to perform a exact ray-cast in the case were the proxy contains a shape.
  213. /// The callback also performs the any collision filtering. This has performance
  214. /// roughly equal to k * log(n), where k is the number of collisions and n is the
  215. /// number of proxies in the tree.
  216. /// </summary>
  217. /// <param name="callback">A callback class that is called for each proxy that is hit by the ray.</param>
  218. /// <param name="input">The ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).</param>
  219. public void RayCast(Func<RayCastInput, int, float> callback, ref RayCastInput input)
  220. {
  221. _tree.RayCast(callback, ref input);
  222. }
  223. public void TouchProxy(int proxyId)
  224. {
  225. BufferMove(proxyId);
  226. }
  227. /// <summary>
  228. /// Compute the height of the embedded tree.
  229. /// </summary>
  230. /// <returns></returns>
  231. public int ComputeHeight()
  232. {
  233. return _tree.ComputeHeight();
  234. }
  235. private void BufferMove(int proxyId)
  236. {
  237. if (_moveCount == _moveCapacity)
  238. {
  239. int[] oldBuffer = _moveBuffer;
  240. _moveCapacity *= 2;
  241. _moveBuffer = new int[_moveCapacity];
  242. Array.Copy(oldBuffer, _moveBuffer, _moveCount);
  243. }
  244. _moveBuffer[_moveCount] = proxyId;
  245. ++_moveCount;
  246. }
  247. private void UnBufferMove(int proxyId)
  248. {
  249. for (int i = 0; i < _moveCount; ++i)
  250. {
  251. if (_moveBuffer[i] == proxyId)
  252. {
  253. _moveBuffer[i] = -1;
  254. return;
  255. }
  256. }
  257. }
  258. private bool QueryCallback(int proxyId)
  259. {
  260. // A proxy cannot form a pair with itself.
  261. if (proxyId == _queryProxyId)
  262. {
  263. return true;
  264. }
  265. // Grow the pair buffer as needed.
  266. if (_pairCount == _pairCapacity)
  267. {
  268. Pair[] oldBuffer = _pairBuffer;
  269. _pairCapacity *= 2;
  270. _pairBuffer = new Pair[_pairCapacity];
  271. Array.Copy(oldBuffer, _pairBuffer, _pairCount);
  272. }
  273. _pairBuffer[_pairCount].ProxyIdA = Math.Min(proxyId, _queryProxyId);
  274. _pairBuffer[_pairCount].ProxyIdB = Math.Max(proxyId, _queryProxyId);
  275. ++_pairCount;
  276. return true;
  277. }
  278. }
  279. }