evershade/Packages/super-tiled2unity.v2.2.0/Editor/Collision/Geometry/ComposeConvexPolygons.cs

66 lines
2.4 KiB
C#

using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace SuperTiled2Unity.Editor.Geometry
{
// Input is a collection of triangles and output is a collection of convex polygons
// We remove shared edges along triangles were we can using the Hertel-Mehlhorn Algorithm
public class ComposeConvexPolygons
{
public PolygonEdgeGroup PolygonEdgeGroup { get; }
public List<Vector2[]> ConvexPolygons { get; private set; }
public ComposeConvexPolygons()
{
PolygonEdgeGroup = new PolygonEdgeGroup();
}
public List<Vector2[]> Compose(List<Vector2[]> triangles)
{
PolygonEdgeGroup.Initialize(triangles);
CombinePolygons();
return this.ConvexPolygons;
}
private void CombinePolygons()
{
// Before we start merging polygons keep a list of all the ones we have
List<CompositionPolygon> convexPolygons = new List<CompositionPolygon>();
foreach (var edge in PolygonEdgeGroup.PolygonEdges)
{
if (edge.MajorPartner != null)
{
convexPolygons.Add(edge.MajorPartner);
}
if (edge.MinorPartner != null)
{
convexPolygons.Add(edge.MinorPartner);
}
}
convexPolygons = convexPolygons.Distinct().ToList();
// Remove edges that don't have both partners since we can't possibly merge on them
PolygonEdgeGroup.PolygonEdges.RemoveAll(e => e.MinorPartner == null || e.MajorPartner == null);
// Now try to remove edges by merging the polygons on both sides
// We try to remove the longest edges first as, in general, it gives us solutions that avoid long splinters
var edgesByLength = PolygonEdgeGroup.PolygonEdges.OrderByDescending(edge => edge.Length2);
foreach (var edge in edgesByLength)
{
if (edge.CanMergePolygons())
{
// Remove the minor polygon from our list of convex polygons and merge
convexPolygons.Remove(edge.MinorPartner);
edge.MergePolygons();
}
}
ConvexPolygons = convexPolygons.Select(cp => cp.Points.ToArray()).ToList();
}
}
}