Collision.cs 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494
  1. /*
  2. * Box2D.XNA port of Box2D:
  3. * Copyright (c) 2009 Brandon Furtwangler, Nathan Furtwangler
  4. *
  5. * Original source Box2D:
  6. * Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
  7. *
  8. * This software is provided 'as-is', without any express or implied
  9. * warranty. In no event will the authors be held liable for any damages
  10. * arising from the use of this software.
  11. * Permission is granted to anyone to use this software for any purpose,
  12. * including commercial applications, and to alter it and redistribute it
  13. * freely, subject to the following restrictions:
  14. * 1. The origin of this software must not be misrepresented; you must not
  15. * claim that you wrote the original software. If you use this software
  16. * in a product, an acknowledgment in the product documentation would be
  17. * appreciated but is not required.
  18. * 2. Altered source versions must be plainly marked as such, and must not be
  19. * misrepresented as being the original software.
  20. * 3. This notice may not be removed or altered from any source distribution.
  21. */
  22. using System;
  23. using System.Diagnostics;
  24. using System.Runtime.InteropServices;
  25. using Microsoft.Xna.Framework;
  26. namespace Box2D.XNA
  27. {
  28. internal enum ContactFeatureType : byte
  29. {
  30. Vertex = 0,
  31. Face = 1,
  32. };
  33. /// The features that intersect to form the contact point
  34. /// This must be 4 bytes or less.
  35. public struct ContactFeature
  36. {
  37. internal byte indexA; ///< Feature index on ShapeA
  38. internal byte indexB; ///< Feature index on ShapeB
  39. internal byte typeA; ///< The feature type on ShapeA
  40. internal byte typeB; ///< The feature type on ShapeB
  41. };
  42. /// Contact ids to facilitate warm starting.
  43. [StructLayout(LayoutKind.Explicit)]
  44. public struct ContactID
  45. {
  46. [FieldOffset(0)]
  47. public ContactFeature Features;
  48. /// The features that intersect to form the contact point
  49. [FieldOffset(0)]
  50. public uint Key; ///< Used to quickly compare contact ids.
  51. };
  52. /// A manifold point is a contact point belonging to a contact
  53. /// manifold. It holds details related to the geometry and dynamics
  54. /// of the contact points.
  55. /// The local point usage depends on the manifold type:
  56. /// -ShapeType.Circles: the local center of circleB
  57. /// -SeparationFunction.FaceA: the local center of cirlceB or the clip point of polygonB
  58. /// -SeparationFunction.FaceB: the clip point of polygonA
  59. /// This structure is stored across time steps, so we keep it small.
  60. /// Note: the impulses are used for internal caching and may not
  61. /// provide reliable contact forces, especially for high speed collisions.
  62. public struct ManifoldPoint
  63. {
  64. public Vector2 LocalPoint; ///< usage depends on manifold type
  65. public float NormalImpulse; ///< the non-penetration impulse
  66. public float TangentImpulse; ///< the friction impulse
  67. public ContactID Id; ///< uniquely identifies a contact point between two Shapes
  68. };
  69. public enum ManifoldType
  70. {
  71. Circles,
  72. FaceA,
  73. FaceB
  74. };
  75. public enum EdgeType
  76. {
  77. Isolated,
  78. Concave,
  79. Flat,
  80. Convex
  81. };
  82. /// A manifold for two touching convex Shapes.
  83. /// Box2D supports multiple types of contact:
  84. /// - clip point versus plane with radius
  85. /// - point versus point with radius (circles)
  86. /// The local point usage depends on the manifold type:
  87. /// -ShapeType.Circles: the local center of circleA
  88. /// -SeparationFunction.FaceA: the center of faceA
  89. /// -SeparationFunction.FaceB: the center of faceB
  90. /// Similarly the local normal usage:
  91. /// -ShapeType.Circles: not used
  92. /// -SeparationFunction.FaceA: the normal on polygonA
  93. /// -SeparationFunction.FaceB: the normal on polygonB
  94. /// We store contacts in this way so that position correction can
  95. /// account for movement, which is critical for continuous physics.
  96. /// All contact scenarios must be expressed in one of these types.
  97. /// This structure is stored across time steps, so we keep it small.
  98. public struct Manifold
  99. {
  100. public FixedArray2<ManifoldPoint> _points; ///< the points of contact
  101. public Vector2 _localNormal; ///< not use for Type.SeparationFunction.Points
  102. public Vector2 _localPoint; ///< usage depends on manifold type
  103. public ManifoldType _type;
  104. public int _pointCount; ///< the number of manifold points
  105. };
  106. /// This is used to compute the current state of a contact manifold.
  107. public struct WorldManifold
  108. {
  109. /// Evaluate the manifold with supplied transforms. This assumes
  110. /// modest motion from the original state. This does not change the
  111. /// point count, impulses, etc. The radii must come from the Shapes
  112. /// that generated the manifold.
  113. public WorldManifold(ref Manifold manifold,
  114. ref Transform xfA, float radiusA,
  115. ref Transform xfB, float radiusB)
  116. {
  117. _points = new FixedArray2<Vector2>();
  118. if (manifold._pointCount == 0)
  119. {
  120. _normal = Vector2.UnitY;
  121. return;
  122. }
  123. switch (manifold._type)
  124. {
  125. case ManifoldType.Circles:
  126. {
  127. Vector2 pointA = MathUtils.Multiply(ref xfA, manifold._localPoint);
  128. Vector2 pointB = MathUtils.Multiply(ref xfB, manifold._points[0].LocalPoint);
  129. _normal = new Vector2(1.0f, 0.0f);
  130. if (Vector2.DistanceSquared(pointA, pointB) > Settings.b2_epsilon * Settings.b2_epsilon)
  131. {
  132. _normal = pointB - pointA;
  133. _normal.Normalize();
  134. }
  135. Vector2 cA = pointA + radiusA * _normal;
  136. Vector2 cB = pointB - radiusB * _normal;
  137. _points[0] = 0.5f * (cA + cB);
  138. }
  139. break;
  140. case ManifoldType.FaceA:
  141. {
  142. _normal = MathUtils.Multiply(ref xfA.R, manifold._localNormal);
  143. Vector2 planePoint = MathUtils.Multiply(ref xfA, manifold._localPoint);
  144. for (int i = 0; i < manifold._pointCount; ++i)
  145. {
  146. Vector2 clipPoint = MathUtils.Multiply(ref xfB, manifold._points[i].LocalPoint);
  147. Vector2 cA = clipPoint + (radiusA - Vector2.Dot(clipPoint - planePoint, _normal)) * _normal;
  148. Vector2 cB = clipPoint - radiusB * _normal;
  149. _points[i] = 0.5f * (cA + cB);
  150. }
  151. }
  152. break;
  153. case ManifoldType.FaceB:
  154. {
  155. _normal = MathUtils.Multiply(ref xfB.R, manifold._localNormal);
  156. Vector2 planePoint = MathUtils.Multiply(ref xfB, manifold._localPoint);
  157. for (int i = 0; i < manifold._pointCount; ++i)
  158. {
  159. Vector2 clipPoint = MathUtils.Multiply(ref xfA, manifold._points[i].LocalPoint);
  160. Vector2 cA = clipPoint - radiusA * _normal;
  161. Vector2 cB = clipPoint + (radiusB - Vector2.Dot(clipPoint - planePoint, _normal)) * _normal;
  162. _points[i] = 0.5f * (cA + cB);
  163. }
  164. // Ensure normal points from A to B.
  165. _normal *= -1;
  166. }
  167. break;
  168. default:
  169. _normal = Vector2.UnitY;
  170. break;
  171. }
  172. }
  173. public Vector2 _normal; ///< world vector pointing from A to B
  174. public FixedArray2<Vector2> _points; ///< world contact point (point of intersection)
  175. };
  176. /// This is used for determining the state of contact points.
  177. public enum PointState
  178. {
  179. Null, ///< point does not exist
  180. Add, ///< point was added in the update
  181. Persist, ///< point persisted across the update
  182. Remove, ///< point was removed in the update
  183. };
  184. /// Used for computing contact manifolds.
  185. public struct ClipVertex
  186. {
  187. public Vector2 v;
  188. public ContactID id;
  189. };
  190. /// Ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).
  191. public struct RayCastInput
  192. {
  193. public Vector2 p1, p2;
  194. public float maxFraction;
  195. };
  196. /// Ray-cast output data. The ray hits at p1 + fraction * (p2 - p1), where p1 and p2
  197. /// come from RayCastInput.
  198. public struct RayCastOutput
  199. {
  200. public Vector2 normal;
  201. public float fraction;
  202. };
  203. /// An axis aligned bounding box.
  204. public struct AABB
  205. {
  206. /// Verify that the bounds are sorted.
  207. public bool IsValid()
  208. {
  209. Vector2 d = upperBound - lowerBound;
  210. bool valid = d.X >= 0.0f && d.Y >= 0.0f;
  211. valid = valid && lowerBound.IsValid() && upperBound.IsValid();
  212. return valid;
  213. }
  214. /// Get the center of the AABB.
  215. public Vector2 GetCenter()
  216. {
  217. return 0.5f * (lowerBound + upperBound);
  218. }
  219. /// Get the extents of the AABB (half-widths).
  220. public Vector2 GetExtents()
  221. {
  222. return 0.5f * (upperBound - lowerBound);
  223. }
  224. /// Get the perimeter length
  225. public float GetPerimeter()
  226. {
  227. float wx = upperBound.X - lowerBound.X;
  228. float wy = upperBound.Y - lowerBound.Y;
  229. return 2.0f * (wx + wy);
  230. }
  231. /// Combine an AABB into this one.
  232. public void Combine(ref AABB aabb)
  233. {
  234. lowerBound = Vector2.Min(lowerBound, aabb.lowerBound);
  235. upperBound = Vector2.Max(upperBound, aabb.upperBound);
  236. }
  237. /// Combine two AABBs into this one.
  238. public void Combine(ref AABB aabb1, ref AABB aabb2)
  239. {
  240. lowerBound = Vector2.Min(aabb1.lowerBound, aabb2.lowerBound);
  241. upperBound = Vector2.Max(aabb1.upperBound, aabb2.upperBound);
  242. }
  243. /// Does this aabb contain the provided AABB.
  244. public bool Contains(ref AABB aabb)
  245. {
  246. bool result = true;
  247. result = result && lowerBound.X <= aabb.lowerBound.X;
  248. result = result && lowerBound.Y <= aabb.lowerBound.Y;
  249. result = result && aabb.upperBound.X <= upperBound.X;
  250. result = result && aabb.upperBound.Y <= upperBound.Y;
  251. return result;
  252. }
  253. public static bool TestOverlap(ref AABB a, ref AABB b)
  254. {
  255. Vector2 d1, d2;
  256. d1 = b.lowerBound - a.upperBound;
  257. d2 = a.lowerBound - b.upperBound;
  258. if (d1.X > 0.0f || d1.Y > 0.0f)
  259. return false;
  260. if (d2.X > 0.0f || d2.Y > 0.0f)
  261. return false;
  262. return true;
  263. }
  264. public static bool TestOverlap( Shape ShapeA, int indexA,
  265. Shape ShapeB, int indexB,
  266. ref Transform xfA, ref Transform xfB)
  267. {
  268. DistanceInput input = new DistanceInput();
  269. input.proxyA.Set(ShapeA, indexA);
  270. input.proxyB.Set(ShapeB, indexB);
  271. input.transformA = xfA;
  272. input.transformB = xfB;
  273. input.useRadii = true;
  274. SimplexCache cache;
  275. DistanceOutput output;
  276. Distance.ComputeDistance(out output, out cache, ref input);
  277. return output.distance < 10.0f * Settings.b2_epsilon;
  278. }
  279. // From Real-time Collision Detection, p179.
  280. public bool RayCast(out RayCastOutput output, ref RayCastInput input)
  281. {
  282. output = new RayCastOutput();
  283. float tmin = -Settings.b2_maxFloat;
  284. float tmax = Settings.b2_maxFloat;
  285. Vector2 p = input.p1;
  286. Vector2 d = input.p2 - input.p1;
  287. Vector2 absD = MathUtils.Abs(d);
  288. Vector2 normal = Vector2.Zero;
  289. for (int i = 0; i < 2; ++i)
  290. {
  291. float absD_i = i == 0 ? absD.X : absD.Y;
  292. float lowerBound_i = i == 0 ? lowerBound.X : lowerBound.Y;
  293. float upperBound_i = i == 0 ? upperBound.X : upperBound.Y;
  294. float p_i = i == 0 ? p.X : p.Y;
  295. if (absD_i < Settings.b2_epsilon)
  296. {
  297. // Parallel.
  298. if (p_i < lowerBound_i || upperBound_i < p_i)
  299. {
  300. return false;
  301. }
  302. }
  303. else
  304. {
  305. float d_i = i == 0 ? d.X : d.Y;
  306. float inv_d = 1.0f / d_i;
  307. float t1 = (lowerBound_i - p_i) * inv_d;
  308. float t2 = (upperBound_i - p_i) * inv_d;
  309. // Sign of the normal vector.
  310. float s = -1.0f;
  311. if (t1 > t2)
  312. {
  313. MathUtils.Swap<float>(ref t1, ref t2);
  314. s = 1.0f;
  315. }
  316. // Push the min up
  317. if (t1 > tmin)
  318. {
  319. if (i == 0)
  320. {
  321. normal.X = s;
  322. }
  323. else
  324. {
  325. normal.Y = s;
  326. }
  327. tmin = t1;
  328. }
  329. // Pull the max down
  330. tmax = Math.Min(tmax, t2);
  331. if (tmin > tmax)
  332. {
  333. return false;
  334. }
  335. }
  336. }
  337. // Does the ray start inside the box?
  338. // Does the ray intersect beyond the max fraction?
  339. if (tmin < 0.0f || input.maxFraction < tmin)
  340. {
  341. return false;
  342. }
  343. // Intersection.
  344. output.fraction = tmin;
  345. output.normal = normal;
  346. return true;
  347. }
  348. public Vector2 lowerBound; ///< the lower vertex
  349. public Vector2 upperBound; ///< the upper vertex
  350. };
  351. public static class Collision
  352. {
  353. public static void GetPointStates(out FixedArray2<PointState> state1, out FixedArray2<PointState> state2,
  354. ref Manifold manifold1, ref Manifold manifold2)
  355. {
  356. state1 = new FixedArray2<PointState>();
  357. state2 = new FixedArray2<PointState>();
  358. // Detect persists and removes.
  359. for (int i = 0; i < manifold1._pointCount; ++i)
  360. {
  361. ContactID id = manifold1._points[i].Id;
  362. state1[i] = PointState.Remove;
  363. for (int j = 0; j < manifold2._pointCount; ++j)
  364. {
  365. if (manifold2._points[j].Id.Key == id.Key)
  366. {
  367. state1[i] = PointState.Persist;
  368. break;
  369. }
  370. }
  371. }
  372. // Detect persists and adds.
  373. for (int i = 0; i < manifold2._pointCount; ++i)
  374. {
  375. ContactID id = manifold2._points[i].Id;
  376. state2[i] = PointState.Add;
  377. for (int j = 0; j < manifold1._pointCount; ++j)
  378. {
  379. if (manifold1._points[j].Id.Key == id.Key)
  380. {
  381. state2[i] = PointState.Persist;
  382. break;
  383. }
  384. }
  385. }
  386. }
  387. /// Compute the collision manifold between two circles.
  388. public static void CollideCircles(ref Manifold manifold,
  389. CircleShape circleA, ref Transform xfA,
  390. CircleShape circleB, ref Transform xfB)
  391. {
  392. manifold._pointCount = 0;
  393. Vector2 pA = MathUtils.Multiply(ref xfA, circleA._p);
  394. Vector2 pB = MathUtils.Multiply(ref xfB, circleB._p);
  395. Vector2 d = pB - pA;
  396. float distSqr = Vector2.Dot(d, d);
  397. float rA = circleA._radius;
  398. float rB = circleB._radius;
  399. float radius = rA + rB;
  400. if (distSqr > radius * radius)
  401. {
  402. return;
  403. }
  404. manifold._type = ManifoldType.Circles;
  405. manifold._localPoint = circleA._p;
  406. manifold._localNormal = Vector2.Zero;
  407. manifold._pointCount = 1;
  408. var p0 = manifold._points[0];
  409. p0.LocalPoint = circleB._p;
  410. p0.Id.Key = 0;
  411. manifold._points[0] = p0;
  412. }
  413. /// Compute the collision manifold between a polygon and a circle.
  414. public static void CollidePolygonAndCircle(ref Manifold manifold,
  415. PolygonShape polygonA, ref Transform xfA,
  416. CircleShape circleB, ref Transform xfB)
  417. {
  418. manifold._pointCount = 0;
  419. // Compute circle position in the frame of the polygon.
  420. Vector2 c = MathUtils.Multiply(ref xfB, circleB._p);
  421. Vector2 cLocal = MathUtils.MultiplyT(ref xfA, c);
  422. // Find the min separating edge.
  423. int normalIndex = 0;
  424. float separation = -Settings.b2_maxFloat;
  425. float radius = polygonA._radius + circleB._radius;
  426. int vertexCount = polygonA._vertexCount;
  427. for (int i = 0; i < vertexCount; ++i)
  428. {
  429. float s = Vector2.Dot(polygonA._normals[i], cLocal - polygonA._vertices[i]);
  430. if (s > radius)
  431. {
  432. // Early out.
  433. return;
  434. }
  435. if (s > separation)
  436. {
  437. separation = s;
  438. normalIndex = i;
  439. }
  440. }
  441. // Vertices that subtend the incident face.
  442. int vertIndex1 = normalIndex;
  443. int vertIndex2 = vertIndex1 + 1 < vertexCount ? vertIndex1 + 1 : 0;
  444. Vector2 v1 = polygonA._vertices[vertIndex1];
  445. Vector2 v2 = polygonA._vertices[vertIndex2];
  446. // If the center is inside the polygon ...
  447. if (separation < Settings.b2_epsilon)
  448. {
  449. manifold._pointCount = 1;
  450. manifold._type = ManifoldType.FaceA;
  451. manifold._localNormal = polygonA._normals[normalIndex];
  452. manifold._localPoint = 0.5f * (v1 + v2);
  453. var p0 = manifold._points[0];
  454. p0.LocalPoint = circleB._p;
  455. p0.Id.Key = 0;
  456. manifold._points[0] = p0;
  457. return;
  458. }
  459. // Compute barycentric coordinates
  460. float u1 = Vector2.Dot(cLocal - v1, v2 - v1);
  461. float u2 = Vector2.Dot(cLocal - v2, v1 - v2);
  462. if (u1 <= 0.0f)
  463. {
  464. if (Vector2.DistanceSquared(cLocal, v1) > radius * radius)
  465. {
  466. return;
  467. }
  468. manifold._pointCount = 1;
  469. manifold._type = ManifoldType.FaceA;
  470. manifold._localNormal = cLocal - v1;
  471. manifold._localNormal.Normalize();
  472. manifold._localPoint = v1;
  473. var p0b = manifold._points[0];
  474. p0b.LocalPoint = circleB._p;
  475. p0b.Id.Key = 0;
  476. manifold._points[0] = p0b;
  477. }
  478. else if (u2 <= 0.0f)
  479. {
  480. if (Vector2.DistanceSquared(cLocal, v2) > radius * radius)
  481. {
  482. return;
  483. }
  484. manifold._pointCount = 1;
  485. manifold._type = ManifoldType.FaceA;
  486. manifold._localNormal = cLocal - v2;
  487. manifold._localNormal.Normalize();
  488. manifold._localPoint = v2;
  489. var p0c = manifold._points[0];
  490. p0c.LocalPoint = circleB._p;
  491. p0c.Id.Key = 0;
  492. manifold._points[0] = p0c;
  493. }
  494. else
  495. {
  496. Vector2 faceCenter = 0.5f * (v1 + v2);
  497. float separation2 = Vector2.Dot(cLocal - faceCenter, polygonA._normals[vertIndex1]);
  498. if (separation2 > radius)
  499. {
  500. return;
  501. }
  502. manifold._pointCount = 1;
  503. manifold._type = ManifoldType.FaceA;
  504. manifold._localNormal = polygonA._normals[vertIndex1];
  505. manifold._localPoint = faceCenter;
  506. var p0d = manifold._points[0];
  507. p0d.LocalPoint = circleB._p;
  508. p0d.Id.Key = 0;
  509. manifold._points[0] = p0d;
  510. }
  511. }
  512. /// Compute the collision manifold between two polygons.
  513. public static void CollidePolygons(ref Manifold manifold,
  514. PolygonShape polyA, ref Transform xfA,
  515. PolygonShape polyB, ref Transform xfB)
  516. {
  517. manifold._pointCount = 0;
  518. float totalRadius = polyA._radius + polyB._radius;
  519. int edgeA = 0;
  520. float separationA = FindMaxSeparation(out edgeA, polyA, ref xfA, polyB, ref xfB);
  521. if (separationA > totalRadius)
  522. return;
  523. int edgeB = 0;
  524. float separationB = FindMaxSeparation(out edgeB, polyB, ref xfB, polyA, ref xfA);
  525. if (separationB > totalRadius)
  526. return;
  527. PolygonShape poly1; // reference polygon
  528. PolygonShape poly2; // incident polygon
  529. Transform xf1, xf2;
  530. int edge1; // reference edge
  531. bool flip;
  532. float k_relativeTol = 0.98f;
  533. float k_absoluteTol = 0.001f;
  534. if (separationB > k_relativeTol * separationA + k_absoluteTol)
  535. {
  536. poly1 = polyB;
  537. poly2 = polyA;
  538. xf1 = xfB;
  539. xf2 = xfA;
  540. edge1 = edgeB;
  541. manifold._type = ManifoldType.FaceB;
  542. flip = true;
  543. }
  544. else
  545. {
  546. poly1 = polyA;
  547. poly2 = polyB;
  548. xf1 = xfA;
  549. xf2 = xfB;
  550. edge1 = edgeA;
  551. manifold._type = ManifoldType.FaceA;
  552. flip = false;
  553. }
  554. FixedArray2<ClipVertex> incidentEdge;
  555. FindIncidentEdge(out incidentEdge, poly1, ref xf1, edge1, poly2, ref xf2);
  556. int count1 = poly1._vertexCount;
  557. int iv1 = edge1;
  558. int iv2 = edge1 + 1 < count1 ? edge1 + 1 : 0;
  559. Vector2 v11 = poly1._vertices[iv1];
  560. Vector2 v12 = poly1._vertices[iv2];
  561. Vector2 localTangent = v12 - v11;
  562. localTangent.Normalize();
  563. Vector2 localNormal = MathUtils.Cross(localTangent, 1.0f);
  564. Vector2 planePoint = 0.5f * (v11 + v12);
  565. Vector2 tangent = MathUtils.Multiply(ref xf1.R, localTangent);
  566. Vector2 normal = MathUtils.Cross(tangent, 1.0f);
  567. v11 = MathUtils.Multiply(ref xf1, v11);
  568. v12 = MathUtils.Multiply(ref xf1, v12);
  569. // Face offset.
  570. float frontOffset = Vector2.Dot(normal, v11);
  571. // Side offsets, extended by polytope skin thickness.
  572. float sideOffset1 = -Vector2.Dot(tangent, v11) + totalRadius;
  573. float sideOffset2 = Vector2.Dot(tangent, v12) + totalRadius;
  574. // Clip incident edge against extruded edge1 side edges.
  575. FixedArray2<ClipVertex> clipPoints1;
  576. FixedArray2<ClipVertex> clipPoints2;
  577. int np;
  578. // Clip to box side 1
  579. np = ClipSegmentToLine(out clipPoints1, ref incidentEdge, -tangent, sideOffset1, iv1);
  580. if (np < 2)
  581. return;
  582. // Clip to negative box side 1
  583. np = ClipSegmentToLine(out clipPoints2, ref clipPoints1, tangent, sideOffset2, iv2);
  584. if (np < 2)
  585. {
  586. return;
  587. }
  588. // Now clipPoints2 contains the clipped points.
  589. manifold._localNormal = localNormal;
  590. manifold._localPoint = planePoint;
  591. int pointCount = 0;
  592. for (int i = 0; i < Settings.b2_maxManifoldPoints; ++i)
  593. {
  594. float separation = Vector2.Dot(normal, clipPoints2[i].v) - frontOffset;
  595. if (separation <= totalRadius)
  596. {
  597. ManifoldPoint cp = manifold._points[pointCount];
  598. cp.LocalPoint = MathUtils.MultiplyT(ref xf2, clipPoints2[i].v);
  599. cp.Id = clipPoints2[i].id;
  600. if (flip)
  601. {
  602. // Swap features
  603. ContactFeature cf = cp.Id.Features;
  604. cp.Id.Features.indexA = cf.indexB;
  605. cp.Id.Features.indexB = cf.indexA;
  606. cp.Id.Features.typeA = cf.typeB;
  607. cp.Id.Features.typeB = cf.typeA;
  608. }
  609. manifold._points[pointCount] = cp;
  610. ++pointCount;
  611. }
  612. }
  613. manifold._pointCount = pointCount;
  614. }
  615. // Compute contact points for edge versus circle.
  616. // This accounts for edge connectivity.
  617. public static void CollideEdgeAndCircle(ref Manifold manifold,
  618. EdgeShape edgeA, ref Transform xfA,
  619. CircleShape circleB, ref Transform xfB)
  620. {
  621. manifold._pointCount = 0;
  622. // Compute circle in frame of edge
  623. Vector2 Q = MathUtils.MultiplyT(ref xfA, MathUtils.Multiply(ref xfB, circleB._p));
  624. Vector2 A = edgeA._vertex1, B = edgeA._vertex2;
  625. Vector2 e = B - A;
  626. // Barycentric coordinates
  627. float u = Vector2.Dot(e, B - Q);
  628. float v = Vector2.Dot(e, Q - A);
  629. float radius = edgeA._radius + circleB._radius;
  630. ContactFeature cf;
  631. cf.indexB = 0;
  632. cf.typeB = (byte)ContactFeatureType.Vertex;
  633. Vector2 P, d;
  634. // Region A
  635. if (v <= 0.0f)
  636. {
  637. P = A;
  638. d = Q - P;
  639. float dd = Vector2.Dot(d, d);
  640. if (dd > radius * radius)
  641. {
  642. return;
  643. }
  644. // Is there an edge connected to A?
  645. if (edgeA._hasVertex0)
  646. {
  647. Vector2 A1 = edgeA._vertex0;
  648. Vector2 B1 = A;
  649. Vector2 e1 = B1 - A1;
  650. float u1 = Vector2.Dot(e1, B1 - Q);
  651. // Is the circle in Region AB of the previous edge?
  652. if (u1 > 0.0f)
  653. {
  654. return;
  655. }
  656. }
  657. cf.indexA = 0;
  658. cf.typeA = (byte)ContactFeatureType.Vertex;
  659. manifold._pointCount = 1;
  660. manifold._type = ManifoldType.Circles;
  661. manifold._localNormal = Vector2.Zero;
  662. manifold._localPoint = P;
  663. var mp = new ManifoldPoint();
  664. mp.Id.Key = 0;
  665. mp.Id.Features = cf;
  666. mp.LocalPoint = circleB._p;
  667. manifold._points[0] = mp;
  668. return;
  669. }
  670. // Region B
  671. if (u <= 0.0f)
  672. {
  673. P = B;
  674. d = Q - P;
  675. float dd = Vector2.Dot(d, d);
  676. if (dd > radius * radius)
  677. {
  678. return;
  679. }
  680. // Is there an edge connected to B?
  681. if (edgeA._hasVertex3)
  682. {
  683. Vector2 B2 = edgeA._vertex3;
  684. Vector2 A2 = B;
  685. Vector2 e2 = B2 - A2;
  686. float v2 = Vector2.Dot(e2, Q - A2);
  687. // Is the circle in Region AB of the next edge?
  688. if (v2 > 0.0f)
  689. {
  690. return;
  691. }
  692. }
  693. cf.indexA = 1;
  694. cf.typeA = (byte)ContactFeatureType.Vertex;
  695. manifold._pointCount = 1;
  696. manifold._type = ManifoldType.Circles;
  697. manifold._localNormal = Vector2.Zero;
  698. manifold._localPoint = P;
  699. var mp = new ManifoldPoint();
  700. mp.Id.Key = 0;
  701. mp.Id.Features = cf;
  702. mp.LocalPoint = circleB._p;
  703. manifold._points[0] = mp;
  704. return;
  705. }
  706. // Region AB
  707. float den = Vector2.Dot(e, e);
  708. Debug.Assert(den > 0.0f);
  709. P = (1.0f / den) * (u * A + v * B);
  710. d = Q - P;
  711. float dd2 = Vector2.Dot(d, d);
  712. if (dd2 > radius * radius)
  713. {
  714. return;
  715. }
  716. Vector2 n = new Vector2(-e.Y, e.X);
  717. if (Vector2.Dot(n, Q - A) < 0.0f)
  718. {
  719. n = new Vector2(-n.X, -n.Y);
  720. }
  721. n.Normalize();
  722. cf.indexA = 0;
  723. cf.typeA = (byte)ContactFeatureType.Face;
  724. manifold._pointCount = 1;
  725. manifold._type = ManifoldType.FaceA;
  726. manifold._localNormal = n;
  727. manifold._localPoint = A;
  728. var mp2 = new ManifoldPoint();
  729. mp2.Id.Key = 0;
  730. mp2.Id.Features = cf;
  731. mp2.LocalPoint = circleB._p;
  732. manifold._points[0] = mp2;
  733. }
  734. public enum EPAxisType
  735. {
  736. Unknown,
  737. EdgeA,
  738. EdgeB,
  739. };
  740. public struct EPAxis
  741. {
  742. public EPAxisType type;
  743. public int index;
  744. public float separation;
  745. };
  746. static EPAxis ComputeEdgeSeperation(Vector2 v1, Vector2 v2, Vector2 n, PolygonShape polygonB, float radius)
  747. {
  748. // EdgeA separation
  749. EPAxis axis;
  750. axis.type = EPAxisType.EdgeA;
  751. axis.index = 0;
  752. axis.separation = Vector2.Dot(n, polygonB._vertices[0] - v1);
  753. for (int i = 1; i < polygonB._vertexCount; ++i)
  754. {
  755. float s = Vector2.Dot(n, polygonB._vertices[i] - v1);
  756. if (s < axis.separation)
  757. {
  758. axis.separation = s;
  759. }
  760. }
  761. return axis;
  762. }
  763. static EPAxis ComputePolygonSeperation(Vector2 v1, Vector2 v2, Vector2 n, PolygonShape polygonB, float radius)
  764. {
  765. // PolygonB separation
  766. EPAxis axis;
  767. axis.type = EPAxisType.EdgeB;
  768. axis.index = 0;
  769. axis.separation = float.MinValue;
  770. for (int i = 0; i < polygonB._vertexCount; ++i)
  771. {
  772. float s1 = Vector2.Dot(polygonB._normals[i], v1 - polygonB._vertices[i]);
  773. float s2 = Vector2.Dot(polygonB._normals[i], v2 - polygonB._vertices[i]);
  774. float s = Math.Min(s1, s2);
  775. if (s > axis.separation)
  776. {
  777. axis.index = i;
  778. axis.separation = s;
  779. if (s > radius)
  780. {
  781. return axis;
  782. }
  783. }
  784. }
  785. return axis;
  786. }
  787. static void FindIncidentEdge(ref FixedArray2<ClipVertex> c, PolygonShape poly1, int edge1, PolygonShape poly2)
  788. {
  789. int count1 = poly1._vertexCount;
  790. int count2 = poly2._vertexCount;
  791. Debug.Assert(0 <= edge1 && edge1 < count1);
  792. // Get the normal of the reference edge in poly2's frame.
  793. Vector2 normal1 = poly1._normals[edge1];
  794. // Find the incident edge on poly2.
  795. int index = 0;
  796. float minDot = float.MaxValue;
  797. for (int i = 0; i < count2; ++i)
  798. {
  799. float dot = Vector2.Dot(normal1, poly2._normals[i]);
  800. if (dot < minDot)
  801. {
  802. minDot = dot;
  803. index = i;
  804. }
  805. }
  806. // Build the clip vertices for the incident edge.
  807. int i1 = index;
  808. int i2 = i1 + 1 < count2 ? i1 + 1 : 0;
  809. ClipVertex ctemp = new ClipVertex();
  810. ctemp.v = poly2._vertices[i1];
  811. ctemp.id.Features.indexA = (byte)edge1;
  812. ctemp.id.Features.indexB = (byte)i1;
  813. ctemp.id.Features.typeA = (byte)ContactFeatureType.Face;
  814. ctemp.id.Features.typeB = (byte)ContactFeatureType.Vertex;
  815. c[0] = ctemp;
  816. ctemp.v = poly2._vertices[i2];
  817. ctemp.id.Features.indexA = (byte)edge1;
  818. ctemp.id.Features.indexB = (byte)i2;
  819. ctemp.id.Features.typeA = (byte)ContactFeatureType.Face;
  820. ctemp.id.Features.typeB = (byte)ContactFeatureType.Vertex;
  821. c[1] = ctemp;
  822. }
  823. // Collide and edge and polygon. This uses the SAT and clipping to produce up to 2 contact points.
  824. // Edge adjacency is handle to produce locally valid contact points and normals. This is intended
  825. // to allow the polygon to slide smoothly over an edge chain.
  826. //
  827. // Algorithm
  828. // 1. Classify front-side or back-side collision with edge.
  829. // 2. Compute separation
  830. // 3. Process adjacent edges
  831. // 4. Classify adjacent edge as convex, flat, null, or concave
  832. // 5. Skip null or concave edges. Concave edges get a separate manifold.
  833. // 6. If the edge is flat, compute contact points as normal. Discard boundary points.
  834. // 7. If the edge is convex, compute it's separation.
  835. // 8. Use the minimum separation of up to three edges. If the minimum separation
  836. // is not the primary edge, return.
  837. // 9. If the minimum separation is the primary edge, compute the contact points and return.
  838. static PolygonShape s_polygonA = new PolygonShape();
  839. static PolygonShape s_polygonB = new PolygonShape();
  840. public static void CollideEdgeAndPolygon(ref Manifold manifold,
  841. EdgeShape edgeA, ref Transform xfA,
  842. PolygonShape polygonB_in, ref Transform xfB)
  843. {
  844. manifold._pointCount = 0;
  845. Transform xf;
  846. MathUtils.MultiplyT(ref xfA, ref xfB, out xf);
  847. // Create a polygon for edge shape A
  848. s_polygonA.SetAsEdge(edgeA._vertex1, edgeA._vertex2);
  849. // Build polygonB in frame A
  850. s_polygonB._radius = polygonB_in._radius;
  851. s_polygonB._vertexCount = polygonB_in._vertexCount;
  852. s_polygonB._centroid = MathUtils.Multiply(ref xf, polygonB_in._centroid);
  853. for (int i = 0; i < s_polygonB._vertexCount; ++i)
  854. {
  855. s_polygonB._vertices[i] = MathUtils.Multiply(ref xf, polygonB_in._vertices[i]);
  856. s_polygonB._normals[i] = MathUtils.Multiply(ref xf.R, polygonB_in._normals[i]);
  857. }
  858. float totalRadius = s_polygonA._radius + s_polygonB._radius;
  859. // Edge geometry
  860. Vector2 v1 = edgeA._vertex1;
  861. Vector2 v2 = edgeA._vertex2;
  862. Vector2 e = v2 - v1;
  863. Vector2 edgeNormal = new Vector2(e.Y, -e.X);
  864. edgeNormal.Normalize();
  865. // Determine side
  866. bool isFrontSide = Vector2.Dot(edgeNormal, s_polygonB._centroid - v1) >= 0.0f;
  867. if (isFrontSide == false)
  868. {
  869. edgeNormal = -edgeNormal;
  870. }
  871. // Compute primary separating axis
  872. EPAxis edgeAxis = ComputeEdgeSeperation(v1, v2, edgeNormal, s_polygonB, totalRadius);
  873. if (edgeAxis.separation > totalRadius)
  874. {
  875. // Shapes are separated
  876. return;
  877. }
  878. // Classify adjacent edges
  879. FixedArray2<EdgeType> types = new FixedArray2<EdgeType>();
  880. //types[0] = EdgeType.Isolated;
  881. //types[1] = EdgeType.Isolated;
  882. if (edgeA._hasVertex0)
  883. {
  884. Vector2 v0 = edgeA._vertex0;
  885. float s = Vector2.Dot(edgeNormal, v0 - v1);
  886. if (s > 0.1f * Settings.b2_linearSlop)
  887. {
  888. types[0] = EdgeType.Concave;
  889. }
  890. else if (s >= -0.1f * Settings.b2_linearSlop)
  891. {
  892. types[0] = EdgeType.Flat;
  893. }
  894. else
  895. {
  896. types[0] = EdgeType.Convex;
  897. }
  898. }
  899. if (edgeA._hasVertex3)
  900. {
  901. Vector2 v3 = edgeA._vertex3;
  902. float s = Vector2.Dot(edgeNormal, v3 - v2);
  903. if (s > 0.1f * Settings.b2_linearSlop)
  904. {
  905. types[1] = EdgeType.Concave;
  906. }
  907. else if (s >= -0.1f * Settings.b2_linearSlop)
  908. {
  909. types[1] = EdgeType.Flat;
  910. }
  911. else
  912. {
  913. types[1] = EdgeType.Convex;
  914. }
  915. }
  916. if (types[0] == EdgeType.Convex)
  917. {
  918. // Check separation on previous edge.
  919. Vector2 v0 = edgeA._vertex0;
  920. Vector2 e0 = v1 - v0;
  921. Vector2 n0 = new Vector2(e0.Y, -e0.X);
  922. n0.Normalize();
  923. if (isFrontSide == false)
  924. {
  925. n0 = -n0;
  926. }
  927. EPAxis axis1 = ComputeEdgeSeperation(v0, v1, n0, s_polygonB, totalRadius);
  928. if (axis1.separation > edgeAxis.separation)
  929. {
  930. // The polygon should collide with previous edge
  931. return;
  932. }
  933. }
  934. if (types[1] == EdgeType.Convex)
  935. {
  936. // Check separation on next edge.
  937. Vector2 v3 = edgeA._vertex3;
  938. Vector2 e2 = v3 - v2;
  939. Vector2 n2 = new Vector2(e2.Y, -e2.X);
  940. n2.Normalize();
  941. if (isFrontSide == false)
  942. {
  943. n2 = -n2;
  944. }
  945. EPAxis axis2 = ComputeEdgeSeperation(v2, v3, n2, s_polygonB, totalRadius);
  946. if (axis2.separation > edgeAxis.separation)
  947. {
  948. // The polygon should collide with the next edge
  949. return;
  950. }
  951. }
  952. EPAxis polygonAxis = ComputePolygonSeperation(v1, v2, edgeNormal, s_polygonB, totalRadius);
  953. if (polygonAxis.separation > totalRadius)
  954. {
  955. return;
  956. }
  957. // Use hysteresis for jitter reduction.
  958. float k_relativeTol = 0.98f;
  959. float k_absoluteTol = 0.001f;
  960. EPAxis primaryAxis;
  961. if (polygonAxis.separation > k_relativeTol * edgeAxis.separation + k_absoluteTol)
  962. {
  963. primaryAxis = polygonAxis;
  964. }
  965. else
  966. {
  967. primaryAxis = edgeAxis;
  968. }
  969. PolygonShape poly1;
  970. PolygonShape poly2;
  971. if (primaryAxis.type == EPAxisType.EdgeA)
  972. {
  973. poly1 = s_polygonA;
  974. poly2 = s_polygonB;
  975. if (isFrontSide == false)
  976. {
  977. primaryAxis.index = 1;
  978. }
  979. manifold._type = ManifoldType.FaceA;
  980. }
  981. else
  982. {
  983. poly1 = s_polygonB;
  984. poly2 = s_polygonA;
  985. manifold._type = ManifoldType.FaceB;
  986. }
  987. int edge1 = primaryAxis.index;
  988. FixedArray2<ClipVertex> incidentEdge = new FixedArray2<ClipVertex>();
  989. FindIncidentEdge(ref incidentEdge, poly1, primaryAxis.index, poly2);
  990. int count1 = poly1._vertexCount;
  991. int iv1 = edge1;
  992. int iv2 = edge1 + 1 < count1 ? edge1 + 1 : 0;
  993. Vector2 v11 = poly1._vertices[iv1];
  994. Vector2 v12 = poly1._vertices[iv2];
  995. Vector2 tangent = v12 - v11;
  996. tangent.Normalize();
  997. Vector2 normal = MathUtils.Cross(tangent, 1.0f);
  998. Vector2 planePoint = 0.5f * (v11 + v12);
  999. // Face offset.
  1000. float frontOffset = Vector2.Dot(normal, v11);
  1001. // Side offsets, extended by polytope skin thickness.
  1002. float sideOffset1 = -Vector2.Dot(tangent, v11) + totalRadius;
  1003. float sideOffset2 = Vector2.Dot(tangent, v12) + totalRadius;
  1004. // Clip incident edge against extruded edge1 side edges.
  1005. FixedArray2<ClipVertex> clipPoints1;
  1006. FixedArray2<ClipVertex> clipPoints2;
  1007. int np;
  1008. // Clip to box side 1
  1009. np = ClipSegmentToLine(out clipPoints1, ref incidentEdge, -tangent, sideOffset1, iv1);
  1010. if (np < Settings.b2_maxManifoldPoints)
  1011. {
  1012. return;
  1013. }
  1014. // Clip to negative box side 1
  1015. np = ClipSegmentToLine(out clipPoints2, ref clipPoints1, tangent, sideOffset2, iv2);
  1016. if (np < Settings.b2_maxManifoldPoints)
  1017. {
  1018. return;
  1019. }
  1020. // Now clipPoints2 contains the clipped points.
  1021. if (primaryAxis.type == EPAxisType.EdgeA)
  1022. {
  1023. manifold._localNormal = normal;
  1024. manifold._localPoint = planePoint;
  1025. }
  1026. else
  1027. {
  1028. manifold._localNormal = MathUtils.MultiplyT(ref xf.R, normal);
  1029. manifold._localPoint = MathUtils.MultiplyT(ref xf, planePoint);
  1030. }
  1031. int pointCount = 0;
  1032. for (int i = 0; i < Settings.b2_maxManifoldPoints; ++i)
  1033. {
  1034. float separation;
  1035. separation = Vector2.Dot(normal, clipPoints2[i].v) - frontOffset;
  1036. if (separation <= totalRadius)
  1037. {
  1038. ManifoldPoint cp = manifold._points[pointCount];
  1039. if (primaryAxis.type == EPAxisType.EdgeA)
  1040. {
  1041. cp.LocalPoint = MathUtils.MultiplyT(ref xf, clipPoints2[i].v);
  1042. cp.Id = clipPoints2[i].id;
  1043. }
  1044. else
  1045. {
  1046. cp.LocalPoint = clipPoints2[i].v;
  1047. cp.Id.Features.typeA = clipPoints2[i].id.Features.typeB;
  1048. cp.Id.Features.typeB = clipPoints2[i].id.Features.typeA;
  1049. cp.Id.Features.indexA = clipPoints2[i].id.Features.indexB;
  1050. cp.Id.Features.indexB = clipPoints2[i].id.Features.indexA;
  1051. }
  1052. manifold._points[pointCount] = cp;
  1053. if (cp.Id.Features.typeA == (byte)ContactFeatureType.Vertex && types[cp.Id.Features.indexA] == EdgeType.Flat)
  1054. {
  1055. continue;
  1056. }
  1057. ++pointCount;
  1058. }
  1059. }
  1060. manifold._pointCount = pointCount;
  1061. }
  1062. /// Clipping for contact manifolds.
  1063. public static int ClipSegmentToLine(out FixedArray2<ClipVertex> vOut, ref FixedArray2<ClipVertex> vIn,
  1064. Vector2 normal, float offset, int vertexIndexA)
  1065. {
  1066. vOut = new FixedArray2<ClipVertex>();
  1067. // Start with no output points
  1068. int numOut = 0;
  1069. // Calculate the distance of end points to the line
  1070. float distance0 = Vector2.Dot(normal, vIn[0].v) - offset;
  1071. float distance1 = Vector2.Dot(normal, vIn[1].v) - offset;
  1072. // If the points are behind the plane
  1073. if (distance0 <= 0.0f) vOut[numOut++] = vIn[0];
  1074. if (distance1 <= 0.0f) vOut[numOut++] = vIn[1];
  1075. // If the points are on different sides of the plane
  1076. if (distance0 * distance1 < 0.0f)
  1077. {
  1078. // Find intersection point of edge and plane
  1079. float interp = distance0 / (distance0 - distance1);
  1080. var cv = vOut[numOut];
  1081. cv.v = vIn[0].v + interp * (vIn[1].v - vIn[0].v);
  1082. // VertexA is hitting edgeB.
  1083. cv.id.Features.indexA = (byte)vertexIndexA;
  1084. cv.id.Features.indexB = vIn[0].id.Features.indexB;
  1085. cv.id.Features.typeA = (byte)ContactFeatureType.Vertex;
  1086. cv.id.Features.typeB = (byte)ContactFeatureType.Face;
  1087. vOut[numOut] = cv;
  1088. ++numOut;
  1089. }
  1090. return numOut;
  1091. }
  1092. // Find the separation between poly1 and poly2 for a give edge normal on poly1.
  1093. static float EdgeSeparation(PolygonShape poly1, ref Transform xf1, int edge1,
  1094. PolygonShape poly2, ref Transform xf2)
  1095. {
  1096. int count1 = poly1._vertexCount;
  1097. int count2 = poly2._vertexCount;
  1098. Debug.Assert(0 <= edge1 && edge1 < count1);
  1099. // Convert normal from poly1's frame into poly2's frame.
  1100. #if MATH_OVERLOADS
  1101. Vector2 normal1World = MathUtils.Multiply(ref xf1.R, poly1._normals[edge1]);
  1102. Vector2 normal1 = MathUtils.MultiplyT(ref xf2.R, normal1World);
  1103. #else
  1104. Vector2 p1n = poly1._normals[edge1];
  1105. Vector2 normal1World = new Vector2(xf1.R.col1.X * p1n.X + xf1.R.col2.X * p1n.Y, xf1.R.col1.Y * p1n.X + xf1.R.col2.Y * p1n.Y);
  1106. Vector2 normal1 = new Vector2(normal1World.X * xf2.R.col1.X + normal1World.Y * xf2.R.col1.Y, normal1World.X * xf2.R.col2.X + normal1World.Y * xf2.R.col2.Y);
  1107. #endif
  1108. // Find support vertex on poly2 for -normal.
  1109. int index = 0;
  1110. float minDot = Settings.b2_maxFloat;
  1111. for (int i = 0; i < count2; ++i)
  1112. {
  1113. #if !MATH_OVERLOADS // inlining this made it 1ms slower
  1114. float dot = Vector2.Dot(poly2._vertices[i], normal1);
  1115. #else
  1116. Vector2 p2vi = poly2._vertices[i];
  1117. float dot = p2vi.X * normal1.X + p2vi.Y * normal1.Y;
  1118. #endif
  1119. if (dot < minDot)
  1120. {
  1121. minDot = dot;
  1122. index = i;
  1123. }
  1124. }
  1125. #if MATH_OVERLOADS
  1126. Vector2 v1 = MathUtils.Multiply(ref xf1, poly1._vertices[edge1]);
  1127. Vector2 v2 = MathUtils.Multiply(ref xf2, poly2._vertices[index]);
  1128. #else
  1129. Vector2 p1ve = poly1._vertices[edge1];
  1130. Vector2 p2vi = poly2._vertices[index];
  1131. Vector2 v1 = new Vector2(xf1.Position.X + xf1.R.col1.X * p1ve.X + xf1.R.col2.X * p1ve.Y,
  1132. xf1.Position.Y + xf1.R.col1.Y * p1ve.X + xf1.R.col2.Y * p1ve.Y);
  1133. Vector2 v2 = new Vector2(xf2.Position.X + xf2.R.col1.X * p2vi.X + xf2.R.col2.X * p2vi.Y,
  1134. xf2.Position.Y + xf2.R.col1.Y * p2vi.X + xf2.R.col2.Y * p2vi.Y);
  1135. #endif
  1136. #if !MATH_OVERLOADS // inlining is 1ms slower
  1137. float separation = Vector2.Dot(v2 - v1, normal1World);
  1138. #else
  1139. Vector2 v2subv1 = new Vector2(v2.X - v1.X, v2.Y - v1.Y);
  1140. float separation = v2subv1.X * normal1World.X + v2subv1.Y * normal1World.Y;
  1141. #endif
  1142. return separation;
  1143. }
  1144. // Find the max separation between poly1 and poly2 using edge normals from poly1.
  1145. static float FindMaxSeparation( out int edgeIndex,
  1146. PolygonShape poly1, ref Transform xf1,
  1147. PolygonShape poly2, ref Transform xf2)
  1148. {
  1149. edgeIndex = -1;
  1150. int count1 = poly1._vertexCount;
  1151. // Vector pointing from the centroid of poly1 to the centroid of poly2.
  1152. Vector2 d = MathUtils.Multiply(ref xf2, poly2._centroid) - MathUtils.Multiply(ref xf1, poly1._centroid);
  1153. Vector2 dLocal1 = MathUtils.MultiplyT(ref xf1.R, d);
  1154. // Find edge normal on poly1 that has the largest projection onto d.
  1155. int edge = 0;
  1156. float maxDot = -Settings.b2_maxFloat;
  1157. for (int i = 0; i < count1; ++i)
  1158. {
  1159. float dot = Vector2.Dot(poly1._normals[i], dLocal1);
  1160. if (dot > maxDot)
  1161. {
  1162. maxDot = dot;
  1163. edge = i;
  1164. }
  1165. }
  1166. // Get the separation for the edge normal.
  1167. float s = EdgeSeparation(poly1, ref xf1, edge, poly2, ref xf2);
  1168. // Check the separation for the previous edge normal.
  1169. int prevEdge = edge - 1 >= 0 ? edge - 1 : count1 - 1;
  1170. float sPrev = EdgeSeparation(poly1, ref xf1, prevEdge, poly2, ref xf2);
  1171. // Check the separation for the next edge normal.
  1172. int nextEdge = edge + 1 < count1 ? edge + 1 : 0;
  1173. float sNext = EdgeSeparation(poly1, ref xf1, nextEdge, poly2, ref xf2);
  1174. // Find the best edge and the search direction.
  1175. int bestEdge;
  1176. float bestSeparation;
  1177. int increment;
  1178. if (sPrev > s && sPrev > sNext)
  1179. {
  1180. increment = -1;
  1181. bestEdge = prevEdge;
  1182. bestSeparation = sPrev;
  1183. }
  1184. else if (sNext > s)
  1185. {
  1186. increment = 1;
  1187. bestEdge = nextEdge;
  1188. bestSeparation = sNext;
  1189. }
  1190. else
  1191. {
  1192. edgeIndex = edge;
  1193. return s;
  1194. }
  1195. // Perform a local search for the best edge normal.
  1196. for ( ; ; )
  1197. {
  1198. if (increment == -1)
  1199. edge = bestEdge - 1 >= 0 ? bestEdge - 1 : count1 - 1;
  1200. else
  1201. edge = bestEdge + 1 < count1 ? bestEdge + 1 : 0;
  1202. s = EdgeSeparation(poly1, ref xf1, edge, poly2, ref xf2);
  1203. if (s > bestSeparation)
  1204. {
  1205. bestEdge = edge;
  1206. bestSeparation = s;
  1207. }
  1208. else
  1209. {
  1210. break;
  1211. }
  1212. }
  1213. edgeIndex = bestEdge;
  1214. return bestSeparation;
  1215. }
  1216. static void FindIncidentEdge(out FixedArray2<ClipVertex> c,
  1217. PolygonShape poly1, ref Transform xf1, int edge1,
  1218. PolygonShape poly2, ref Transform xf2)
  1219. {
  1220. c = new FixedArray2<ClipVertex>();
  1221. int count1 = poly1._vertexCount;
  1222. int count2 = poly2._vertexCount;
  1223. Debug.Assert(0 <= edge1 && edge1 < count1);
  1224. // Get the normal of the reference edge in poly2's frame.
  1225. Vector2 normal1 = MathUtils.MultiplyT(ref xf2.R, MathUtils.Multiply(ref xf1.R, poly1._normals[edge1]));
  1226. // Find the incident edge on poly2.
  1227. int index = 0;
  1228. float minDot = Settings.b2_maxFloat;
  1229. for (int i = 0; i < count2; ++i)
  1230. {
  1231. float dot = Vector2.Dot(normal1, poly2._normals[i]);
  1232. if (dot < minDot)
  1233. {
  1234. minDot = dot;
  1235. index = i;
  1236. }
  1237. }
  1238. // Build the clip vertices for the incident edge.
  1239. int i1 = index;
  1240. int i2 = i1 + 1 < count2 ? i1 + 1 : 0;
  1241. var cv0 = c[0];
  1242. cv0.v = MathUtils.Multiply(ref xf2, poly2._vertices[i1]);
  1243. cv0.id.Features.indexA = (byte)edge1;
  1244. cv0.id.Features.indexB = (byte)i1;
  1245. cv0.id.Features.typeA = (byte)ContactFeatureType.Face;
  1246. cv0.id.Features.typeB = (byte)ContactFeatureType.Vertex;
  1247. c[0] = cv0;
  1248. var cv1 = c[1];
  1249. cv1.v = MathUtils.Multiply(ref xf2, poly2._vertices[i2]);
  1250. cv1.id.Features.indexA = (byte)edge1;
  1251. cv1.id.Features.indexB = (byte)i2;
  1252. cv1.id.Features.typeA = (byte)ContactFeatureType.Face;
  1253. cv1.id.Features.typeB = (byte)ContactFeatureType.Vertex;
  1254. c[1] = cv1;
  1255. }
  1256. }
  1257. }