using System.Collections.Generic; using System.Linq; using SuperTiled2Unity.Editor.LibTessDotNet; using UnityEngine; namespace SuperTiled2Unity.Editor.Geometry { // Input is a ClipperLib solution and output is a collection of triangles public class Triangulator { public List TriangulateClipperSolution(ClipperLib.PolyTree solution) { var tess = new Tess(); tess.NoEmptyPolygons = true; // Add a contour for each part of the solution tree ClipperLib.PolyNode node = solution.GetFirst(); while (node != null) { // Only interested in closed paths if (!node.IsOpen) { // Add a new countor. Holes are automatically generated. var vertices = node.Contour.Select(pt => new ContourVertex { Position = new Vec3 { X = pt.X, Y = pt.Y, Z = 0 } }).ToArray(); tess.AddContour(vertices); } node = node.GetNext(); } return TrianglesFromTessellator(tess); } public List TriangulatePolygon(Vector2[] points) { var tess = new Tess(); tess.NoEmptyPolygons = true; var vertices = points.Select(pt => new ContourVertex { Position = new Vec3 { X = pt.x, Y = pt.y, Z = 0 } }).ToArray(); tess.AddContour(vertices); return TrianglesFromTessellator(tess); } private List TrianglesFromTessellator(Tess tess) { var triangles = new List(); // Do the tessellation tess.Tessellate(WindingRule.EvenOdd, ElementType.Polygons, 3); // Extract the triangles int numTriangles = tess.ElementCount; for (int i = 0; i < numTriangles; i++) { var v0 = tess.Vertices[tess.Elements[i * 3 + 0]].Position; var v1 = tess.Vertices[tess.Elements[i * 3 + 1]].Position; var v2 = tess.Vertices[tess.Elements[i * 3 + 2]].Position; var triangle = new List() { new Vector2(v0.X, v0.Y), new Vector2(v1.X, v1.Y), new Vector2(v2.X, v2.Y), }; // Assume each triangle needs to be CCW float cross = GeoMath.Cross(triangle[0], triangle[1], triangle[2]); if (cross > 0) { triangle.Reverse(); } triangles.Add(triangle.ToArray()); } return triangles; } } }