Collision.cs 70 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945
  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 System.Diagnostics;
  27. using System.Runtime.InteropServices;
  28. using FarseerPhysics.Collision.Shapes;
  29. using FarseerPhysics.Common;
  30. using Microsoft.Xna.Framework;
  31. namespace FarseerPhysics.Collision
  32. {
  33. internal enum ContactFeatureType : byte
  34. {
  35. Vertex = 0,
  36. Face = 1,
  37. }
  38. /// <summary>
  39. /// The features that intersect to form the contact point
  40. /// This must be 4 bytes or less.
  41. /// </summary>
  42. public struct ContactFeature
  43. {
  44. /// <summary>
  45. /// Feature index on ShapeA
  46. /// </summary>
  47. public byte IndexA;
  48. /// <summary>
  49. /// Feature index on ShapeB
  50. /// </summary>
  51. public byte IndexB;
  52. /// <summary>
  53. /// The feature type on ShapeA
  54. /// </summary>
  55. public byte TypeA;
  56. /// <summary>
  57. /// The feature type on ShapeB
  58. /// </summary>
  59. public byte TypeB;
  60. }
  61. /// <summary>
  62. /// Contact ids to facilitate warm starting.
  63. /// </summary>
  64. [StructLayout(LayoutKind.Explicit)]
  65. public struct ContactID
  66. {
  67. /// <summary>
  68. /// The features that intersect to form the contact point
  69. /// </summary>
  70. [FieldOffset(0)]
  71. public ContactFeature Features;
  72. /// <summary>
  73. /// Used to quickly compare contact ids.
  74. /// </summary>
  75. [FieldOffset(0)]
  76. public uint Key;
  77. }
  78. /// <summary>
  79. /// A manifold point is a contact point belonging to a contact
  80. /// manifold. It holds details related to the geometry and dynamics
  81. /// of the contact points.
  82. /// The local point usage depends on the manifold type:
  83. /// -ShapeType.Circles: the local center of circleB
  84. /// -SeparationFunction.FaceA: the local center of cirlceB or the clip point of polygonB
  85. /// -SeparationFunction.FaceB: the clip point of polygonA
  86. /// This structure is stored across time steps, so we keep it small.
  87. /// Note: the impulses are used for internal caching and may not
  88. /// provide reliable contact forces, especially for high speed collisions.
  89. /// </summary>
  90. public struct ManifoldPoint
  91. {
  92. /// <summary>
  93. /// Uniquely identifies a contact point between two Shapes
  94. /// </summary>
  95. public ContactID Id;
  96. public Vector2 LocalPoint;
  97. public float NormalImpulse;
  98. public float TangentImpulse;
  99. }
  100. public enum ManifoldType
  101. {
  102. Circles,
  103. FaceA,
  104. FaceB
  105. }
  106. /// <summary>
  107. /// A manifold for two touching convex Shapes.
  108. /// Box2D supports multiple types of contact:
  109. /// - clip point versus plane with radius
  110. /// - point versus point with radius (circles)
  111. /// The local point usage depends on the manifold type:
  112. /// -ShapeType.Circles: the local center of circleA
  113. /// -SeparationFunction.FaceA: the center of faceA
  114. /// -SeparationFunction.FaceB: the center of faceB
  115. /// Similarly the local normal usage:
  116. /// -ShapeType.Circles: not used
  117. /// -SeparationFunction.FaceA: the normal on polygonA
  118. /// -SeparationFunction.FaceB: the normal on polygonB
  119. /// We store contacts in this way so that position correction can
  120. /// account for movement, which is critical for continuous physics.
  121. /// All contact scenarios must be expressed in one of these types.
  122. /// This structure is stored across time steps, so we keep it small.
  123. /// </summary>
  124. public struct Manifold
  125. {
  126. /// <summary>
  127. /// Not use for Type.SeparationFunction.Points
  128. /// </summary>
  129. public Vector2 LocalNormal;
  130. /// <summary>
  131. /// Usage depends on manifold type
  132. /// </summary>
  133. public Vector2 LocalPoint;
  134. /// <summary>
  135. /// The number of manifold points
  136. /// </summary>
  137. public int PointCount;
  138. /// <summary>
  139. /// The points of contact
  140. /// </summary>
  141. public FixedArray2<ManifoldPoint> Points;
  142. public ManifoldType Type;
  143. }
  144. /// <summary>
  145. /// This is used for determining the state of contact points.
  146. /// </summary>
  147. public enum PointState
  148. {
  149. /// <summary>
  150. /// Point does not exist
  151. /// </summary>
  152. Null,
  153. /// <summary>
  154. /// Point was added in the update
  155. /// </summary>
  156. Add,
  157. /// <summary>
  158. /// Point persisted across the update
  159. /// </summary>
  160. Persist,
  161. /// <summary>
  162. /// Point was removed in the update
  163. /// </summary>
  164. Remove,
  165. }
  166. /// <summary>
  167. /// Used for computing contact manifolds.
  168. /// </summary>
  169. public struct ClipVertex
  170. {
  171. public ContactID ID;
  172. public Vector2 V;
  173. }
  174. /// <summary>
  175. /// Ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).
  176. /// </summary>
  177. public struct RayCastInput
  178. {
  179. public float MaxFraction;
  180. public Vector2 Point1, Point2;
  181. }
  182. /// <summary>
  183. /// Ray-cast output data. The ray hits at p1 + fraction * (p2 - p1), where p1 and p2
  184. /// come from RayCastInput.
  185. /// </summary>
  186. public struct RayCastOutput
  187. {
  188. public float Fraction;
  189. public Vector2 Normal;
  190. }
  191. /// <summary>
  192. /// An axis aligned bounding box.
  193. /// </summary>
  194. public struct AABB
  195. {
  196. private static DistanceInput _input = new DistanceInput();
  197. /// <summary>
  198. /// The lower vertex
  199. /// </summary>
  200. public Vector2 LowerBound;
  201. /// <summary>
  202. /// The upper vertex
  203. /// </summary>
  204. public Vector2 UpperBound;
  205. public AABB(Vector2 min, Vector2 max)
  206. : this(ref min, ref max)
  207. {
  208. }
  209. public AABB(ref Vector2 min, ref Vector2 max)
  210. {
  211. LowerBound = min;
  212. UpperBound = max;
  213. }
  214. public AABB(Vector2 center, float width, float height)
  215. {
  216. LowerBound = center - new Vector2(width / 2, height / 2);
  217. UpperBound = center + new Vector2(width / 2, height / 2);
  218. }
  219. /// <summary>
  220. /// Get the center of the AABB.
  221. /// </summary>
  222. /// <value></value>
  223. public Vector2 Center
  224. {
  225. get { return 0.5f * (LowerBound + UpperBound); }
  226. }
  227. /// <summary>
  228. /// Get the extents of the AABB (half-widths).
  229. /// </summary>
  230. /// <value></value>
  231. public Vector2 Extents
  232. {
  233. get { return 0.5f * (UpperBound - LowerBound); }
  234. }
  235. /// <summary>
  236. /// Get the perimeter length
  237. /// </summary>
  238. /// <value></value>
  239. public float Perimeter
  240. {
  241. get
  242. {
  243. float wx = UpperBound.X - LowerBound.X;
  244. float wy = UpperBound.Y - LowerBound.Y;
  245. return 2.0f * (wx + wy);
  246. }
  247. }
  248. /// <summary>
  249. /// Gets the vertices of the AABB.
  250. /// </summary>
  251. /// <value>The corners of the AABB</value>
  252. public Vertices Vertices
  253. {
  254. get
  255. {
  256. Vertices vertices = new Vertices();
  257. vertices.Add(LowerBound);
  258. vertices.Add(new Vector2(LowerBound.X, UpperBound.Y));
  259. vertices.Add(UpperBound);
  260. vertices.Add(new Vector2(UpperBound.X, LowerBound.Y));
  261. return vertices;
  262. }
  263. }
  264. /// <summary>
  265. /// first quadrant
  266. /// </summary>
  267. public AABB Q1
  268. {
  269. get { return new AABB(Center, UpperBound); }
  270. }
  271. public AABB Q2
  272. {
  273. get
  274. {
  275. return new AABB(new Vector2(LowerBound.X, Center.Y), new Vector2(Center.X, UpperBound.Y));
  276. ;
  277. }
  278. }
  279. public AABB Q3
  280. {
  281. get { return new AABB(LowerBound, Center); }
  282. }
  283. public AABB Q4
  284. {
  285. get { return new AABB(new Vector2(Center.X, LowerBound.Y), new Vector2(UpperBound.X, Center.Y)); }
  286. }
  287. public Vector2[] GetVertices()
  288. {
  289. Vector2 p1 = UpperBound;
  290. Vector2 p2 = new Vector2(UpperBound.X, LowerBound.Y);
  291. Vector2 p3 = LowerBound;
  292. Vector2 p4 = new Vector2(LowerBound.X, UpperBound.Y);
  293. return new[] { p1, p2, p3, p4 };
  294. }
  295. /// <summary>
  296. /// Verify that the bounds are sorted.
  297. /// </summary>
  298. /// <returns>
  299. /// <c>true</c> if this instance is valid; otherwise, <c>false</c>.
  300. /// </returns>
  301. public bool IsValid()
  302. {
  303. Vector2 d = UpperBound - LowerBound;
  304. bool valid = d.X >= 0.0f && d.Y >= 0.0f;
  305. valid = valid && LowerBound.IsValid() && UpperBound.IsValid();
  306. return valid;
  307. }
  308. /// <summary>
  309. /// Combine an AABB into this one.
  310. /// </summary>
  311. /// <param name="aabb">The aabb.</param>
  312. public void Combine(ref AABB aabb)
  313. {
  314. LowerBound = Vector2.Min(LowerBound, aabb.LowerBound);
  315. UpperBound = Vector2.Max(UpperBound, aabb.UpperBound);
  316. }
  317. /// <summary>
  318. /// Combine two AABBs into this one.
  319. /// </summary>
  320. /// <param name="aabb1">The aabb1.</param>
  321. /// <param name="aabb2">The aabb2.</param>
  322. public void Combine(ref AABB aabb1, ref AABB aabb2)
  323. {
  324. LowerBound = Vector2.Min(aabb1.LowerBound, aabb2.LowerBound);
  325. UpperBound = Vector2.Max(aabb1.UpperBound, aabb2.UpperBound);
  326. }
  327. /// <summary>
  328. /// Does this aabb contain the provided AABB.
  329. /// </summary>
  330. /// <param name="aabb">The aabb.</param>
  331. /// <returns>
  332. /// <c>true</c> if it contains the specified aabb; otherwise, <c>false</c>.
  333. /// </returns>
  334. public bool Contains(ref AABB aabb)
  335. {
  336. bool result = true;
  337. result = result && LowerBound.X <= aabb.LowerBound.X;
  338. result = result && LowerBound.Y <= aabb.LowerBound.Y;
  339. result = result && aabb.UpperBound.X <= UpperBound.X;
  340. result = result && aabb.UpperBound.Y <= UpperBound.Y;
  341. return result;
  342. }
  343. /// <summary>
  344. /// Determines whether the AAABB contains the specified point.
  345. /// </summary>
  346. /// <param name="point">The point.</param>
  347. /// <returns>
  348. /// <c>true</c> if it contains the specified point; otherwise, <c>false</c>.
  349. /// </returns>
  350. public bool Contains(ref Vector2 point)
  351. {
  352. //using epsilon to try and gaurd against float rounding errors.
  353. if ((point.X > (LowerBound.X + Settings.Epsilon) && point.X < (UpperBound.X - Settings.Epsilon) &&
  354. (point.Y > (LowerBound.Y + Settings.Epsilon) && point.Y < (UpperBound.Y - Settings.Epsilon))))
  355. {
  356. return true;
  357. }
  358. return false;
  359. }
  360. public static bool TestOverlap(AABB a, AABB b)
  361. {
  362. return TestOverlap(ref a, ref b);
  363. }
  364. public static bool TestOverlap(ref AABB a, ref AABB b)
  365. {
  366. Vector2 d1 = b.LowerBound - a.UpperBound;
  367. Vector2 d2 = a.LowerBound - b.UpperBound;
  368. if (d1.X > 0.0f || d1.Y > 0.0f)
  369. return false;
  370. if (d2.X > 0.0f || d2.Y > 0.0f)
  371. return false;
  372. return true;
  373. }
  374. public static bool TestOverlap(Shape shapeA, int indexA,
  375. Shape shapeB, int indexB,
  376. ref Transform xfA, ref Transform xfB)
  377. {
  378. _input.ProxyA.Set(shapeA, indexA);
  379. _input.ProxyB.Set(shapeB, indexB);
  380. _input.TransformA = xfA;
  381. _input.TransformB = xfB;
  382. _input.UseRadii = true;
  383. SimplexCache cache;
  384. DistanceOutput output;
  385. Distance.ComputeDistance(out output, out cache, _input);
  386. return output.Distance < 10.0f * Settings.Epsilon;
  387. }
  388. // From Real-time Collision Detection, p179.
  389. public bool RayCast(out RayCastOutput output, ref RayCastInput input)
  390. {
  391. output = new RayCastOutput();
  392. float tmin = -Settings.MaxFloat;
  393. float tmax = Settings.MaxFloat;
  394. Vector2 p = input.Point1;
  395. Vector2 d = input.Point2 - input.Point1;
  396. Vector2 absD = MathUtils.Abs(d);
  397. Vector2 normal = Vector2.Zero;
  398. for (int i = 0; i < 2; ++i)
  399. {
  400. float absD_i = i == 0 ? absD.X : absD.Y;
  401. float lowerBound_i = i == 0 ? LowerBound.X : LowerBound.Y;
  402. float upperBound_i = i == 0 ? UpperBound.X : UpperBound.Y;
  403. float p_i = i == 0 ? p.X : p.Y;
  404. if (absD_i < Settings.Epsilon)
  405. {
  406. // Parallel.
  407. if (p_i < lowerBound_i || upperBound_i < p_i)
  408. {
  409. return false;
  410. }
  411. }
  412. else
  413. {
  414. float d_i = i == 0 ? d.X : d.Y;
  415. float inv_d = 1.0f / d_i;
  416. float t1 = (lowerBound_i - p_i) * inv_d;
  417. float t2 = (upperBound_i - p_i) * inv_d;
  418. // Sign of the normal vector.
  419. float s = -1.0f;
  420. if (t1 > t2)
  421. {
  422. MathUtils.Swap(ref t1, ref t2);
  423. s = 1.0f;
  424. }
  425. // Push the min up
  426. if (t1 > tmin)
  427. {
  428. if (i == 0)
  429. {
  430. normal.X = s;
  431. }
  432. else
  433. {
  434. normal.Y = s;
  435. }
  436. tmin = t1;
  437. }
  438. // Pull the max down
  439. tmax = Math.Min(tmax, t2);
  440. if (tmin > tmax)
  441. {
  442. return false;
  443. }
  444. }
  445. }
  446. // Does the ray start inside the box?
  447. // Does the ray intersect beyond the max fraction?
  448. if (tmin < 0.0f || input.MaxFraction < tmin)
  449. {
  450. return false;
  451. }
  452. // Intersection.
  453. output.Fraction = tmin;
  454. output.Normal = normal;
  455. return true;
  456. }
  457. }
  458. /// <summary>
  459. /// Edge shape plus more stuff.
  460. /// </summary>
  461. public struct FatEdge
  462. {
  463. public bool HasVertex0, HasVertex3;
  464. public Vector2 Normal;
  465. public Vector2 V0, V1, V2, V3;
  466. }
  467. /// <summary>
  468. /// This lets us treate and edge shape and a polygon in the same
  469. /// way in the SAT collider.
  470. /// </summary>
  471. public class EPProxy
  472. {
  473. public Vector2 Centroid;
  474. public int Count;
  475. public Vector2[] Normals = new Vector2[Settings.MaxPolygonVertices];
  476. public Vector2[] Vertices = new Vector2[Settings.MaxPolygonVertices];
  477. }
  478. public struct EPAxis
  479. {
  480. public int Index;
  481. public float Separation;
  482. public EPAxisType Type;
  483. }
  484. public enum EPAxisType
  485. {
  486. Unknown,
  487. EdgeA,
  488. EdgeB,
  489. }
  490. public static class Collision
  491. {
  492. private static FatEdge _edgeA;
  493. private static EPProxy _proxyA = new EPProxy();
  494. private static EPProxy _proxyB = new EPProxy();
  495. private static Transform _xf;
  496. private static Vector2 _limit11, _limit12;
  497. private static Vector2 _limit21, _limit22;
  498. private static float _radius;
  499. private static Vector2[] _tmpNormals = new Vector2[2];
  500. /// <summary>
  501. /// Evaluate the manifold with supplied transforms. This assumes
  502. /// modest motion from the original state. This does not change the
  503. /// point count, impulses, etc. The radii must come from the Shapes
  504. /// that generated the manifold.
  505. /// </summary>
  506. /// <param name="manifold">The manifold.</param>
  507. /// <param name="transformA">The transform for A.</param>
  508. /// <param name="radiusA">The radius for A.</param>
  509. /// <param name="transformB">The transform for B.</param>
  510. /// <param name="radiusB">The radius for B.</param>
  511. /// <param name="normal">World vector pointing from A to B</param>
  512. /// <param name="points">Torld contact point (point of intersection).</param>
  513. public static void GetWorldManifold(ref Manifold manifold,
  514. ref Transform transformA, float radiusA,
  515. ref Transform transformB, float radiusB, out Vector2 normal,
  516. out FixedArray2<Vector2> points)
  517. {
  518. points = new FixedArray2<Vector2>();
  519. normal = Vector2.Zero;
  520. if (manifold.PointCount == 0)
  521. {
  522. normal = Vector2.UnitY;
  523. return;
  524. }
  525. switch (manifold.Type)
  526. {
  527. case ManifoldType.Circles:
  528. {
  529. Vector2 tmp = manifold.Points[0].LocalPoint;
  530. float pointAx = transformA.Position.X + transformA.R.Col1.X * manifold.LocalPoint.X +
  531. transformA.R.Col2.X * manifold.LocalPoint.Y;
  532. float pointAy = transformA.Position.Y + transformA.R.Col1.Y * manifold.LocalPoint.X +
  533. transformA.R.Col2.Y * manifold.LocalPoint.Y;
  534. float pointBx = transformB.Position.X + transformB.R.Col1.X * tmp.X +
  535. transformB.R.Col2.X * tmp.Y;
  536. float pointBy = transformB.Position.Y + transformB.R.Col1.Y * tmp.X +
  537. transformB.R.Col2.Y * tmp.Y;
  538. normal.X = 1;
  539. normal.Y = 0;
  540. float result = (pointAx - pointBx) * (pointAx - pointBx) +
  541. (pointAy - pointBy) * (pointAy - pointBy);
  542. if (result > Settings.Epsilon * Settings.Epsilon)
  543. {
  544. float tmpNormalx = pointBx - pointAx;
  545. float tmpNormaly = pointBy - pointAy;
  546. float factor = 1f / (float)Math.Sqrt(tmpNormalx * tmpNormalx + tmpNormaly * tmpNormaly);
  547. normal.X = tmpNormalx * factor;
  548. normal.Y = tmpNormaly * factor;
  549. }
  550. Vector2 c = Vector2.Zero;
  551. c.X = (pointAx + radiusA * normal.X) + (pointBx - radiusB * normal.X);
  552. c.Y = (pointAy + radiusA * normal.Y) + (pointBy - radiusB * normal.Y);
  553. points[0] = 0.5f * c;
  554. }
  555. break;
  556. case ManifoldType.FaceA:
  557. {
  558. normal.X = transformA.R.Col1.X * manifold.LocalNormal.X +
  559. transformA.R.Col2.X * manifold.LocalNormal.Y;
  560. normal.Y = transformA.R.Col1.Y * manifold.LocalNormal.X +
  561. transformA.R.Col2.Y * manifold.LocalNormal.Y;
  562. float planePointx = transformA.Position.X + transformA.R.Col1.X * manifold.LocalPoint.X +
  563. transformA.R.Col2.X * manifold.LocalPoint.Y;
  564. float planePointy = transformA.Position.Y + transformA.R.Col1.Y * manifold.LocalPoint.X +
  565. transformA.R.Col2.Y * manifold.LocalPoint.Y;
  566. for (int i = 0; i < manifold.PointCount; ++i)
  567. {
  568. Vector2 tmp = manifold.Points[i].LocalPoint;
  569. float clipPointx = transformB.Position.X + transformB.R.Col1.X * tmp.X +
  570. transformB.R.Col2.X * tmp.Y;
  571. float clipPointy = transformB.Position.Y + transformB.R.Col1.Y * tmp.X +
  572. transformB.R.Col2.Y * tmp.Y;
  573. float value = (clipPointx - planePointx) * normal.X + (clipPointy - planePointy) * normal.Y;
  574. Vector2 c = Vector2.Zero;
  575. c.X = (clipPointx + (radiusA - value) * normal.X) + (clipPointx - radiusB * normal.X);
  576. c.Y = (clipPointy + (radiusA - value) * normal.Y) + (clipPointy - radiusB * normal.Y);
  577. points[i] = 0.5f * c;
  578. }
  579. }
  580. break;
  581. case ManifoldType.FaceB:
  582. {
  583. normal.X = transformB.R.Col1.X * manifold.LocalNormal.X +
  584. transformB.R.Col2.X * manifold.LocalNormal.Y;
  585. normal.Y = transformB.R.Col1.Y * manifold.LocalNormal.X +
  586. transformB.R.Col2.Y * manifold.LocalNormal.Y;
  587. float planePointx = transformB.Position.X + transformB.R.Col1.X * manifold.LocalPoint.X +
  588. transformB.R.Col2.X * manifold.LocalPoint.Y;
  589. float planePointy = transformB.Position.Y + transformB.R.Col1.Y * manifold.LocalPoint.X +
  590. transformB.R.Col2.Y * manifold.LocalPoint.Y;
  591. for (int i = 0; i < manifold.PointCount; ++i)
  592. {
  593. Vector2 tmp = manifold.Points[i].LocalPoint;
  594. float clipPointx = transformA.Position.X + transformA.R.Col1.X * tmp.X +
  595. transformA.R.Col2.X * tmp.Y;
  596. float clipPointy = transformA.Position.Y + transformA.R.Col1.Y * tmp.X +
  597. transformA.R.Col2.Y * tmp.Y;
  598. float value = (clipPointx - planePointx) * normal.X + (clipPointy - planePointy) * normal.Y;
  599. Vector2 c = Vector2.Zero;
  600. c.X = (clipPointx - radiusA * normal.X) + (clipPointx + (radiusB - value) * normal.X);
  601. c.Y = (clipPointy - radiusA * normal.Y) + (clipPointy + (radiusB - value) * normal.Y);
  602. points[i] = 0.5f * c;
  603. }
  604. // Ensure normal points from A to B.
  605. normal *= -1;
  606. }
  607. break;
  608. default:
  609. normal = Vector2.UnitY;
  610. break;
  611. }
  612. }
  613. public static void GetPointStates(out FixedArray2<PointState> state1, out FixedArray2<PointState> state2,
  614. ref Manifold manifold1, ref Manifold manifold2)
  615. {
  616. state1 = new FixedArray2<PointState>();
  617. state2 = new FixedArray2<PointState>();
  618. // Detect persists and removes.
  619. for (int i = 0; i < manifold1.PointCount; ++i)
  620. {
  621. ContactID id = manifold1.Points[i].Id;
  622. state1[i] = PointState.Remove;
  623. for (int j = 0; j < manifold2.PointCount; ++j)
  624. {
  625. if (manifold2.Points[j].Id.Key == id.Key)
  626. {
  627. state1[i] = PointState.Persist;
  628. break;
  629. }
  630. }
  631. }
  632. // Detect persists and adds.
  633. for (int i = 0; i < manifold2.PointCount; ++i)
  634. {
  635. ContactID id = manifold2.Points[i].Id;
  636. state2[i] = PointState.Add;
  637. for (int j = 0; j < manifold1.PointCount; ++j)
  638. {
  639. if (manifold1.Points[j].Id.Key == id.Key)
  640. {
  641. state2[i] = PointState.Persist;
  642. break;
  643. }
  644. }
  645. }
  646. }
  647. /// Compute the collision manifold between two circles.
  648. public static void CollideCircles(ref Manifold manifold,
  649. CircleShape circleA, ref Transform xfA,
  650. CircleShape circleB, ref Transform xfB)
  651. {
  652. manifold.PointCount = 0;
  653. float pAx = xfA.Position.X + xfA.R.Col1.X * circleA.Position.X + xfA.R.Col2.X * circleA.Position.Y;
  654. float pAy = xfA.Position.Y + xfA.R.Col1.Y * circleA.Position.X + xfA.R.Col2.Y * circleA.Position.Y;
  655. float pBx = xfB.Position.X + xfB.R.Col1.X * circleB.Position.X + xfB.R.Col2.X * circleB.Position.Y;
  656. float pBy = xfB.Position.Y + xfB.R.Col1.Y * circleB.Position.X + xfB.R.Col2.Y * circleB.Position.Y;
  657. float distSqr = (pBx - pAx) * (pBx - pAx) + (pBy - pAy) * (pBy - pAy);
  658. float radius = circleA.Radius + circleB.Radius;
  659. if (distSqr > radius * radius)
  660. {
  661. return;
  662. }
  663. manifold.Type = ManifoldType.Circles;
  664. manifold.LocalPoint = circleA.Position;
  665. manifold.LocalNormal = Vector2.Zero;
  666. manifold.PointCount = 1;
  667. ManifoldPoint p0 = manifold.Points[0];
  668. p0.LocalPoint = circleB.Position;
  669. p0.Id.Key = 0;
  670. manifold.Points[0] = p0;
  671. }
  672. /// <summary>
  673. /// Compute the collision manifold between a polygon and a circle.
  674. /// </summary>
  675. /// <param name="manifold">The manifold.</param>
  676. /// <param name="polygonA">The polygon A.</param>
  677. /// <param name="transformA">The transform of A.</param>
  678. /// <param name="circleB">The circle B.</param>
  679. /// <param name="transformB">The transform of B.</param>
  680. public static void CollidePolygonAndCircle(ref Manifold manifold,
  681. PolygonShape polygonA, ref Transform transformA,
  682. CircleShape circleB, ref Transform transformB)
  683. {
  684. manifold.PointCount = 0;
  685. // Compute circle position in the frame of the polygon.
  686. Vector2 c =
  687. new Vector2(
  688. transformB.Position.X + transformB.R.Col1.X * circleB.Position.X +
  689. transformB.R.Col2.X * circleB.Position.Y,
  690. transformB.Position.Y + transformB.R.Col1.Y * circleB.Position.X +
  691. transformB.R.Col2.Y * circleB.Position.Y);
  692. Vector2 cLocal =
  693. new Vector2(
  694. (c.X - transformA.Position.X) * transformA.R.Col1.X +
  695. (c.Y - transformA.Position.Y) * transformA.R.Col1.Y,
  696. (c.X - transformA.Position.X) * transformA.R.Col2.X +
  697. (c.Y - transformA.Position.Y) * transformA.R.Col2.Y);
  698. // Find the min separating edge.
  699. int normalIndex = 0;
  700. float separation = -Settings.MaxFloat;
  701. float radius = polygonA.Radius + circleB.Radius;
  702. int vertexCount = polygonA.Vertices.Count;
  703. for (int i = 0; i < vertexCount; ++i)
  704. {
  705. Vector2 value1 = polygonA.Normals[i];
  706. Vector2 value2 = cLocal - polygonA.Vertices[i];
  707. float s = value1.X * value2.X + value1.Y * value2.Y;
  708. if (s > radius)
  709. {
  710. // Early out.
  711. return;
  712. }
  713. if (s > separation)
  714. {
  715. separation = s;
  716. normalIndex = i;
  717. }
  718. }
  719. // Vertices that subtend the incident face.
  720. int vertIndex1 = normalIndex;
  721. int vertIndex2 = vertIndex1 + 1 < vertexCount ? vertIndex1 + 1 : 0;
  722. Vector2 v1 = polygonA.Vertices[vertIndex1];
  723. Vector2 v2 = polygonA.Vertices[vertIndex2];
  724. // If the center is inside the polygon ...
  725. if (separation < Settings.Epsilon)
  726. {
  727. manifold.PointCount = 1;
  728. manifold.Type = ManifoldType.FaceA;
  729. manifold.LocalNormal = polygonA.Normals[normalIndex];
  730. manifold.LocalPoint = 0.5f * (v1 + v2);
  731. ManifoldPoint p0 = manifold.Points[0];
  732. p0.LocalPoint = circleB.Position;
  733. p0.Id.Key = 0;
  734. manifold.Points[0] = p0;
  735. return;
  736. }
  737. // Compute barycentric coordinates
  738. float u1 = (cLocal.X - v1.X) * (v2.X - v1.X) + (cLocal.Y - v1.Y) * (v2.Y - v1.Y);
  739. float u2 = (cLocal.X - v2.X) * (v1.X - v2.X) + (cLocal.Y - v2.Y) * (v1.Y - v2.Y);
  740. if (u1 <= 0.0f)
  741. {
  742. float r = (cLocal.X - v1.X) * (cLocal.X - v1.X) + (cLocal.Y - v1.Y) * (cLocal.Y - v1.Y);
  743. if (r > radius * radius)
  744. {
  745. return;
  746. }
  747. manifold.PointCount = 1;
  748. manifold.Type = ManifoldType.FaceA;
  749. manifold.LocalNormal = cLocal - v1;
  750. float factor = 1f /
  751. (float)
  752. Math.Sqrt(manifold.LocalNormal.X * manifold.LocalNormal.X +
  753. manifold.LocalNormal.Y * manifold.LocalNormal.Y);
  754. manifold.LocalNormal.X = manifold.LocalNormal.X * factor;
  755. manifold.LocalNormal.Y = manifold.LocalNormal.Y * factor;
  756. manifold.LocalPoint = v1;
  757. ManifoldPoint p0b = manifold.Points[0];
  758. p0b.LocalPoint = circleB.Position;
  759. p0b.Id.Key = 0;
  760. manifold.Points[0] = p0b;
  761. }
  762. else if (u2 <= 0.0f)
  763. {
  764. float r = (cLocal.X - v2.X) * (cLocal.X - v2.X) + (cLocal.Y - v2.Y) * (cLocal.Y - v2.Y);
  765. if (r > radius * radius)
  766. {
  767. return;
  768. }
  769. manifold.PointCount = 1;
  770. manifold.Type = ManifoldType.FaceA;
  771. manifold.LocalNormal = cLocal - v2;
  772. float factor = 1f /
  773. (float)
  774. Math.Sqrt(manifold.LocalNormal.X * manifold.LocalNormal.X +
  775. manifold.LocalNormal.Y * manifold.LocalNormal.Y);
  776. manifold.LocalNormal.X = manifold.LocalNormal.X * factor;
  777. manifold.LocalNormal.Y = manifold.LocalNormal.Y * factor;
  778. manifold.LocalPoint = v2;
  779. ManifoldPoint p0c = manifold.Points[0];
  780. p0c.LocalPoint = circleB.Position;
  781. p0c.Id.Key = 0;
  782. manifold.Points[0] = p0c;
  783. }
  784. else
  785. {
  786. Vector2 faceCenter = 0.5f * (v1 + v2);
  787. Vector2 value1 = cLocal - faceCenter;
  788. Vector2 value2 = polygonA.Normals[vertIndex1];
  789. float separation2 = value1.X * value2.X + value1.Y * value2.Y;
  790. if (separation2 > radius)
  791. {
  792. return;
  793. }
  794. manifold.PointCount = 1;
  795. manifold.Type = ManifoldType.FaceA;
  796. manifold.LocalNormal = polygonA.Normals[vertIndex1];
  797. manifold.LocalPoint = faceCenter;
  798. ManifoldPoint p0d = manifold.Points[0];
  799. p0d.LocalPoint = circleB.Position;
  800. p0d.Id.Key = 0;
  801. manifold.Points[0] = p0d;
  802. }
  803. }
  804. /// <summary>
  805. /// Compute the collision manifold between two polygons.
  806. /// </summary>
  807. /// <param name="manifold">The manifold.</param>
  808. /// <param name="polyA">The poly A.</param>
  809. /// <param name="transformA">The transform A.</param>
  810. /// <param name="polyB">The poly B.</param>
  811. /// <param name="transformB">The transform B.</param>
  812. public static void CollidePolygons(ref Manifold manifold,
  813. PolygonShape polyA, ref Transform transformA,
  814. PolygonShape polyB, ref Transform transformB)
  815. {
  816. manifold.PointCount = 0;
  817. float totalRadius = polyA.Radius + polyB.Radius;
  818. int edgeA = 0;
  819. float separationA = FindMaxSeparation(out edgeA, polyA, ref transformA, polyB, ref transformB);
  820. if (separationA > totalRadius)
  821. return;
  822. int edgeB = 0;
  823. float separationB = FindMaxSeparation(out edgeB, polyB, ref transformB, polyA, ref transformA);
  824. if (separationB > totalRadius)
  825. return;
  826. PolygonShape poly1; // reference polygon
  827. PolygonShape poly2; // incident polygon
  828. Transform xf1, xf2;
  829. int edge1; // reference edge
  830. bool flip;
  831. const float k_relativeTol = 0.98f;
  832. const float k_absoluteTol = 0.001f;
  833. if (separationB > k_relativeTol * separationA + k_absoluteTol)
  834. {
  835. poly1 = polyB;
  836. poly2 = polyA;
  837. xf1 = transformB;
  838. xf2 = transformA;
  839. edge1 = edgeB;
  840. manifold.Type = ManifoldType.FaceB;
  841. flip = true;
  842. }
  843. else
  844. {
  845. poly1 = polyA;
  846. poly2 = polyB;
  847. xf1 = transformA;
  848. xf2 = transformB;
  849. edge1 = edgeA;
  850. manifold.Type = ManifoldType.FaceA;
  851. flip = false;
  852. }
  853. FixedArray2<ClipVertex> incidentEdge;
  854. FindIncidentEdge(out incidentEdge, poly1, ref xf1, edge1, poly2, ref xf2);
  855. int count1 = poly1.Vertices.Count;
  856. int iv1 = edge1;
  857. int iv2 = edge1 + 1 < count1 ? edge1 + 1 : 0;
  858. Vector2 v11 = poly1.Vertices[iv1];
  859. Vector2 v12 = poly1.Vertices[iv2];
  860. float localTangentX = v12.X - v11.X;
  861. float localTangentY = v12.Y - v11.Y;
  862. float factor = 1f / (float)Math.Sqrt(localTangentX * localTangentX + localTangentY * localTangentY);
  863. localTangentX = localTangentX * factor;
  864. localTangentY = localTangentY * factor;
  865. Vector2 localNormal = new Vector2(localTangentY, -localTangentX);
  866. Vector2 planePoint = 0.5f * (v11 + v12);
  867. Vector2 tangent = new Vector2(xf1.R.Col1.X * localTangentX + xf1.R.Col2.X * localTangentY,
  868. xf1.R.Col1.Y * localTangentX + xf1.R.Col2.Y * localTangentY);
  869. float normalx = tangent.Y;
  870. float normaly = -tangent.X;
  871. v11 = new Vector2(xf1.Position.X + xf1.R.Col1.X * v11.X + xf1.R.Col2.X * v11.Y,
  872. xf1.Position.Y + xf1.R.Col1.Y * v11.X + xf1.R.Col2.Y * v11.Y);
  873. v12 = new Vector2(xf1.Position.X + xf1.R.Col1.X * v12.X + xf1.R.Col2.X * v12.Y,
  874. xf1.Position.Y + xf1.R.Col1.Y * v12.X + xf1.R.Col2.Y * v12.Y);
  875. // Face offset.
  876. float frontOffset = normalx * v11.X + normaly * v11.Y;
  877. // Side offsets, extended by polytope skin thickness.
  878. float sideOffset1 = -(tangent.X * v11.X + tangent.Y * v11.Y) + totalRadius;
  879. float sideOffset2 = tangent.X * v12.X + tangent.Y * v12.Y + totalRadius;
  880. // Clip incident edge against extruded edge1 side edges.
  881. FixedArray2<ClipVertex> clipPoints1;
  882. FixedArray2<ClipVertex> clipPoints2;
  883. // Clip to box side 1
  884. int np = ClipSegmentToLine(out clipPoints1, ref incidentEdge, -tangent, sideOffset1, iv1);
  885. if (np < 2)
  886. return;
  887. // Clip to negative box side 1
  888. np = ClipSegmentToLine(out clipPoints2, ref clipPoints1, tangent, sideOffset2, iv2);
  889. if (np < 2)
  890. {
  891. return;
  892. }
  893. // Now clipPoints2 contains the clipped points.
  894. manifold.LocalNormal = localNormal;
  895. manifold.LocalPoint = planePoint;
  896. int pointCount = 0;
  897. for (int i = 0; i < Settings.MaxManifoldPoints; ++i)
  898. {
  899. Vector2 value = clipPoints2[i].V;
  900. float separation = normalx * value.X + normaly * value.Y - frontOffset;
  901. if (separation <= totalRadius)
  902. {
  903. ManifoldPoint cp = manifold.Points[pointCount];
  904. Vector2 tmp = clipPoints2[i].V;
  905. float tmp1X = tmp.X - xf2.Position.X;
  906. float tmp1Y = tmp.Y - xf2.Position.Y;
  907. cp.LocalPoint.X = tmp1X * xf2.R.Col1.X + tmp1Y * xf2.R.Col1.Y;
  908. cp.LocalPoint.Y = tmp1X * xf2.R.Col2.X + tmp1Y * xf2.R.Col2.Y;
  909. cp.Id = clipPoints2[i].ID;
  910. if (flip)
  911. {
  912. // Swap features
  913. ContactFeature cf = cp.Id.Features;
  914. cp.Id.Features.IndexA = cf.IndexB;
  915. cp.Id.Features.IndexB = cf.IndexA;
  916. cp.Id.Features.TypeA = cf.TypeB;
  917. cp.Id.Features.TypeB = cf.TypeA;
  918. }
  919. manifold.Points[pointCount] = cp;
  920. ++pointCount;
  921. }
  922. }
  923. manifold.PointCount = pointCount;
  924. }
  925. /// <summary>
  926. /// Compute contact points for edge versus circle.
  927. /// This accounts for edge connectivity.
  928. /// </summary>
  929. /// <param name="manifold">The manifold.</param>
  930. /// <param name="edgeA">The edge A.</param>
  931. /// <param name="transformA">The transform A.</param>
  932. /// <param name="circleB">The circle B.</param>
  933. /// <param name="transformB">The transform B.</param>
  934. public static void CollideEdgeAndCircle(ref Manifold manifold,
  935. EdgeShape edgeA, ref Transform transformA,
  936. CircleShape circleB, ref Transform transformB)
  937. {
  938. manifold.PointCount = 0;
  939. // Compute circle in frame of edge
  940. Vector2 Q = MathUtils.MultiplyT(ref transformA, MathUtils.Multiply(ref transformB, ref circleB._position));
  941. Vector2 A = edgeA.Vertex1, B = edgeA.Vertex2;
  942. Vector2 e = B - A;
  943. // Barycentric coordinates
  944. float u = Vector2.Dot(e, B - Q);
  945. float v = Vector2.Dot(e, Q - A);
  946. float radius = edgeA.Radius + circleB.Radius;
  947. ContactFeature cf;
  948. cf.IndexB = 0;
  949. cf.TypeB = (byte)ContactFeatureType.Vertex;
  950. Vector2 P, d;
  951. // Region A
  952. if (v <= 0.0f)
  953. {
  954. P = A;
  955. d = Q - P;
  956. float dd;
  957. Vector2.Dot(ref d, ref d, out dd);
  958. if (dd > radius * radius)
  959. {
  960. return;
  961. }
  962. // Is there an edge connected to A?
  963. if (edgeA.HasVertex0)
  964. {
  965. Vector2 A1 = edgeA.Vertex0;
  966. Vector2 B1 = A;
  967. Vector2 e1 = B1 - A1;
  968. float u1 = Vector2.Dot(e1, B1 - Q);
  969. // Is the circle in Region AB of the previous edge?
  970. if (u1 > 0.0f)
  971. {
  972. return;
  973. }
  974. }
  975. cf.IndexA = 0;
  976. cf.TypeA = (byte)ContactFeatureType.Vertex;
  977. manifold.PointCount = 1;
  978. manifold.Type = ManifoldType.Circles;
  979. manifold.LocalNormal = Vector2.Zero;
  980. manifold.LocalPoint = P;
  981. ManifoldPoint mp = new ManifoldPoint();
  982. mp.Id.Key = 0;
  983. mp.Id.Features = cf;
  984. mp.LocalPoint = circleB.Position;
  985. manifold.Points[0] = mp;
  986. return;
  987. }
  988. // Region B
  989. if (u <= 0.0f)
  990. {
  991. P = B;
  992. d = Q - P;
  993. float dd;
  994. Vector2.Dot(ref d, ref d, out dd);
  995. if (dd > radius * radius)
  996. {
  997. return;
  998. }
  999. // Is there an edge connected to B?
  1000. if (edgeA.HasVertex3)
  1001. {
  1002. Vector2 B2 = edgeA.Vertex3;
  1003. Vector2 A2 = B;
  1004. Vector2 e2 = B2 - A2;
  1005. float v2 = Vector2.Dot(e2, Q - A2);
  1006. // Is the circle in Region AB of the next edge?
  1007. if (v2 > 0.0f)
  1008. {
  1009. return;
  1010. }
  1011. }
  1012. cf.IndexA = 1;
  1013. cf.TypeA = (byte)ContactFeatureType.Vertex;
  1014. manifold.PointCount = 1;
  1015. manifold.Type = ManifoldType.Circles;
  1016. manifold.LocalNormal = Vector2.Zero;
  1017. manifold.LocalPoint = P;
  1018. ManifoldPoint mp = new ManifoldPoint();
  1019. mp.Id.Key = 0;
  1020. mp.Id.Features = cf;
  1021. mp.LocalPoint = circleB.Position;
  1022. manifold.Points[0] = mp;
  1023. return;
  1024. }
  1025. // Region AB
  1026. float den;
  1027. Vector2.Dot(ref e, ref e, out den);
  1028. Debug.Assert(den > 0.0f);
  1029. P = (1.0f / den) * (u * A + v * B);
  1030. d = Q - P;
  1031. float dd2;
  1032. Vector2.Dot(ref d, ref d, out dd2);
  1033. if (dd2 > radius * radius)
  1034. {
  1035. return;
  1036. }
  1037. Vector2 n = new Vector2(-e.Y, e.X);
  1038. if (Vector2.Dot(n, Q - A) < 0.0f)
  1039. {
  1040. n = new Vector2(-n.X, -n.Y);
  1041. }
  1042. n.Normalize();
  1043. cf.IndexA = 0;
  1044. cf.TypeA = (byte)ContactFeatureType.Face;
  1045. manifold.PointCount = 1;
  1046. manifold.Type = ManifoldType.FaceA;
  1047. manifold.LocalNormal = n;
  1048. manifold.LocalPoint = A;
  1049. ManifoldPoint mp2 = new ManifoldPoint();
  1050. mp2.Id.Key = 0;
  1051. mp2.Id.Features = cf;
  1052. mp2.LocalPoint = circleB.Position;
  1053. manifold.Points[0] = mp2;
  1054. }
  1055. /// <summary>
  1056. /// Collides and edge and a polygon, taking into account edge adjacency.
  1057. /// </summary>
  1058. /// <param name="manifold">The manifold.</param>
  1059. /// <param name="edgeA">The edge A.</param>
  1060. /// <param name="xfA">The xf A.</param>
  1061. /// <param name="polygonB">The polygon B.</param>
  1062. /// <param name="xfB">The xf B.</param>
  1063. public static void CollideEdgeAndPolygon(ref Manifold manifold,
  1064. EdgeShape edgeA, ref Transform xfA,
  1065. PolygonShape polygonB, ref Transform xfB)
  1066. {
  1067. MathUtils.MultiplyT(ref xfA, ref xfB, out _xf);
  1068. // Edge geometry
  1069. _edgeA.V0 = edgeA.Vertex0;
  1070. _edgeA.V1 = edgeA.Vertex1;
  1071. _edgeA.V2 = edgeA.Vertex2;
  1072. _edgeA.V3 = edgeA.Vertex3;
  1073. Vector2 e = _edgeA.V2 - _edgeA.V1;
  1074. // Normal points outwards in CCW order.
  1075. _edgeA.Normal = new Vector2(e.Y, -e.X);
  1076. _edgeA.Normal.Normalize();
  1077. _edgeA.HasVertex0 = edgeA.HasVertex0;
  1078. _edgeA.HasVertex3 = edgeA.HasVertex3;
  1079. // Proxy for edge
  1080. _proxyA.Vertices[0] = _edgeA.V1;
  1081. _proxyA.Vertices[1] = _edgeA.V2;
  1082. _proxyA.Normals[0] = _edgeA.Normal;
  1083. _proxyA.Normals[1] = -_edgeA.Normal;
  1084. _proxyA.Centroid = 0.5f * (_edgeA.V1 + _edgeA.V2);
  1085. _proxyA.Count = 2;
  1086. // Proxy for polygon
  1087. _proxyB.Count = polygonB.Vertices.Count;
  1088. _proxyB.Centroid = MathUtils.Multiply(ref _xf, ref polygonB.MassData.Centroid);
  1089. for (int i = 0; i < polygonB.Vertices.Count; ++i)
  1090. {
  1091. _proxyB.Vertices[i] = MathUtils.Multiply(ref _xf, polygonB.Vertices[i]);
  1092. _proxyB.Normals[i] = MathUtils.Multiply(ref _xf.R, polygonB.Normals[i]);
  1093. }
  1094. _radius = 2.0f * Settings.PolygonRadius;
  1095. _limit11 = Vector2.Zero;
  1096. _limit12 = Vector2.Zero;
  1097. _limit21 = Vector2.Zero;
  1098. _limit22 = Vector2.Zero;
  1099. //Collide(ref manifold); inline start
  1100. manifold.PointCount = 0;
  1101. //ComputeAdjacency(); inline start
  1102. Vector2 v0 = _edgeA.V0;
  1103. Vector2 v1 = _edgeA.V1;
  1104. Vector2 v2 = _edgeA.V2;
  1105. Vector2 v3 = _edgeA.V3;
  1106. // Determine allowable the normal regions based on adjacency.
  1107. // Note: it may be possible that no normal is admissable.
  1108. Vector2 centerB = _proxyB.Centroid;
  1109. if (_edgeA.HasVertex0)
  1110. {
  1111. Vector2 e0 = v1 - v0;
  1112. Vector2 e1 = v2 - v1;
  1113. Vector2 n0 = new Vector2(e0.Y, -e0.X);
  1114. Vector2 n1 = new Vector2(e1.Y, -e1.X);
  1115. n0.Normalize();
  1116. n1.Normalize();
  1117. bool convex = MathUtils.Cross(n0, n1) >= 0.0f;
  1118. bool front0 = Vector2.Dot(n0, centerB - v0) >= 0.0f;
  1119. bool front1 = Vector2.Dot(n1, centerB - v1) >= 0.0f;
  1120. if (convex)
  1121. {
  1122. if (front0 || front1)
  1123. {
  1124. _limit11 = n1;
  1125. _limit12 = n0;
  1126. }
  1127. else
  1128. {
  1129. _limit11 = -n1;
  1130. _limit12 = -n0;
  1131. }
  1132. }
  1133. else
  1134. {
  1135. if (front0 && front1)
  1136. {
  1137. _limit11 = n0;
  1138. _limit12 = n1;
  1139. }
  1140. else
  1141. {
  1142. _limit11 = -n0;
  1143. _limit12 = -n1;
  1144. }
  1145. }
  1146. }
  1147. else
  1148. {
  1149. _limit11 = Vector2.Zero;
  1150. _limit12 = Vector2.Zero;
  1151. }
  1152. if (_edgeA.HasVertex3)
  1153. {
  1154. Vector2 e1 = v2 - v1;
  1155. Vector2 e2 = v3 - v2;
  1156. Vector2 n1 = new Vector2(e1.Y, -e1.X);
  1157. Vector2 n2 = new Vector2(e2.Y, -e2.X);
  1158. n1.Normalize();
  1159. n2.Normalize();
  1160. bool convex = MathUtils.Cross(n1, n2) >= 0.0f;
  1161. bool front1 = Vector2.Dot(n1, centerB - v1) >= 0.0f;
  1162. bool front2 = Vector2.Dot(n2, centerB - v2) >= 0.0f;
  1163. if (convex)
  1164. {
  1165. if (front1 || front2)
  1166. {
  1167. _limit21 = n2;
  1168. _limit22 = n1;
  1169. }
  1170. else
  1171. {
  1172. _limit21 = -n2;
  1173. _limit22 = -n1;
  1174. }
  1175. }
  1176. else
  1177. {
  1178. if (front1 && front2)
  1179. {
  1180. _limit21 = n1;
  1181. _limit22 = n2;
  1182. }
  1183. else
  1184. {
  1185. _limit21 = -n1;
  1186. _limit22 = -n2;
  1187. }
  1188. }
  1189. }
  1190. else
  1191. {
  1192. _limit21 = Vector2.Zero;
  1193. _limit22 = Vector2.Zero;
  1194. }
  1195. //ComputeAdjacency(); inline end
  1196. //EPAxis edgeAxis = ComputeEdgeSeparation(); inline start
  1197. EPAxis edgeAxis = ComputeEdgeSeparation();
  1198. // If no valid normal can be found than this edge should not collide.
  1199. // This can happen on the middle edge of a 3-edge zig-zag chain.
  1200. if (edgeAxis.Type == EPAxisType.Unknown)
  1201. {
  1202. return;
  1203. }
  1204. if (edgeAxis.Separation > _radius)
  1205. {
  1206. return;
  1207. }
  1208. EPAxis polygonAxis = ComputePolygonSeparation();
  1209. if (polygonAxis.Type != EPAxisType.Unknown && polygonAxis.Separation > _radius)
  1210. {
  1211. return;
  1212. }
  1213. // Use hysteresis for jitter reduction.
  1214. const float k_relativeTol = 0.98f;
  1215. const float k_absoluteTol = 0.001f;
  1216. EPAxis primaryAxis;
  1217. if (polygonAxis.Type == EPAxisType.Unknown)
  1218. {
  1219. primaryAxis = edgeAxis;
  1220. }
  1221. else if (polygonAxis.Separation > k_relativeTol * edgeAxis.Separation + k_absoluteTol)
  1222. {
  1223. primaryAxis = polygonAxis;
  1224. }
  1225. else
  1226. {
  1227. primaryAxis = edgeAxis;
  1228. }
  1229. EPProxy proxy1;
  1230. EPProxy proxy2;
  1231. FixedArray2<ClipVertex> incidentEdge = new FixedArray2<ClipVertex>();
  1232. if (primaryAxis.Type == EPAxisType.EdgeA)
  1233. {
  1234. proxy1 = _proxyA;
  1235. proxy2 = _proxyB;
  1236. manifold.Type = ManifoldType.FaceA;
  1237. }
  1238. else
  1239. {
  1240. proxy1 = _proxyB;
  1241. proxy2 = _proxyA;
  1242. manifold.Type = ManifoldType.FaceB;
  1243. }
  1244. int edge1 = primaryAxis.Index;
  1245. FindIncidentEdge(ref incidentEdge, proxy1, primaryAxis.Index, proxy2);
  1246. int count1 = proxy1.Count;
  1247. int iv1 = edge1;
  1248. int iv2 = edge1 + 1 < count1 ? edge1 + 1 : 0;
  1249. Vector2 v11 = proxy1.Vertices[iv1];
  1250. Vector2 v12 = proxy1.Vertices[iv2];
  1251. Vector2 tangent = v12 - v11;
  1252. tangent.Normalize();
  1253. Vector2 normal = MathUtils.Cross(tangent, 1.0f);
  1254. Vector2 planePoint = 0.5f * (v11 + v12);
  1255. // Face offset.
  1256. float frontOffset = Vector2.Dot(normal, v11);
  1257. // Side offsets, extended by polytope skin thickness.
  1258. float sideOffset1 = -Vector2.Dot(tangent, v11) + _radius;
  1259. float sideOffset2 = Vector2.Dot(tangent, v12) + _radius;
  1260. // Clip incident edge against extruded edge1 side edges.
  1261. FixedArray2<ClipVertex> clipPoints1;
  1262. FixedArray2<ClipVertex> clipPoints2;
  1263. int np;
  1264. // Clip to box side 1
  1265. np = ClipSegmentToLine(out clipPoints1, ref incidentEdge, -tangent, sideOffset1, iv1);
  1266. if (np < Settings.MaxManifoldPoints)
  1267. {
  1268. return;
  1269. }
  1270. // Clip to negative box side 1
  1271. np = ClipSegmentToLine(out clipPoints2, ref clipPoints1, tangent, sideOffset2, iv2);
  1272. if (np < Settings.MaxManifoldPoints)
  1273. {
  1274. return;
  1275. }
  1276. // Now clipPoints2 contains the clipped points.
  1277. if (primaryAxis.Type == EPAxisType.EdgeA)
  1278. {
  1279. manifold.LocalNormal = normal;
  1280. manifold.LocalPoint = planePoint;
  1281. }
  1282. else
  1283. {
  1284. manifold.LocalNormal = MathUtils.MultiplyT(ref _xf.R, ref normal);
  1285. manifold.LocalPoint = MathUtils.MultiplyT(ref _xf, ref planePoint);
  1286. }
  1287. int pointCount = 0;
  1288. for (int i1 = 0; i1 < Settings.MaxManifoldPoints; ++i1)
  1289. {
  1290. float separation = Vector2.Dot(normal, clipPoints2[i1].V) - frontOffset;
  1291. if (separation <= _radius)
  1292. {
  1293. ManifoldPoint cp = manifold.Points[pointCount];
  1294. if (primaryAxis.Type == EPAxisType.EdgeA)
  1295. {
  1296. cp.LocalPoint = MathUtils.MultiplyT(ref _xf, clipPoints2[i1].V);
  1297. cp.Id = clipPoints2[i1].ID;
  1298. }
  1299. else
  1300. {
  1301. cp.LocalPoint = clipPoints2[i1].V;
  1302. cp.Id.Features.TypeA = clipPoints2[i1].ID.Features.TypeB;
  1303. cp.Id.Features.TypeB = clipPoints2[i1].ID.Features.TypeA;
  1304. cp.Id.Features.IndexA = clipPoints2[i1].ID.Features.IndexB;
  1305. cp.Id.Features.IndexB = clipPoints2[i1].ID.Features.IndexA;
  1306. }
  1307. manifold.Points[pointCount] = cp;
  1308. ++pointCount;
  1309. }
  1310. }
  1311. manifold.PointCount = pointCount;
  1312. //Collide(ref manifold); inline end
  1313. }
  1314. private static EPAxis ComputeEdgeSeparation()
  1315. {
  1316. // EdgeA separation
  1317. EPAxis bestAxis;
  1318. bestAxis.Type = EPAxisType.Unknown;
  1319. bestAxis.Index = -1;
  1320. bestAxis.Separation = -Settings.MaxFloat;
  1321. _tmpNormals[0] = _edgeA.Normal;
  1322. _tmpNormals[1] = -_edgeA.Normal;
  1323. for (int i = 0; i < 2; ++i)
  1324. {
  1325. Vector2 n = _tmpNormals[i];
  1326. // Adjacency
  1327. bool valid1 = MathUtils.Cross(n, _limit11) >= -Settings.AngularSlop &&
  1328. MathUtils.Cross(_limit12, n) >= -Settings.AngularSlop;
  1329. bool valid2 = MathUtils.Cross(n, _limit21) >= -Settings.AngularSlop &&
  1330. MathUtils.Cross(_limit22, n) >= -Settings.AngularSlop;
  1331. if (valid1 == false || valid2 == false)
  1332. {
  1333. continue;
  1334. }
  1335. EPAxis axis;
  1336. axis.Type = EPAxisType.EdgeA;
  1337. axis.Index = i;
  1338. axis.Separation = Settings.MaxFloat;
  1339. for (int j = 0; j < _proxyB.Count; ++j)
  1340. {
  1341. float s = Vector2.Dot(n, _proxyB.Vertices[j] - _edgeA.V1);
  1342. if (s < axis.Separation)
  1343. {
  1344. axis.Separation = s;
  1345. }
  1346. }
  1347. if (axis.Separation > _radius)
  1348. {
  1349. return axis;
  1350. }
  1351. if (axis.Separation > bestAxis.Separation)
  1352. {
  1353. bestAxis = axis;
  1354. }
  1355. }
  1356. return bestAxis;
  1357. }
  1358. private static EPAxis ComputePolygonSeparation()
  1359. {
  1360. EPAxis axis;
  1361. axis.Type = EPAxisType.Unknown;
  1362. axis.Index = -1;
  1363. axis.Separation = -Settings.MaxFloat;
  1364. for (int i = 0; i < _proxyB.Count; ++i)
  1365. {
  1366. Vector2 n = -_proxyB.Normals[i];
  1367. // Adjacency
  1368. bool valid1 = MathUtils.Cross(n, _limit11) >= -Settings.AngularSlop &&
  1369. MathUtils.Cross(_limit12, n) >= -Settings.AngularSlop;
  1370. bool valid2 = MathUtils.Cross(n, _limit21) >= -Settings.AngularSlop &&
  1371. MathUtils.Cross(_limit22, n) >= -Settings.AngularSlop;
  1372. if (valid1 == false && valid2 == false)
  1373. {
  1374. continue;
  1375. }
  1376. float s1 = Vector2.Dot(n, _proxyB.Vertices[i] - _edgeA.V1);
  1377. float s2 = Vector2.Dot(n, _proxyB.Vertices[i] - _edgeA.V2);
  1378. float s = Math.Min(s1, s2);
  1379. if (s > _radius)
  1380. {
  1381. axis.Type = EPAxisType.EdgeB;
  1382. axis.Index = i;
  1383. axis.Separation = s;
  1384. }
  1385. if (s > axis.Separation)
  1386. {
  1387. axis.Type = EPAxisType.EdgeB;
  1388. axis.Index = i;
  1389. axis.Separation = s;
  1390. }
  1391. }
  1392. return axis;
  1393. }
  1394. private static void FindIncidentEdge(ref FixedArray2<ClipVertex> c, EPProxy proxy1, int edge1, EPProxy proxy2)
  1395. {
  1396. int count2 = proxy2.Count;
  1397. Debug.Assert(0 <= edge1 && edge1 < proxy1.Count);
  1398. // Get the normal of the reference edge in proxy2's frame.
  1399. Vector2 normal1 = proxy1.Normals[edge1];
  1400. // Find the incident edge on proxy2.
  1401. int index = 0;
  1402. float minDot = float.MaxValue;
  1403. for (int i = 0; i < count2; ++i)
  1404. {
  1405. float dot = Vector2.Dot(normal1, proxy2.Normals[i]);
  1406. if (dot < minDot)
  1407. {
  1408. minDot = dot;
  1409. index = i;
  1410. }
  1411. }
  1412. // Build the clip vertices for the incident edge.
  1413. int i1 = index;
  1414. int i2 = i1 + 1 < count2 ? i1 + 1 : 0;
  1415. ClipVertex cTemp = new ClipVertex();
  1416. cTemp.V = proxy2.Vertices[i1];
  1417. cTemp.ID.Features.IndexA = (byte)edge1;
  1418. cTemp.ID.Features.IndexB = (byte)i1;
  1419. cTemp.ID.Features.TypeA = (byte)ContactFeatureType.Face;
  1420. cTemp.ID.Features.TypeB = (byte)ContactFeatureType.Vertex;
  1421. c[0] = cTemp;
  1422. cTemp.V = proxy2.Vertices[i2];
  1423. cTemp.ID.Features.IndexA = (byte)edge1;
  1424. cTemp.ID.Features.IndexB = (byte)i2;
  1425. cTemp.ID.Features.TypeA = (byte)ContactFeatureType.Face;
  1426. cTemp.ID.Features.TypeB = (byte)ContactFeatureType.Vertex;
  1427. c[1] = cTemp;
  1428. }
  1429. /// <summary>
  1430. /// Clipping for contact manifolds.
  1431. /// </summary>
  1432. /// <param name="vOut">The v out.</param>
  1433. /// <param name="vIn">The v in.</param>
  1434. /// <param name="normal">The normal.</param>
  1435. /// <param name="offset">The offset.</param>
  1436. /// <param name="vertexIndexA">The vertex index A.</param>
  1437. /// <returns></returns>
  1438. private static int ClipSegmentToLine(out FixedArray2<ClipVertex> vOut, ref FixedArray2<ClipVertex> vIn,
  1439. Vector2 normal, float offset, int vertexIndexA)
  1440. {
  1441. vOut = new FixedArray2<ClipVertex>();
  1442. ClipVertex v0 = vIn[0];
  1443. ClipVertex v1 = vIn[1];
  1444. // Start with no output points
  1445. int numOut = 0;
  1446. // Calculate the distance of end points to the line
  1447. float distance0 = normal.X * v0.V.X + normal.Y * v0.V.Y - offset;
  1448. float distance1 = normal.X * v1.V.X + normal.Y * v1.V.Y - offset;
  1449. // If the points are behind the plane
  1450. if (distance0 <= 0.0f) vOut[numOut++] = v0;
  1451. if (distance1 <= 0.0f) vOut[numOut++] = v1;
  1452. // If the points are on different sides of the plane
  1453. if (distance0 * distance1 < 0.0f)
  1454. {
  1455. // Find intersection point of edge and plane
  1456. float interp = distance0 / (distance0 - distance1);
  1457. ClipVertex cv = vOut[numOut];
  1458. cv.V.X = v0.V.X + interp * (v1.V.X - v0.V.X);
  1459. cv.V.Y = v0.V.Y + interp * (v1.V.Y - v0.V.Y);
  1460. // VertexA is hitting edgeB.
  1461. cv.ID.Features.IndexA = (byte)vertexIndexA;
  1462. cv.ID.Features.IndexB = v0.ID.Features.IndexB;
  1463. cv.ID.Features.TypeA = (byte)ContactFeatureType.Vertex;
  1464. cv.ID.Features.TypeB = (byte)ContactFeatureType.Face;
  1465. vOut[numOut] = cv;
  1466. ++numOut;
  1467. }
  1468. return numOut;
  1469. }
  1470. /// <summary>
  1471. /// Find the separation between poly1 and poly2 for a give edge normal on poly1.
  1472. /// </summary>
  1473. /// <param name="poly1">The poly1.</param>
  1474. /// <param name="xf1">The XF1.</param>
  1475. /// <param name="edge1">The edge1.</param>
  1476. /// <param name="poly2">The poly2.</param>
  1477. /// <param name="xf2">The XF2.</param>
  1478. /// <returns></returns>
  1479. private static float EdgeSeparation(PolygonShape poly1, ref Transform xf1, int edge1,
  1480. PolygonShape poly2, ref Transform xf2)
  1481. {
  1482. int count2 = poly2.Vertices.Count;
  1483. Debug.Assert(0 <= edge1 && edge1 < poly1.Vertices.Count);
  1484. // Convert normal from poly1's frame into poly2's frame.
  1485. Vector2 p1n = poly1.Normals[edge1];
  1486. float normalWorldx = xf1.R.Col1.X * p1n.X + xf1.R.Col2.X * p1n.Y;
  1487. float normalWorldy = xf1.R.Col1.Y * p1n.X + xf1.R.Col2.Y * p1n.Y;
  1488. Vector2 normal = new Vector2(normalWorldx * xf2.R.Col1.X + normalWorldy * xf2.R.Col1.Y,
  1489. normalWorldx * xf2.R.Col2.X + normalWorldy * xf2.R.Col2.Y);
  1490. // Find support vertex on poly2 for -normal.
  1491. int index = 0;
  1492. float minDot = Settings.MaxFloat;
  1493. for (int i = 0; i < count2; ++i)
  1494. {
  1495. float dot = Vector2.Dot(poly2.Vertices[i], normal);
  1496. if (dot < minDot)
  1497. {
  1498. minDot = dot;
  1499. index = i;
  1500. }
  1501. }
  1502. Vector2 p1ve = poly1.Vertices[edge1];
  1503. Vector2 p2vi = poly2.Vertices[index];
  1504. return ((xf2.Position.X + xf2.R.Col1.X * p2vi.X + xf2.R.Col2.X * p2vi.Y) -
  1505. (xf1.Position.X + xf1.R.Col1.X * p1ve.X + xf1.R.Col2.X * p1ve.Y)) * normalWorldx +
  1506. ((xf2.Position.Y + xf2.R.Col1.Y * p2vi.X + xf2.R.Col2.Y * p2vi.Y) -
  1507. (xf1.Position.Y + xf1.R.Col1.Y * p1ve.X + xf1.R.Col2.Y * p1ve.Y)) * normalWorldy;
  1508. }
  1509. /// <summary>
  1510. /// Find the max separation between poly1 and poly2 using edge normals from poly1.
  1511. /// </summary>
  1512. /// <param name="edgeIndex">Index of the edge.</param>
  1513. /// <param name="poly1">The poly1.</param>
  1514. /// <param name="xf1">The XF1.</param>
  1515. /// <param name="poly2">The poly2.</param>
  1516. /// <param name="xf2">The XF2.</param>
  1517. /// <returns></returns>
  1518. private static float FindMaxSeparation(out int edgeIndex,
  1519. PolygonShape poly1, ref Transform xf1,
  1520. PolygonShape poly2, ref Transform xf2)
  1521. {
  1522. int count1 = poly1.Vertices.Count;
  1523. // Vector pointing from the centroid of poly1 to the centroid of poly2.
  1524. float dx = (xf2.Position.X + xf2.R.Col1.X * poly2.MassData.Centroid.X +
  1525. xf2.R.Col2.X * poly2.MassData.Centroid.Y) -
  1526. (xf1.Position.X + xf1.R.Col1.X * poly1.MassData.Centroid.X +
  1527. xf1.R.Col2.X * poly1.MassData.Centroid.Y);
  1528. float dy = (xf2.Position.Y + xf2.R.Col1.Y * poly2.MassData.Centroid.X +
  1529. xf2.R.Col2.Y * poly2.MassData.Centroid.Y) -
  1530. (xf1.Position.Y + xf1.R.Col1.Y * poly1.MassData.Centroid.X +
  1531. xf1.R.Col2.Y * poly1.MassData.Centroid.Y);
  1532. Vector2 dLocal1 = new Vector2(dx * xf1.R.Col1.X + dy * xf1.R.Col1.Y, dx * xf1.R.Col2.X + dy * xf1.R.Col2.Y);
  1533. // Find edge normal on poly1 that has the largest projection onto d.
  1534. int edge = 0;
  1535. float maxDot = -Settings.MaxFloat;
  1536. for (int i = 0; i < count1; ++i)
  1537. {
  1538. float dot = Vector2.Dot(poly1.Normals[i], dLocal1);
  1539. if (dot > maxDot)
  1540. {
  1541. maxDot = dot;
  1542. edge = i;
  1543. }
  1544. }
  1545. // Get the separation for the edge normal.
  1546. float s = EdgeSeparation(poly1, ref xf1, edge, poly2, ref xf2);
  1547. // Check the separation for the previous edge normal.
  1548. int prevEdge = edge - 1 >= 0 ? edge - 1 : count1 - 1;
  1549. float sPrev = EdgeSeparation(poly1, ref xf1, prevEdge, poly2, ref xf2);
  1550. // Check the separation for the next edge normal.
  1551. int nextEdge = edge + 1 < count1 ? edge + 1 : 0;
  1552. float sNext = EdgeSeparation(poly1, ref xf1, nextEdge, poly2, ref xf2);
  1553. // Find the best edge and the search direction.
  1554. int bestEdge;
  1555. float bestSeparation;
  1556. int increment;
  1557. if (sPrev > s && sPrev > sNext)
  1558. {
  1559. increment = -1;
  1560. bestEdge = prevEdge;
  1561. bestSeparation = sPrev;
  1562. }
  1563. else if (sNext > s)
  1564. {
  1565. increment = 1;
  1566. bestEdge = nextEdge;
  1567. bestSeparation = sNext;
  1568. }
  1569. else
  1570. {
  1571. edgeIndex = edge;
  1572. return s;
  1573. }
  1574. // Perform a local search for the best edge normal.
  1575. for (; ; )
  1576. {
  1577. if (increment == -1)
  1578. edge = bestEdge - 1 >= 0 ? bestEdge - 1 : count1 - 1;
  1579. else
  1580. edge = bestEdge + 1 < count1 ? bestEdge + 1 : 0;
  1581. s = EdgeSeparation(poly1, ref xf1, edge, poly2, ref xf2);
  1582. if (s > bestSeparation)
  1583. {
  1584. bestEdge = edge;
  1585. bestSeparation = s;
  1586. }
  1587. else
  1588. {
  1589. break;
  1590. }
  1591. }
  1592. edgeIndex = bestEdge;
  1593. return bestSeparation;
  1594. }
  1595. private static void FindIncidentEdge(out FixedArray2<ClipVertex> c,
  1596. PolygonShape poly1, ref Transform xf1, int edge1,
  1597. PolygonShape poly2, ref Transform xf2)
  1598. {
  1599. c = new FixedArray2<ClipVertex>();
  1600. int count2 = poly2.Vertices.Count;
  1601. Debug.Assert(0 <= edge1 && edge1 < poly1.Vertices.Count);
  1602. // Get the normal of the reference edge in poly2's frame.
  1603. Vector2 v = poly1.Normals[edge1];
  1604. float tmpx = xf1.R.Col1.X * v.X + xf1.R.Col2.X * v.Y;
  1605. float tmpy = xf1.R.Col1.Y * v.X + xf1.R.Col2.Y * v.Y;
  1606. Vector2 normal1 = new Vector2(tmpx * xf2.R.Col1.X + tmpy * xf2.R.Col1.Y,
  1607. tmpx * xf2.R.Col2.X + tmpy * xf2.R.Col2.Y);
  1608. // Find the incident edge on poly2.
  1609. int index = 0;
  1610. float minDot = Settings.MaxFloat;
  1611. for (int i = 0; i < count2; ++i)
  1612. {
  1613. float dot = Vector2.Dot(normal1, poly2.Normals[i]);
  1614. if (dot < minDot)
  1615. {
  1616. minDot = dot;
  1617. index = i;
  1618. }
  1619. }
  1620. // Build the clip vertices for the incident edge.
  1621. int i1 = index;
  1622. int i2 = i1 + 1 < count2 ? i1 + 1 : 0;
  1623. ClipVertex cv0 = c[0];
  1624. Vector2 v1 = poly2.Vertices[i1];
  1625. cv0.V.X = xf2.Position.X + xf2.R.Col1.X * v1.X + xf2.R.Col2.X * v1.Y;
  1626. cv0.V.Y = xf2.Position.Y + xf2.R.Col1.Y * v1.X + xf2.R.Col2.Y * v1.Y;
  1627. cv0.ID.Features.IndexA = (byte)edge1;
  1628. cv0.ID.Features.IndexB = (byte)i1;
  1629. cv0.ID.Features.TypeA = (byte)ContactFeatureType.Face;
  1630. cv0.ID.Features.TypeB = (byte)ContactFeatureType.Vertex;
  1631. c[0] = cv0;
  1632. ClipVertex cv1 = c[1];
  1633. Vector2 v2 = poly2.Vertices[i2];
  1634. cv1.V.X = xf2.Position.X + xf2.R.Col1.X * v2.X + xf2.R.Col2.X * v2.Y;
  1635. cv1.V.Y = xf2.Position.Y + xf2.R.Col1.Y * v2.X + xf2.R.Col2.Y * v2.Y;
  1636. cv1.ID.Features.IndexA = (byte)edge1;
  1637. cv1.ID.Features.IndexB = (byte)i2;
  1638. cv1.ID.Features.TypeA = (byte)ContactFeatureType.Face;
  1639. cv1.ID.Features.TypeB = (byte)ContactFeatureType.Vertex;
  1640. c[1] = cv1;
  1641. }
  1642. }
  1643. }