Guest User

Untitled

a guest
Apr 24th, 2018
69
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.61 KB | None | 0 0
  1. sing Microsoft.Xna.Framework;
  2. using System.Collections.Generic;
  3.  
  4. namespace GJK_test
  5. {
  6.  
  7. public struct GJKCollisionInfo
  8. {
  9. public bool collided;
  10. public Vector2[] simplex;
  11. }
  12.  
  13. public struct Edge
  14. {
  15. public Vector2 normal;
  16. public int index;
  17. public double distance;
  18. }
  19. public struct GJKEPACollisonInfo
  20. {
  21. public Edge closest;
  22. public GJKCollisionInfo info;
  23.  
  24. public Vector2 GetPenetrationVector()
  25. {
  26. return closest.normal * (float)closest.distance;
  27. }
  28. }
  29. static public class GJK
  30. {
  31. static uint IndexOfFurthestPoint(Vector2[] vertices, Vector2 d)
  32. {
  33. uint index = 0;
  34. float maxProduct = Vector2.Dot(d, vertices[index]);
  35. for (uint i = 1; i < vertices.Length; i++)
  36. {
  37. float product = Vector2.Dot(d, vertices[i]); // may be negative
  38. if (product > maxProduct)
  39. {
  40. maxProduct = product;
  41. index = i;
  42. }
  43. }
  44. return index;
  45. }
  46.  
  47. public static Vector2 Support(Vector2[] vertices1, // first shape
  48. Vector2[] vertices2, // second shape
  49. Vector2 d)// direction
  50. {
  51.  
  52. // get furthest point of first body along an arbitrary direction
  53. uint i = IndexOfFurthestPoint(vertices1, d);
  54.  
  55. // get furthest point of second body along the opposite direction
  56. // note that this time direction is negated
  57. uint j = IndexOfFurthestPoint(vertices2, -d);
  58.  
  59. // return the Minkowski sum of two points to see if bodies 'overlap'
  60. // note that the second point-vector is negated, a + (-b) = c
  61. return Vector2.Add(vertices1[i], -vertices2[j]);
  62. }
  63.  
  64. static Vector2 AveragePoint(Vector2[] vertices)
  65. {
  66. Vector2 avg = Vector2.Zero;
  67. for (uint i = 0; i < vertices.Length; i++)
  68. {
  69. avg.X += vertices[i].X;
  70. avg.Y += vertices[i].Y;
  71. }
  72. avg.X /= vertices.Length;
  73. avg.Y /= vertices.Length;
  74. return avg;
  75. }
  76.  
  77. static Vector2 TripleProduct(Vector2 a, Vector2 b, Vector2 c)
  78. {
  79.  
  80. Vector2 r;
  81.  
  82. float ac = a.X * c.X + a.Y * c.Y; // perform a.dot(c)
  83. float bc = b.X * c.X + b.Y * c.Y; // perform b.dot(c)
  84.  
  85. // perform b * a.dot(c) - a * b.dot(c)
  86. r.X = b.X * ac - a.X * bc;
  87. r.Y = b.Y * ac - a.Y * bc;
  88. return r;
  89. }
  90.  
  91. static bool GJKCheckCollision(Vector2[] vertices1, Vector2[] vertices2, out int iter_count)
  92. {
  93. iter_count = 0;
  94. uint index = 0; // index of current vertex of simplex
  95. Vector2 a, b, c, d, ao, ab, ac, abperp, acperp;
  96. Vector2[] simplex = new Vector2[3];
  97.  
  98.  
  99. Vector2 position1 = AveragePoint(vertices1); // not a CoG but
  100. Vector2 position2 = AveragePoint(vertices2); // it's ok for GJK )
  101.  
  102. // initial direction from the center of 1st body to the center of 2nd body
  103. d = Vector2.Subtract(position1, position2);
  104.  
  105. // if initial direction is zero – set it to any arbitrary axis (we choose X)
  106. if ((d.X == 0) && (d.Y == 0)) d.X = 1.0f;
  107.  
  108. // set the first support as initial point of the new simplex
  109. a = simplex[0] = Support(vertices1, vertices2, d);
  110.  
  111. if (Vector2.Dot(a, d) <= 0)
  112. return false; // no collision
  113.  
  114. d = Vector2.Negate(a); // The next search direction is always towards the origin, so the next search direction is negate(a)
  115.  
  116. while (true)
  117. {
  118. iter_count++;
  119.  
  120. a = simplex[++index] = Support(vertices1, vertices2, d);
  121.  
  122. if (Vector2.Dot(a, d) <= 0)
  123. return false; // no collision
  124.  
  125. ao = Vector2.Negate(a); // from point A to Origin is just negative A
  126.  
  127. // simplex has 2 points (a line segment, not a triangle yet)
  128. if (index < 2)
  129. {
  130. b = simplex[0];
  131. ab = Vector2.Subtract(b, a); // from point A to B
  132. d = TripleProduct(ab, ao, ab); // normal to AB towards Origin
  133. if (d.LengthSquared() == 0)
  134. d = new Vector2(ab.Y, -ab.X);
  135. continue; // skip to next iteration
  136. }
  137.  
  138. b = simplex[1];
  139. c = simplex[0];
  140. ab = Vector2.Subtract(b, a); // from point A to B
  141. ac = Vector2.Subtract(c, a); // from point A to C
  142.  
  143. acperp = TripleProduct(ab, ac, ac);
  144.  
  145. if (Vector2.Dot(acperp, ao) >= 0)
  146. {
  147.  
  148. d = acperp; // new direction is normal to AC towards Origin
  149.  
  150. }
  151. else
  152. {
  153.  
  154. abperp = TripleProduct(ac, ab, ab);
  155.  
  156. if (Vector2.Dot(abperp, ao) < 0)
  157. return true; // collision
  158.  
  159. simplex[0] = simplex[1]; // swap first element (point C)
  160.  
  161. d = abperp; // new direction is normal to AB towards Origin
  162. }
  163.  
  164. simplex[1] = simplex[2]; // swap element in the middle (point B)
  165. --index;
  166. }
  167.  
  168. }
  169.  
  170. public static GJKCollisionInfo GJKCollisionCheckWithInfo(Vector2[] vertices1, Vector2[] vertices2, out int iter_count)
  171. {
  172. GJKCollisionInfo Result = new GJKCollisionInfo();
  173. iter_count = 0;
  174. uint index = 0; // index of current vertex of simplex
  175. Vector2 a, b, c, d, ao, ab, ac, abperp, acperp;
  176. Vector2[] simplex = new Vector2[3];
  177.  
  178.  
  179. Vector2 position1 = AveragePoint(vertices1); // not a CoG but
  180. Vector2 position2 = AveragePoint(vertices2); // it's ok for GJK )
  181.  
  182. // initial direction from the center of 1st body to the center of 2nd body
  183. d = Vector2.Subtract(position1, position2);
  184.  
  185. // if initial direction is zero – set it to any arbitrary axis (we choose X)
  186. if ((d.X == 0) && (d.Y == 0)) d.X = 1.0f;
  187.  
  188. // set the first support as initial point of the new simplex
  189. a = simplex[0] = Support(vertices1, vertices2, d);
  190.  
  191. if (Vector2.Dot(a, d) <= 0)
  192. {
  193. Result.collided = false;
  194. Result.simplex = simplex;
  195. return Result; // no collision
  196. }
  197. d = Vector2.Negate(a); // The next search direction is always towards the origin, so the next search direction is negate(a)
  198.  
  199. while (true)
  200. {
  201. iter_count++;
  202.  
  203. a = simplex[++index] = Support(vertices1, vertices2, d);
  204.  
  205. if (Vector2.Dot(a, d) <= 0)
  206. {
  207.  
  208. Result.collided = false;
  209. Result.simplex = simplex;
  210. break;
  211. }
  212. ao = Vector2.Negate(a); // from point A to Origin is just negative A
  213.  
  214. // simplex has 2 points (a line segment, not a triangle yet)
  215. if (index < 2)
  216. {
  217. b = simplex[0];
  218. ab = Vector2.Subtract(b, a); // from point A to B
  219. d = TripleProduct(ab, ao, ab); // normal to AB towards Origin
  220. if (d.LengthSquared() == 0)
  221. d = new Vector2(ab.Y, -ab.X);
  222. continue; // skip to next iteration
  223. }
  224.  
  225. b = simplex[1];
  226. c = simplex[0];
  227. ab = Vector2.Subtract(b, a); // from point A to B
  228. ac = Vector2.Subtract(c, a); // from point A to C
  229.  
  230. acperp = TripleProduct(ab, ac, ac);
  231.  
  232. if (Vector2.Dot(acperp, ao) >= 0)
  233. {
  234.  
  235. d = acperp; // new direction is normal to AC towards Origin
  236.  
  237. }
  238. else
  239. {
  240.  
  241. abperp = TripleProduct(ac, ab, ab);
  242.  
  243. if (Vector2.Dot(abperp, ao) < 0)
  244. {
  245.  
  246. Result.collided = true;
  247. Result.simplex = simplex;
  248. break;
  249. }
  250.  
  251. simplex[0] = simplex[1]; // swap first element (point C)
  252.  
  253. d = abperp; // new direction is normal to AB towards Origin
  254. }
  255.  
  256. simplex[1] = simplex[2]; // swap element in the middle (point B)
  257. --index;
  258. }
  259. return Result;
  260. }
  261.  
  262. static Edge FindClosestEdge(List<Vector2> s)
  263. {
  264. Edge closest = new Edge();
  265. // prime the distance of the edge to the max
  266. closest.distance = double.MaxValue;
  267. // s is the passed in simplex
  268. for (int i = 0; i < s.Count; i++)
  269. {
  270. // compute the next points index
  271. int j = i + 1 == s.Count ? 0 : i + 1;
  272. // get the current point and the next one
  273. Vector2 a = s[i];
  274. Vector2 b = s[j];
  275. // create the edge vector
  276. Vector2 e = b - (a); // or a.to(b);
  277. // get the vector from the origin to a
  278. Vector2 oa = a; // or a - ORIGIN
  279. // get the vector from the edge towards the origin
  280. Vector2 n = TripleProduct(e, oa, e);
  281. // normalize the vector
  282. n.Normalize();
  283. // calculate the distance from the origin to the edge
  284. double d = Vector2.Dot(n, a); // could use b or a here
  285. // check the distance against the other distances
  286. if (d < closest.distance)
  287. {
  288. // if this edge is closer then use it
  289. closest.distance = d;
  290. closest.normal = n;
  291. closest.index = j;
  292. }
  293. }
  294. // return the closest edge we found
  295. return closest;
  296. }
  297.  
  298. public static GJKEPACollisonInfo GJKEPACollisionCheckWithInfo(Vector2[] vertices1, Vector2[] vertices2, out int iter_count)
  299. {
  300. GJKEPACollisonInfo Result = new GJKEPACollisonInfo();
  301. const double TOLERANCE = double.Epsilon;
  302. const int MaxIterations = 100;
  303. GJKCollisionInfo info = GJKCollisionCheckWithInfo(vertices1, vertices2, out iter_count);
  304. List<Vector2> simplex = new List<Vector2>(info.simplex);
  305. // loop to find the collision information
  306. Edge e = new Edge();
  307. Vector2 p = new Vector2();
  308. if (info.collided)
  309. {
  310. for (int i = 0; i < MaxIterations; i++)
  311. {
  312. // obtain the feature (edge for 2D) closest to the
  313. // origin on the Minkowski Difference
  314. e = FindClosestEdge(simplex);
  315. // obtain a new support point in the direction of the edge normal
  316. p = Support(vertices1, vertices2, e.normal);
  317. // check the distance from the origin to the edge against the
  318. // distance p is along e.normal
  319. double d = Vector2.Dot(p, e.normal);
  320. if (d - e.distance < TOLERANCE)
  321. {
  322. // the tolerance should be something positive close to zero (ex. 0.00001)
  323.  
  324. // if the difference is less than the tolerance then we can
  325. // assume that we cannot expand the simplex any further and
  326. // we have our solution
  327. Result.closest.normal = -1 * e.normal;
  328. Result.closest.distance = d;
  329. Result.closest.index = e.index;
  330. break;
  331. }
  332. else
  333. {
  334. // we haven't reached the edge of the Minkowski Difference
  335. // so continue expanding by adding the new point to the simplex
  336. // in between the points that made the closest edge
  337. simplex.Insert(e.index, p);
  338. }
  339. }
  340. }
  341. Result.closest.normal = -1 * e.normal;
  342. Result.closest.distance = Vector2.Dot(p, e.normal);
  343. Result.closest.index = e.index;
  344. Result.info.simplex = simplex.ToArray();
  345. Result.info = info;
  346. return Result;
  347. }
  348. }
  349. }
Add Comment
Please, Sign In to add comment