EarclipDecomposer.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691
  1. /*
  2. * C# Version Ported by Matt Bettcher and Ian Qvist 2009-2010
  3. *
  4. * Original C++ Version Copyright (c) 2007 Eric Jordan
  5. *
  6. * This software is provided 'as-is', without any express or implied
  7. * warranty. In no event will the authors be held liable for any damages
  8. * arising from the use of this software.
  9. * Permission is granted to anyone to use this software for any purpose,
  10. * including commercial applications, and to alter it and redistribute it
  11. * freely, subject to the following restrictions:
  12. * 1. The origin of this software must not be misrepresented; you must not
  13. * claim that you wrote the original software. If you use this software
  14. * in a product, an acknowledgment in the product documentation would be
  15. * appreciated but is not required.
  16. * 2. Altered source versions must be plainly marked as such, and must not be
  17. * misrepresented as being the original software.
  18. * 3. This notice may not be removed or altered from any source distribution.
  19. */
  20. using System;
  21. using System.Collections.Generic;
  22. using FarseerPhysics.Common.PolygonManipulation;
  23. using Microsoft.Xna.Framework;
  24. namespace FarseerPhysics.Common.Decomposition
  25. {
  26. /// <summary>
  27. /// Ported from jBox2D. Original author: ewjordan
  28. /// Triangulates a polygon using simple ear-clipping algorithm.
  29. ///
  30. /// Only works on simple polygons.
  31. ///
  32. /// Triangles may be degenerate, especially if you have identical points
  33. /// in the input to the algorithm. Check this before you use them.
  34. /// </summary>
  35. public static class EarclipDecomposer
  36. {
  37. //box2D rev 32 - for details, see http://www.box2d.org/forum/viewtopic.php?f=4&t=83&start=50
  38. private const float Tol = .001f;
  39. /// <summary>
  40. /// Decomposes a non-convex polygon into a number of convex polygons, up
  41. /// to maxPolys (remaining pieces are thrown out).
  42. ///
  43. /// Each resulting polygon will have no more than Settings.MaxPolygonVertices
  44. /// vertices.
  45. ///
  46. /// Warning: Only works on simple polygons
  47. /// </summary>
  48. /// <param name="vertices">The vertices.</param>
  49. /// <returns></returns>
  50. public static List<Vertices> ConvexPartition(Vertices vertices)
  51. {
  52. return ConvexPartition(vertices, int.MaxValue, 0);
  53. }
  54. /// <summary>
  55. /// Decomposes a non-convex polygon into a number of convex polygons, up
  56. /// to maxPolys (remaining pieces are thrown out).
  57. /// Each resulting polygon will have no more than Settings.MaxPolygonVertices
  58. /// vertices.
  59. /// Warning: Only works on simple polygons
  60. /// </summary>
  61. /// <param name="vertices">The vertices.</param>
  62. /// <param name="maxPolys">The maximum number of polygons.</param>
  63. /// <param name="tolerance">The tolerance.</param>
  64. /// <returns></returns>
  65. public static List<Vertices> ConvexPartition(Vertices vertices, int maxPolys, float tolerance)
  66. {
  67. if (vertices.Count < 3)
  68. return new List<Vertices> { vertices };
  69. /*
  70. if (vertices.IsConvex() && vertices.Count <= Settings.MaxPolygonVertices)
  71. {
  72. if (vertices.IsCounterClockWise())
  73. {
  74. Vertices tempP = new Vertices(vertices);
  75. tempP.Reverse();
  76. tempP = SimplifyTools.CollinearSimplify(tempP);
  77. tempP.ForceCounterClockWise();
  78. return new List<Vertices> { tempP };
  79. }
  80. vertices = SimplifyTools.CollinearSimplify(vertices);
  81. vertices.ForceCounterClockWise();
  82. return new List<Vertices> { vertices };
  83. }
  84. */
  85. List<Triangle> triangulated;
  86. if (vertices.IsCounterClockWise())
  87. {
  88. Vertices tempP = new Vertices(vertices);
  89. tempP.Reverse();
  90. triangulated = TriangulatePolygon(tempP);
  91. }
  92. else
  93. {
  94. triangulated = TriangulatePolygon(vertices);
  95. }
  96. if (triangulated.Count < 1)
  97. {
  98. //Still no luck? Oh well...
  99. throw new Exception("Can't triangulate your polygon.");
  100. }
  101. List<Vertices> polygonizedTriangles = PolygonizeTriangles(triangulated, maxPolys, tolerance);
  102. //The polygonized triangles are not guaranteed to be without collinear points. We remove
  103. //them to be sure.
  104. for (int i = 0; i < polygonizedTriangles.Count; i++)
  105. {
  106. polygonizedTriangles[i] = SimplifyTools.CollinearSimplify(polygonizedTriangles[i], 0);
  107. }
  108. //Remove empty vertice collections
  109. for (int i = polygonizedTriangles.Count - 1; i >= 0; i--)
  110. {
  111. if (polygonizedTriangles[i].Count == 0)
  112. polygonizedTriangles.RemoveAt(i);
  113. }
  114. return polygonizedTriangles;
  115. }
  116. /// <summary>
  117. /// Turns a list of triangles into a list of convex polygons. Very simple
  118. /// method - start with a seed triangle, keep adding triangles to it until
  119. /// you can't add any more without making the polygon non-convex.
  120. ///
  121. /// Returns an integer telling how many polygons were created. Will fill
  122. /// polys array up to polysLength entries, which may be smaller or larger
  123. /// than the return value.
  124. ///
  125. /// Takes O(N///P) where P is the number of resultant polygons, N is triangle
  126. /// count.
  127. ///
  128. /// The final polygon list will not necessarily be minimal, though in
  129. /// practice it works fairly well.
  130. /// </summary>
  131. /// <param name="triangulated">The triangulated.</param>
  132. ///<param name="maxPolys">The maximun number of polygons</param>
  133. ///<param name="tolerance">The tolerance</param>
  134. ///<returns></returns>
  135. public static List<Vertices> PolygonizeTriangles(List<Triangle> triangulated, int maxPolys, float tolerance)
  136. {
  137. List<Vertices> polys = new List<Vertices>(50);
  138. int polyIndex = 0;
  139. if (triangulated.Count <= 0)
  140. {
  141. //return empty polygon list
  142. return polys;
  143. }
  144. bool[] covered = new bool[triangulated.Count];
  145. for (int i = 0; i < triangulated.Count; ++i)
  146. {
  147. covered[i] = false;
  148. //Check here for degenerate triangles
  149. if (((triangulated[i].X[0] == triangulated[i].X[1]) && (triangulated[i].Y[0] == triangulated[i].Y[1]))
  150. ||
  151. ((triangulated[i].X[1] == triangulated[i].X[2]) && (triangulated[i].Y[1] == triangulated[i].Y[2]))
  152. ||
  153. ((triangulated[i].X[0] == triangulated[i].X[2]) && (triangulated[i].Y[0] == triangulated[i].Y[2])))
  154. {
  155. covered[i] = true;
  156. }
  157. }
  158. bool notDone = true;
  159. while (notDone)
  160. {
  161. int currTri = -1;
  162. for (int i = 0; i < triangulated.Count; ++i)
  163. {
  164. if (covered[i])
  165. continue;
  166. currTri = i;
  167. break;
  168. }
  169. if (currTri == -1)
  170. {
  171. notDone = false;
  172. }
  173. else
  174. {
  175. Vertices poly = new Vertices(3);
  176. for (int i = 0; i < 3; i++)
  177. {
  178. poly.Add(new Vector2(triangulated[currTri].X[i], triangulated[currTri].Y[i]));
  179. }
  180. covered[currTri] = true;
  181. int index = 0;
  182. for (int i = 0; i < 2 * triangulated.Count; ++i, ++index)
  183. {
  184. while (index >= triangulated.Count) index -= triangulated.Count;
  185. if (covered[index])
  186. {
  187. continue;
  188. }
  189. Vertices newP = AddTriangle(triangulated[index], poly);
  190. if (newP == null)
  191. continue; // is this right
  192. if (newP.Count > Settings.MaxPolygonVertices)
  193. continue;
  194. if (newP.IsConvex())
  195. {
  196. //Or should it be IsUsable? Maybe re-write IsConvex to apply the angle threshold from Box2d
  197. poly = new Vertices(newP);
  198. covered[index] = true;
  199. }
  200. }
  201. //We have a maximum of polygons that we need to keep under.
  202. if (polyIndex < maxPolys)
  203. {
  204. //SimplifyTools.MergeParallelEdges(poly, tolerance);
  205. //If identical points are present, a triangle gets
  206. //borked by the MergeParallelEdges function, hence
  207. //the vertex number check
  208. if (poly.Count >= 3)
  209. polys.Add(new Vertices(poly));
  210. //else
  211. // printf("Skipping corrupt poly\n");
  212. }
  213. if (poly.Count >= 3)
  214. polyIndex++; //Must be outside (polyIndex < polysLength) test
  215. }
  216. }
  217. return polys;
  218. }
  219. /// <summary>
  220. /// Triangulates a polygon using simple ear-clipping algorithm. Returns
  221. /// size of Triangle array unless the polygon can't be triangulated.
  222. /// This should only happen if the polygon self-intersects,
  223. /// though it will not _always_ return null for a bad polygon - it is the
  224. /// caller's responsibility to check for self-intersection, and if it
  225. /// doesn't, it should at least check that the return value is non-null
  226. /// before using. You're warned!
  227. ///
  228. /// Triangles may be degenerate, especially if you have identical points
  229. /// in the input to the algorithm. Check this before you use them.
  230. ///
  231. /// This is totally unoptimized, so for large polygons it should not be part
  232. /// of the simulation loop.
  233. ///
  234. /// Warning: Only works on simple polygons.
  235. /// </summary>
  236. /// <returns></returns>
  237. public static List<Triangle> TriangulatePolygon(Vertices vertices)
  238. {
  239. List<Triangle> results = new List<Triangle>();
  240. if (vertices.Count < 3)
  241. return new List<Triangle>();
  242. //Recurse and split on pinch points
  243. Vertices pA, pB;
  244. Vertices pin = new Vertices(vertices);
  245. if (ResolvePinchPoint(pin, out pA, out pB))
  246. {
  247. List<Triangle> mergeA = TriangulatePolygon(pA);
  248. List<Triangle> mergeB = TriangulatePolygon(pB);
  249. if (mergeA.Count == -1 || mergeB.Count == -1)
  250. throw new Exception("Can't triangulate your polygon.");
  251. for (int i = 0; i < mergeA.Count; ++i)
  252. {
  253. results.Add(new Triangle(mergeA[i]));
  254. }
  255. for (int i = 0; i < mergeB.Count; ++i)
  256. {
  257. results.Add(new Triangle(mergeB[i]));
  258. }
  259. return results;
  260. }
  261. Triangle[] buffer = new Triangle[vertices.Count - 2];
  262. int bufferSize = 0;
  263. float[] xrem = new float[vertices.Count];
  264. float[] yrem = new float[vertices.Count];
  265. for (int i = 0; i < vertices.Count; ++i)
  266. {
  267. xrem[i] = vertices[i].X;
  268. yrem[i] = vertices[i].Y;
  269. }
  270. int vNum = vertices.Count;
  271. while (vNum > 3)
  272. {
  273. // Find an ear
  274. int earIndex = -1;
  275. float earMaxMinCross = -10.0f;
  276. for (int i = 0; i < vNum; ++i)
  277. {
  278. if (IsEar(i, xrem, yrem, vNum))
  279. {
  280. int lower = Remainder(i - 1, vNum);
  281. int upper = Remainder(i + 1, vNum);
  282. Vector2 d1 = new Vector2(xrem[upper] - xrem[i], yrem[upper] - yrem[i]);
  283. Vector2 d2 = new Vector2(xrem[i] - xrem[lower], yrem[i] - yrem[lower]);
  284. Vector2 d3 = new Vector2(xrem[lower] - xrem[upper], yrem[lower] - yrem[upper]);
  285. d1.Normalize();
  286. d2.Normalize();
  287. d3.Normalize();
  288. float cross12;
  289. MathUtils.Cross(ref d1, ref d2, out cross12);
  290. cross12 = Math.Abs(cross12);
  291. float cross23;
  292. MathUtils.Cross(ref d2, ref d3, out cross23);
  293. cross23 = Math.Abs(cross23);
  294. float cross31;
  295. MathUtils.Cross(ref d3, ref d1, out cross31);
  296. cross31 = Math.Abs(cross31);
  297. //Find the maximum minimum angle
  298. float minCross = Math.Min(cross12, Math.Min(cross23, cross31));
  299. if (minCross > earMaxMinCross)
  300. {
  301. earIndex = i;
  302. earMaxMinCross = minCross;
  303. }
  304. }
  305. }
  306. // If we still haven't found an ear, we're screwed.
  307. // Note: sometimes this is happening because the
  308. // remaining points are collinear. Really these
  309. // should just be thrown out without halting triangulation.
  310. if (earIndex == -1)
  311. {
  312. for (int i = 0; i < bufferSize; i++)
  313. {
  314. results.Add(new Triangle(buffer[i]));
  315. }
  316. return results;
  317. }
  318. // Clip off the ear:
  319. // - remove the ear tip from the list
  320. --vNum;
  321. float[] newx = new float[vNum];
  322. float[] newy = new float[vNum];
  323. int currDest = 0;
  324. for (int i = 0; i < vNum; ++i)
  325. {
  326. if (currDest == earIndex) ++currDest;
  327. newx[i] = xrem[currDest];
  328. newy[i] = yrem[currDest];
  329. ++currDest;
  330. }
  331. // - add the clipped triangle to the triangle list
  332. int under = (earIndex == 0) ? (vNum) : (earIndex - 1);
  333. int over = (earIndex == vNum) ? 0 : (earIndex + 1);
  334. Triangle toAdd = new Triangle(xrem[earIndex], yrem[earIndex], xrem[over], yrem[over], xrem[under],
  335. yrem[under]);
  336. buffer[bufferSize] = toAdd;
  337. ++bufferSize;
  338. // - replace the old list with the new one
  339. xrem = newx;
  340. yrem = newy;
  341. }
  342. Triangle tooAdd = new Triangle(xrem[1], yrem[1], xrem[2], yrem[2], xrem[0], yrem[0]);
  343. buffer[bufferSize] = tooAdd;
  344. ++bufferSize;
  345. for (int i = 0; i < bufferSize; i++)
  346. {
  347. results.Add(new Triangle(buffer[i]));
  348. }
  349. return results;
  350. }
  351. /// <summary>
  352. /// Finds and fixes "pinch points," points where two polygon
  353. /// vertices are at the same point.
  354. ///
  355. /// If a pinch point is found, pin is broken up into poutA and poutB
  356. /// and true is returned; otherwise, returns false.
  357. ///
  358. /// Mostly for internal use.
  359. ///
  360. /// O(N^2) time, which sucks...
  361. /// </summary>
  362. /// <param name="pin">The pin.</param>
  363. /// <param name="poutA">The pout A.</param>
  364. /// <param name="poutB">The pout B.</param>
  365. /// <returns></returns>
  366. private static bool ResolvePinchPoint(Vertices pin, out Vertices poutA, out Vertices poutB)
  367. {
  368. poutA = new Vertices();
  369. poutB = new Vertices();
  370. if (pin.Count < 3)
  371. return false;
  372. bool hasPinchPoint = false;
  373. int pinchIndexA = -1;
  374. int pinchIndexB = -1;
  375. for (int i = 0; i < pin.Count; ++i)
  376. {
  377. for (int j = i + 1; j < pin.Count; ++j)
  378. {
  379. //Don't worry about pinch points where the points
  380. //are actually just dupe neighbors
  381. if (Math.Abs(pin[i].X - pin[j].X) < Tol && Math.Abs(pin[i].Y - pin[j].Y) < Tol && j != i + 1)
  382. {
  383. pinchIndexA = i;
  384. pinchIndexB = j;
  385. hasPinchPoint = true;
  386. break;
  387. }
  388. }
  389. if (hasPinchPoint) break;
  390. }
  391. if (hasPinchPoint)
  392. {
  393. int sizeA = pinchIndexB - pinchIndexA;
  394. if (sizeA == pin.Count) return false; //has dupe points at wraparound, not a problem here
  395. for (int i = 0; i < sizeA; ++i)
  396. {
  397. int ind = Remainder(pinchIndexA + i, pin.Count); // is this right
  398. poutA.Add(pin[ind]);
  399. }
  400. int sizeB = pin.Count - sizeA;
  401. for (int i = 0; i < sizeB; ++i)
  402. {
  403. int ind = Remainder(pinchIndexB + i, pin.Count); // is this right
  404. poutB.Add(pin[ind]);
  405. }
  406. }
  407. return hasPinchPoint;
  408. }
  409. /// <summary>
  410. /// Fix for obnoxious behavior for the % operator for negative numbers...
  411. /// </summary>
  412. /// <param name="x">The x.</param>
  413. /// <param name="modulus">The modulus.</param>
  414. /// <returns></returns>
  415. private static int Remainder(int x, int modulus)
  416. {
  417. int rem = x % modulus;
  418. while (rem < 0)
  419. {
  420. rem += modulus;
  421. }
  422. return rem;
  423. }
  424. private static Vertices AddTriangle(Triangle t, Vertices vertices)
  425. {
  426. // First, find vertices that connect
  427. int firstP = -1;
  428. int firstT = -1;
  429. int secondP = -1;
  430. int secondT = -1;
  431. for (int i = 0; i < vertices.Count; i++)
  432. {
  433. if (t.X[0] == vertices[i].X && t.Y[0] == vertices[i].Y)
  434. {
  435. if (firstP == -1)
  436. {
  437. firstP = i;
  438. firstT = 0;
  439. }
  440. else
  441. {
  442. secondP = i;
  443. secondT = 0;
  444. }
  445. }
  446. else if (t.X[1] == vertices[i].X && t.Y[1] == vertices[i].Y)
  447. {
  448. if (firstP == -1)
  449. {
  450. firstP = i;
  451. firstT = 1;
  452. }
  453. else
  454. {
  455. secondP = i;
  456. secondT = 1;
  457. }
  458. }
  459. else if (t.X[2] == vertices[i].X && t.Y[2] == vertices[i].Y)
  460. {
  461. if (firstP == -1)
  462. {
  463. firstP = i;
  464. firstT = 2;
  465. }
  466. else
  467. {
  468. secondP = i;
  469. secondT = 2;
  470. }
  471. }
  472. }
  473. // Fix ordering if first should be last vertex of poly
  474. if (firstP == 0 && secondP == vertices.Count - 1)
  475. {
  476. firstP = vertices.Count - 1;
  477. secondP = 0;
  478. }
  479. // Didn't find it
  480. if (secondP == -1)
  481. {
  482. return null;
  483. }
  484. // Find tip index on triangle
  485. int tipT = 0;
  486. if (tipT == firstT || tipT == secondT)
  487. tipT = 1;
  488. if (tipT == firstT || tipT == secondT)
  489. tipT = 2;
  490. Vertices result = new Vertices(vertices.Count + 1);
  491. for (int i = 0; i < vertices.Count; i++)
  492. {
  493. result.Add(vertices[i]);
  494. if (i == firstP)
  495. result.Add(new Vector2(t.X[tipT], t.Y[tipT]));
  496. }
  497. return result;
  498. }
  499. /// <summary>
  500. /// Checks if vertex i is the tip of an ear in polygon defined by xv[] and
  501. /// yv[].
  502. ///
  503. /// Assumes clockwise orientation of polygon...ick
  504. /// </summary>
  505. /// <param name="i">The i.</param>
  506. /// <param name="xv">The xv.</param>
  507. /// <param name="yv">The yv.</param>
  508. /// <param name="xvLength">Length of the xv.</param>
  509. /// <returns>
  510. /// <c>true</c> if the specified i is ear; otherwise, <c>false</c>.
  511. /// </returns>
  512. private static bool IsEar(int i, float[] xv, float[] yv, int xvLength)
  513. {
  514. float dx0, dy0, dx1, dy1;
  515. if (i >= xvLength || i < 0 || xvLength < 3)
  516. {
  517. return false;
  518. }
  519. int upper = i + 1;
  520. int lower = i - 1;
  521. if (i == 0)
  522. {
  523. dx0 = xv[0] - xv[xvLength - 1];
  524. dy0 = yv[0] - yv[xvLength - 1];
  525. dx1 = xv[1] - xv[0];
  526. dy1 = yv[1] - yv[0];
  527. lower = xvLength - 1;
  528. }
  529. else if (i == xvLength - 1)
  530. {
  531. dx0 = xv[i] - xv[i - 1];
  532. dy0 = yv[i] - yv[i - 1];
  533. dx1 = xv[0] - xv[i];
  534. dy1 = yv[0] - yv[i];
  535. upper = 0;
  536. }
  537. else
  538. {
  539. dx0 = xv[i] - xv[i - 1];
  540. dy0 = yv[i] - yv[i - 1];
  541. dx1 = xv[i + 1] - xv[i];
  542. dy1 = yv[i + 1] - yv[i];
  543. }
  544. float cross = dx0 * dy1 - dx1 * dy0;
  545. if (cross > 0)
  546. return false;
  547. Triangle myTri = new Triangle(xv[i], yv[i], xv[upper], yv[upper],
  548. xv[lower], yv[lower]);
  549. for (int j = 0; j < xvLength; ++j)
  550. {
  551. if (j == i || j == lower || j == upper)
  552. continue;
  553. if (myTri.IsInside(xv[j], yv[j]))
  554. return false;
  555. }
  556. return true;
  557. }
  558. }
  559. public class Triangle
  560. {
  561. public float[] X;
  562. public float[] Y;
  563. //Constructor automatically fixes orientation to ccw
  564. public Triangle(float x1, float y1, float x2, float y2, float x3, float y3)
  565. {
  566. X = new float[3];
  567. Y = new float[3];
  568. float dx1 = x2 - x1;
  569. float dx2 = x3 - x1;
  570. float dy1 = y2 - y1;
  571. float dy2 = y3 - y1;
  572. float cross = dx1 * dy2 - dx2 * dy1;
  573. bool ccw = (cross > 0);
  574. if (ccw)
  575. {
  576. X[0] = x1;
  577. X[1] = x2;
  578. X[2] = x3;
  579. Y[0] = y1;
  580. Y[1] = y2;
  581. Y[2] = y3;
  582. }
  583. else
  584. {
  585. X[0] = x1;
  586. X[1] = x3;
  587. X[2] = x2;
  588. Y[0] = y1;
  589. Y[1] = y3;
  590. Y[2] = y2;
  591. }
  592. }
  593. public Triangle(Triangle t)
  594. {
  595. X = new float[3];
  596. Y = new float[3];
  597. X[0] = t.X[0];
  598. X[1] = t.X[1];
  599. X[2] = t.X[2];
  600. Y[0] = t.Y[0];
  601. Y[1] = t.Y[1];
  602. Y[2] = t.Y[2];
  603. }
  604. public bool IsInside(float x, float y)
  605. {
  606. if (x < X[0] && x < X[1] && x < X[2]) return false;
  607. if (x > X[0] && x > X[1] && x > X[2]) return false;
  608. if (y < Y[0] && y < Y[1] && y < Y[2]) return false;
  609. if (y > Y[0] && y > Y[1] && y > Y[2]) return false;
  610. float vx2 = x - X[0];
  611. float vy2 = y - Y[0];
  612. float vx1 = X[1] - X[0];
  613. float vy1 = Y[1] - Y[0];
  614. float vx0 = X[2] - X[0];
  615. float vy0 = Y[2] - Y[0];
  616. float dot00 = vx0 * vx0 + vy0 * vy0;
  617. float dot01 = vx0 * vx1 + vy0 * vy1;
  618. float dot02 = vx0 * vx2 + vy0 * vy2;
  619. float dot11 = vx1 * vx1 + vy1 * vy1;
  620. float dot12 = vx1 * vx2 + vy1 * vy2;
  621. float invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01);
  622. float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
  623. float v = (dot00 * dot12 - dot01 * dot02) * invDenom;
  624. return ((u > 0) && (v > 0) && (u + v < 1));
  625. }
  626. }
  627. }