using System.Collections.Generic; using Microsoft.Xna.Framework; namespace FarseerPhysics.Common.Decomposition { // Original code can be found here: http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml /// /// Triangulates a polygon into triangles. /// Doesn't handle holes. /// public static class FlipcodeDecomposer { private static Vector2 _tmpA; private static Vector2 _tmpB; private static Vector2 _tmpC; /// /// Check if the point P is inside the triangle defined by /// the points A, B, C /// /// The A point. /// The B point. /// The C point. /// The point to be tested. /// True if the point is inside the triangle private static bool InsideTriangle(ref Vector2 a, ref Vector2 b, ref Vector2 c, ref Vector2 p) { //A cross bp float abp = (c.X - b.X) * (p.Y - b.Y) - (c.Y - b.Y) * (p.X - b.X); //A cross ap float aap = (b.X - a.X) * (p.Y - a.Y) - (b.Y - a.Y) * (p.X - a.X); //b cross cp float bcp = (a.X - c.X) * (p.Y - c.Y) - (a.Y - c.Y) * (p.X - c.X); return ((abp >= 0.0f) && (bcp >= 0.0f) && (aap >= 0.0f)); } /// /// Cut a the contour and add a triangle into V to describe the /// location of the cut /// /// The list of points defining the polygon /// The index of the first point /// The index of the second point /// The index of the third point /// The number of elements in the array. /// The array to populate with indicies of triangles. /// True if a triangle was found private static bool Snip(Vertices contour, int u, int v, int w, int n, int[] V) { if (Settings.Epsilon > MathUtils.Area(ref _tmpA, ref _tmpB, ref _tmpC)) { return false; } for (int p = 0; p < n; p++) { if ((p == u) || (p == v) || (p == w)) { continue; } Vector2 point = contour[V[p]]; if (InsideTriangle(ref _tmpA, ref _tmpB, ref _tmpC, ref point)) { return false; } } return true; } /// /// Decompose the polygon into triangles /// /// The list of points describing the polygon /// public static List ConvexPartition(Vertices contour) { int n = contour.Count; if (n < 3) return new List(); int[] V = new int[n]; // We want a counter-clockwise polygon in V if (contour.IsCounterClockWise()) { for (int v = 0; v < n; v++) V[v] = v; } else { for (int v = 0; v < n; v++) V[v] = (n - 1) - v; } int nv = n; // Remove nv-2 Vertices, creating 1 triangle every time int count = 2 * nv; /* error detection */ List result = new List(); for (int v = nv - 1; nv > 2; ) { // If we loop, it is probably a non-simple polygon if (0 >= (count--)) { // Triangulate: ERROR - probable bad polygon! return new List(); } // Three consecutive vertices in current polygon, int u = v; if (nv <= u) u = 0; // Previous v = u + 1; if (nv <= v) v = 0; // New v int w = v + 1; if (nv <= w) w = 0; // Next _tmpA = contour[V[u]]; _tmpB = contour[V[v]]; _tmpC = contour[V[w]]; if (Snip(contour, u, v, w, nv, V)) { int s, t; // Output Triangle Vertices triangle = new Vertices(3); triangle.Add(_tmpA); triangle.Add(_tmpB); triangle.Add(_tmpC); result.Add(triangle); // Remove v from remaining polygon for (s = v, t = v + 1; t < nv; s++, t++) { V[s] = V[t]; } nv--; // Reset error detection counter count = 2 * nv; } } return result; } } }