Editor/Core/Analysis/HandCountFitting.cs
namespace HumanoidRigger;
using Vector3=System.Numerics.Vector3;

/// <summary>An explicit digit count is anatomical input. Unresolved chains remain low-confidence for review.</summary>
internal static class HandCountFitting
{
    public static void Apply(ImportedCharacter character,Anatomy anatomy,string side,int count)
    {
        var fingers=count==1?new[]{"Index"}:Profiles.Fingers.Take(count).ToArray();
        foreach(var key in anatomy.Points.Keys.Where(k=>k.EndsWith("."+side)&&Profiles.Fingers.Any(k.StartsWith)&&!fingers.Any(k.StartsWith)).ToArray())anatomy.Points.Remove(key);
        anatomy.Warnings.RemoveAll(w=>w.StartsWith(side+" hand")||w.StartsWith(side+" fingers"));
        if(count==0)return;
        var wrist=anatomy["Hand."+side];var forward=Vector3.Normalize(wrist-anatomy["LowerArm."+side]);
        var normal=anatomy.Hands.TryGetValue(side,out var frame)?frame.Normal:Vector3.UnitZ;
        var across=Vector3.Cross(normal,forward);
        if(across.LengthSquared()<1e-8f)across=Vector3.Cross(Math.Abs(forward.Z)<.9f?Vector3.UnitZ:Vector3.UnitY,forward);
        across=Vector3.Normalize(across)*(side=="L"?1:-1);
        if(anatomy.Points.TryGetValue("ThumbTip."+side,out var thumb)&&Vector3.Dot(thumb.Position-wrist,across)<0)across=-across;
        var surface=character.Meshes.Where(m=>m.Kind==MeshKind.Body).SelectMany(m=>m.Vertices).Where(p=>Vector3.Distance(p,wrist)<anatomy.Height*.13f).ToArray();
        int unresolved=0;
        for(int f=0;f<fingers.Length;f++)
        {
            var finger=fingers[f];if(anatomy.Points.ContainsKey(finger+"Tip."+side))continue;unresolved++;
            int ordinal=Array.IndexOf(Profiles.Fingers,finger);
            float spread=(2-ordinal)*anatomy.Height*.009f;
            var start=wrist+forward*anatomy.Height*(finger=="Thumb"?.015f:.03f)+across*spread;
            var direction=Vector3.Normalize(forward+across*(finger=="Thumb"?.8f:0));
            float length=anatomy.Height*(finger=="Pinky"?.035f:finger=="Thumb"?.04f:.05f);
            for(int joint=0;joint<4;joint++)
            {
                var seed=start+direction*length*(joint/3f);
                var center=surface.Length>3?BodyDetector.RefineCenter(surface,seed,direction,anatomy.Height*.008f):seed;
                string role=finger+(joint==3?"Tip":(joint+1).ToString())+"."+side;
                anatomy.Set(role,center,.2f);
            }
        }
        if(unresolved>0)anatomy.Warnings.Add($"{side} hand: {unresolved} finger chain(s) need adjustment. Their positions could not be determined reliably.");
    }
}