FlipcodeDecomposer.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. using System.Collections.Generic;
  2. using Microsoft.Xna.Framework;
  3. namespace FarseerPhysics.Common.Decomposition
  4. {
  5. // Original code can be found here: http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml
  6. /// <summary>
  7. /// Triangulates a polygon into triangles.
  8. /// Doesn't handle holes.
  9. /// </summary>
  10. public static class FlipcodeDecomposer
  11. {
  12. private static Vector2 _tmpA;
  13. private static Vector2 _tmpB;
  14. private static Vector2 _tmpC;
  15. /// <summary>
  16. /// Check if the point P is inside the triangle defined by
  17. /// the points A, B, C
  18. /// </summary>
  19. /// <param name="a">The A point.</param>
  20. /// <param name="b">The B point.</param>
  21. /// <param name="c">The C point.</param>
  22. /// <param name="p">The point to be tested.</param>
  23. /// <returns>True if the point is inside the triangle</returns>
  24. private static bool InsideTriangle(ref Vector2 a, ref Vector2 b, ref Vector2 c, ref Vector2 p)
  25. {
  26. //A cross bp
  27. float abp = (c.X - b.X) * (p.Y - b.Y) - (c.Y - b.Y) * (p.X - b.X);
  28. //A cross ap
  29. float aap = (b.X - a.X) * (p.Y - a.Y) - (b.Y - a.Y) * (p.X - a.X);
  30. //b cross cp
  31. float bcp = (a.X - c.X) * (p.Y - c.Y) - (a.Y - c.Y) * (p.X - c.X);
  32. return ((abp >= 0.0f) && (bcp >= 0.0f) && (aap >= 0.0f));
  33. }
  34. /// <summary>
  35. /// Cut a the contour and add a triangle into V to describe the
  36. /// location of the cut
  37. /// </summary>
  38. /// <param name="contour">The list of points defining the polygon</param>
  39. /// <param name="u">The index of the first point</param>
  40. /// <param name="v">The index of the second point</param>
  41. /// <param name="w">The index of the third point</param>
  42. /// <param name="n">The number of elements in the array.</param>
  43. /// <param name="V">The array to populate with indicies of triangles.</param>
  44. /// <returns>True if a triangle was found</returns>
  45. private static bool Snip(Vertices contour, int u, int v, int w, int n,
  46. int[] V)
  47. {
  48. if (Settings.Epsilon > MathUtils.Area(ref _tmpA, ref _tmpB, ref _tmpC))
  49. {
  50. return false;
  51. }
  52. for (int p = 0; p < n; p++)
  53. {
  54. if ((p == u) || (p == v) || (p == w))
  55. {
  56. continue;
  57. }
  58. Vector2 point = contour[V[p]];
  59. if (InsideTriangle(ref _tmpA, ref _tmpB, ref _tmpC, ref point))
  60. {
  61. return false;
  62. }
  63. }
  64. return true;
  65. }
  66. /// <summary>
  67. /// Decompose the polygon into triangles
  68. /// </summary>
  69. /// <param name="contour">The list of points describing the polygon</param>
  70. /// <returns></returns>
  71. public static List<Vertices> ConvexPartition(Vertices contour)
  72. {
  73. int n = contour.Count;
  74. if (n < 3)
  75. return new List<Vertices>();
  76. int[] V = new int[n];
  77. // We want a counter-clockwise polygon in V
  78. if (contour.IsCounterClockWise())
  79. {
  80. for (int v = 0; v < n; v++)
  81. V[v] = v;
  82. }
  83. else
  84. {
  85. for (int v = 0; v < n; v++)
  86. V[v] = (n - 1) - v;
  87. }
  88. int nv = n;
  89. // Remove nv-2 Vertices, creating 1 triangle every time
  90. int count = 2 * nv; /* error detection */
  91. List<Vertices> result = new List<Vertices>();
  92. for (int v = nv - 1; nv > 2; )
  93. {
  94. // If we loop, it is probably a non-simple polygon
  95. if (0 >= (count--))
  96. {
  97. // Triangulate: ERROR - probable bad polygon!
  98. return new List<Vertices>();
  99. }
  100. // Three consecutive vertices in current polygon, <u,v,w>
  101. int u = v;
  102. if (nv <= u)
  103. u = 0; // Previous
  104. v = u + 1;
  105. if (nv <= v)
  106. v = 0; // New v
  107. int w = v + 1;
  108. if (nv <= w)
  109. w = 0; // Next
  110. _tmpA = contour[V[u]];
  111. _tmpB = contour[V[v]];
  112. _tmpC = contour[V[w]];
  113. if (Snip(contour, u, v, w, nv, V))
  114. {
  115. int s, t;
  116. // Output Triangle
  117. Vertices triangle = new Vertices(3);
  118. triangle.Add(_tmpA);
  119. triangle.Add(_tmpB);
  120. triangle.Add(_tmpC);
  121. result.Add(triangle);
  122. // Remove v from remaining polygon
  123. for (s = v, t = v + 1; t < nv; s++, t++)
  124. {
  125. V[s] = V[t];
  126. }
  127. nv--;
  128. // Reset error detection counter
  129. count = 2 * nv;
  130. }
  131. }
  132. return result;
  133. }
  134. }
  135. }