Editor/Core/Validation/SeamWeightRepair.cs
#nullable enable annotations
namespace HumanoidRigger;

/// <summary>Close authored surface seams, then refit their neighborhoods against every pose.
/// Equal weights at equal positions guarantee seam closure for arbitrary bone motion.</summary>
internal static class SeamWeightRepair
{
    internal static GeneratedRig Improve(ImportedCharacter character,GeneratedRig rig,ValidationGeometry? geometry=null)
    {
        if(!rig.Report.Passed)return rig;
        var seams=new SurfaceSeams(character);int gaps=seams.Mismatches(rig.Weights);
        if(gaps==0)return rig;
        var candidate=new GeneratedRig{Profile=rig.Profile,Bones=rig.Bones,Anatomy=rig.Anatomy,Weights=seams.Couple(rig)};
        geometry??=new ValidationGeometry(character);
        candidate.Report=RigValidator.Validate(character,candidate,null,geometry);
        var checks=JointCoverage.Measure(character,candidate,geometry);
        candidate=PoseWeightRepair.Improve(character,candidate,geometry,checks);
        checks=JointCoverage.Measure(character,candidate,geometry);
        bool Safe(StressResult p)=>p.NonFiniteVertices==0&&p.NonFiniteMeasurements==0&&p.ReversedTriangles==0&&p.MaximumStretch<=4&&p.MinimumAreaRatio>=.025f;
        // Closing seams must not bring a limb onto the torso. A rig that already
        // carries that warning is no reason to leave its seams open as well.
        var trunk=new TrunkRegion(character,rig);
        if(candidate.Report.Passed&&candidate.Report.StressTests.All(Safe)&&checks.All(c=>Safe(c.Result))&&seams.Mismatches(candidate.Weights)==0&&
            (trunk.HasBleeding(character,rig)||!trunk.HasBleeding(character,candidate)))
        {
            candidate.Report.Repairs=rig.Report.Repairs+candidate.Weights.SelectMany((p,m)=>p.Select((w,v)=>w.SequenceEqual(rig.Weights[m][v])?0:1)).Sum();
            candidate.Report.RepairPasses+=rig.Report.RepairPasses+1;
            candidate.Report.JointStressTests.AddRange(checks.Select(c=>c.Result));
            return candidate;
        }
        rig.Report.Issues.Add(new("surface-seam",$"{gaps} split surface seams still have unequal weights and may open during movement.",true));
        return rig;
    }
}