using System; using System.Collections.Generic; using UnityEngine; namespace BracerLib.Utility { /// /// Sourced from https://mmems.gitbook.io/calepin/Algorithms/Polygon%20triangulation%20-%20tessellation/Triangulator%20-%20Unity /// public static class Triangulator { public static int[] Triangulate(Vector2[] points) { var n = points.Length; if (n < 3) return Array.Empty(); var indices = new List(); var verts = new int[n]; if (Area(points) > 0f) { for (var i = 0; i < n; i++) verts[i] = i; } else { for (var i = 0; i < n; i++) verts[i] = n - 1 - i; } var nv = n; var count = 2 * nv; for (int _ = 0, j = nv - 1; nv > 2;) { if (count-- <= 0) return indices.ToArray(); var u = j; if (nv <= u) u = 0; j = u + 1; if (nv <= j) j = 0; var w = j + 1; if (nv <= w) w = 0; if (!Snip(u, j, w, nv, points, verts)) continue; indices.Add(verts[u]); indices.Add(verts[j]); indices.Add(verts[w]); _++; for (int s = j, t = j + 1; t < nv; s++, t++) verts[s] = verts[t]; nv--; count = 2 * nv; } indices.Reverse(); return indices.ToArray(); } public static bool Snip(int u, int v, int w, int n, Vector2[] points, int[] verts) { var a = points[verts[u]]; var b = points[verts[v]]; var c = points[verts[w]]; if (Mathf.Epsilon > (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x)) return false; for (var i = 0; i < n; i++) { if (i == u || i == v || i == w) continue; if (InsideTriangle(a, b, c, points[verts[i]])) return false; } return true; } /// /// Check if a point is inside of a triangle of 3 given points. /// Used from https://blackpawn.com/texts/pointinpoly/ /// public static bool InsideTriangle(Vector2 a, Vector2 b, Vector2 c, Vector2 p) { var v0 = c - a; var v1 = b - a; var v2 = p - a; var dots = new[] { Vector2.Dot(v0, v0), Vector2.Dot(v0, v1), Vector2.Dot(v0, v2), Vector2.Dot(v1, v1), Vector2.Dot(v1, v2) }; var invDenom = 1 / (dots[0] * dots[3] - dots[1] * dots[1]); var u = (dots[3] * dots[2] - dots[1] * dots[4]) * invDenom; var v = (dots[0] * dots[4] - dots[1] * dots[2]) * invDenom; return u >= 0f && v >= 0f && u + v < 1; } public static float Area(Vector2[] points) { var n = points.Length; var area = 0f; for (int i = n - 1, j = 0; j < n; i = j++) { var iVal = points[i]; var jVal = points[j]; area += iVal.x * jVal.y - jVal.x * iVal.y; } return area * 0.5f; } } }