PageRenderTime 42ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/BEPUphysics/CollisionTests/Manifolds/BoxContactManifold.cs

#
C# | 238 lines | 160 code | 24 blank | 54 comment | 22 complexity | b5c90d38665a0ef953b389bb44b4c8f7 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, BSD-3-Clause, MPL-2.0-no-copyleft-exception, LGPL-2.1
  1. using System;
  2. using BEPUphysics.BroadPhaseEntries;
  3. using BEPUphysics.BroadPhaseEntries.MobileCollidables;
  4. using BEPUphysics.CollisionTests.CollisionAlgorithms;
  5. using BEPUutilities.ResourceManagement;
  6. using Microsoft.Xna.Framework;
  7. using BEPUutilities.DataStructures;
  8. using BEPUphysics.CollisionShapes.ConvexShapes;
  9. namespace BEPUphysics.CollisionTests.Manifolds
  10. {
  11. ///<summary>
  12. /// Manages persistent contact data between two boxes.
  13. ///</summary>
  14. public class BoxContactManifold : ContactManifold
  15. {
  16. protected ConvexCollidable<BoxShape> boxA, boxB;
  17. ///<summary>
  18. /// Gets the first collidable in the pair.
  19. ///</summary>
  20. public ConvexCollidable<BoxShape> CollidableA
  21. {
  22. get
  23. {
  24. return boxA;
  25. }
  26. }
  27. /// <summary>
  28. /// Gets the second collidable in the pair.
  29. /// </summary>
  30. public ConvexCollidable<BoxShape> CollidableB
  31. {
  32. get
  33. {
  34. return boxB;
  35. }
  36. }
  37. ///<summary>
  38. /// Constructs a new manifold.
  39. ///</summary>
  40. public BoxContactManifold()
  41. {
  42. contacts = new RawList<Contact>(4);
  43. unusedContacts = new UnsafeResourcePool<Contact>(4);
  44. contactIndicesToRemove = new RawList<int>(4);
  45. }
  46. #if ALLOWUNSAFE
  47. ///<summary>
  48. /// Updates the manifold.
  49. ///</summary>
  50. ///<param name="dt">Timestep duration.</param>
  51. public override void Update(float dt)
  52. {
  53. //Now, generate a contact between the two shapes.
  54. float distance;
  55. Vector3 axis;
  56. BoxContactDataCache manifold;
  57. if (BoxBoxCollider.AreBoxesColliding(boxA.Shape, boxB.Shape, ref boxA.worldTransform, ref boxB.worldTransform, out distance, out axis, out manifold))
  58. {
  59. unsafe
  60. {
  61. BoxContactData* manifoldPointer = &manifold.D1;
  62. Vector3.Negate(ref axis, out axis);
  63. var toRemove = new TinyList<int>();
  64. for (int i = 0; i < contacts.Count; i++)
  65. {
  66. bool found = false;
  67. for (int j = manifold.Count - 1; j >= 0; j--)
  68. {
  69. if (contacts.Elements[i].Id == manifoldPointer[j].Id)
  70. {
  71. found = true;
  72. //Update contact...
  73. contacts.Elements[i].Position = manifoldPointer[j].Position;
  74. contacts.Elements[i].PenetrationDepth = -manifoldPointer[j].Depth;
  75. contacts.Elements[i].Normal = axis;
  76. //Remove manifold entry
  77. manifold.RemoveAt(j);
  78. break;
  79. }
  80. }
  81. if (!found)
  82. {//No match found
  83. toRemove.Add(i);
  84. }
  85. }
  86. //toRemove is sorted by increasing index. Go backwards along it so that the indices are valid all the way through.
  87. for (int i = toRemove.Count - 1; i >= 0; i--)
  88. Remove(toRemove[i]);
  89. //Add new contacts.
  90. for (int i = 0; i < manifold.Count; i++)
  91. {
  92. var newContact = new ContactData
  93. {
  94. Position = manifoldPointer[i].Position,
  95. PenetrationDepth = -manifoldPointer[i].Depth,
  96. Normal = axis,
  97. Id = manifoldPointer[i].Id
  98. };
  99. Add(ref newContact);
  100. }
  101. }
  102. }
  103. else
  104. {
  105. //Not colliding, so get rid of it.
  106. for (int i = contacts.Count - 1; i >= 0; i--)
  107. {
  108. Remove(i);
  109. }
  110. }
  111. }
  112. #else
  113. public override void Update(float dt)
  114. {
  115. //Now, generate a contact between the two shapes.
  116. float distance;
  117. Vector3 axis;
  118. var manifold = new TinyStructList<BoxContactData>();
  119. if (BoxBoxCollider.AreBoxesColliding(boxA.Shape, boxB.Shape, ref boxA.worldTransform, ref boxB.worldTransform, out distance, out axis, out manifold))
  120. {
  121. Vector3.Negate(ref axis, out axis);
  122. TinyList<int> toRemove = new TinyList<int>();
  123. BoxContactData data;
  124. for (int i = 0; i < contacts.Count; i++)
  125. {
  126. bool found = false;
  127. for (int j = manifold.Count - 1; j >= 0; j--)
  128. {
  129. manifold.Get(j, out data);
  130. if (contacts.Elements[i].Id == data.Id)
  131. {
  132. found = true;
  133. //Update contact...
  134. contacts.Elements[i].Position = data.Position;
  135. contacts.Elements[i].PenetrationDepth = -data.Depth;
  136. contacts.Elements[i].Normal = axis;
  137. //Remove manifold entry
  138. manifold.RemoveAt(j);
  139. break;
  140. }
  141. }
  142. if (!found)
  143. {//No match found
  144. toRemove.Add(i);
  145. }
  146. }
  147. ////Go through the indices to remove.
  148. ////For each one, replace the removal index with a contact in the new manifold.
  149. //int removalIndex;
  150. //for (removalIndex = toRemove.count - 1; removalIndex >= 0 && manifold.count > 0; removalIndex--)
  151. //{
  152. // int indexToReplace = toRemove[removalIndex];
  153. // toRemove.RemoveAt(removalIndex);
  154. // manifold.Get(manifold.count - 1, out data);
  155. // //Update contact...
  156. // contacts.Elements[indexToReplace].Position = data.Position;
  157. // contacts.Elements[indexToReplace].PenetrationDepth = -data.Depth;
  158. // contacts.Elements[indexToReplace].Normal = axis;
  159. // contacts.Elements[indexToReplace].Id = data.Id;
  160. // //Remove manifold entry
  161. // manifold.RemoveAt(manifold.count - 1);
  162. //}
  163. //Alright, we ran out of contacts to replace (if, in fact, toRemove isn't empty now). Just remove the remainder.
  164. //toRemove is sorted by increasing index. Go backwards along it so that the indices are valid all the way through.
  165. for (int i = toRemove.Count - 1; i >= 0; i--)
  166. Remove(toRemove[i]);
  167. //Add new contacts.
  168. for (int i = 0; i < manifold.Count; i++)
  169. {
  170. manifold.Get(i, out data);
  171. ContactData newContact = new ContactData();
  172. newContact.Position = data.Position;
  173. newContact.PenetrationDepth = -data.Depth;
  174. newContact.Normal = axis;
  175. newContact.Id = data.Id;
  176. Add(ref newContact);
  177. }
  178. }
  179. else
  180. {
  181. //Not colliding, so get rid of it.
  182. for (int i = contacts.Count - 1; i >= 0; i--)
  183. {
  184. Remove(i);
  185. }
  186. }
  187. }
  188. #endif
  189. ///<summary>
  190. /// Initializes the manifold.
  191. ///</summary>
  192. ///<param name="newCollidableA">First collidable.</param>
  193. ///<param name="newCollidableB">Second collidable.</param>
  194. ///<exception cref="Exception">Thrown when the collidables being used are not of the proper type.</exception>
  195. public override void Initialize(Collidable newCollidableA, Collidable newCollidableB)
  196. {
  197. boxA = (ConvexCollidable<BoxShape>)newCollidableA;
  198. boxB = (ConvexCollidable<BoxShape>)newCollidableB;
  199. if (boxA == null || boxB == null)
  200. {
  201. throw new Exception("Inappropriate types used to initialize pair tester.");
  202. }
  203. }
  204. ///<summary>
  205. /// Cleans up the manifold.
  206. ///</summary>
  207. public override void CleanUp()
  208. {
  209. boxA = null;
  210. boxB = null;
  211. base.CleanUp();
  212. }
  213. }
  214. }