Editor/Core/Analysis/WristFitting.cs
#nullable enable annotations
namespace HumanoidRigger;
using Vector3=System.Numerics.Vector3;

/// <summary>Finds the forearm bottleneck before the palm expands, using closed mesh sections.</summary>
public static class WristFitting
{
    public static Vector3? Detect(ImportedCharacter character,Anatomy anatomy,string side)
    {
        var wrist=anatomy["Hand."+side];var axis=Vector3.Normalize(wrist-anatomy["LowerArm."+side]);float h=anatomy.Height;
        var sections=new List<(float Offset,MeshSections.Section Section)>();
        for(int i=0;i<=66;i++)
        {
            float offset=h*(-.12f+i*.00225f);var seed=wrist+axis*offset;
            var section=MeshSections.Cut(character,seed,axis,h*.085f,h*.00001f).Where(s=>Vector3.Distance(s.Center,seed)<h*.04f).MinBy(s=>Vector3.Distance(s.Center,seed));
            if(section is not null)sections.Add((offset,section));
        }
        MeshSections.Section? best=null;float bestScore=0;
        foreach(var (offset,section) in sections)
        {
            if(section.Radius<h*.01f||section.Radius>h*.045f)continue;
            if(sections.Any(s=>Math.Abs(s.Offset-offset)<h*.006f&&s.Section.Area<section.Area*.999f))continue;
            var proximal=sections.Where(s=>s.Offset<offset-h*.02f&&s.Offset>offset-h*.045f).ToArray();
            var distal=sections.Where(s=>s.Offset>offset+h*.02f&&s.Offset<offset+h*.055f).ToArray();
            if(proximal.Length<4||distal.Length<4)continue;
            float before=proximal.Average(s=>s.Section.Area)/section.Area,after=distal.Max(s=>s.Section.Radius)/section.Radius;
            if(before<1.15f||after<1.12f)continue;
            float score=MathF.Log(before)*.5f+MathF.Log(after)-Math.Abs(offset)/h*.5f;
            if(score>bestScore){bestScore=score;best=section;}
        }
        return best?.Center;
    }
}