Editor/Core/Validation/ValidationGeometry.cs
namespace HumanoidRigger;
using Vector3=System.Numerics.Vector3;

/// <summary>Immutable mesh evidence shared only within one rig-generation call.
/// Weights, bone frames and every stress pose are still checked for each trial.</summary>
internal sealed class ValidationGeometry
{
    readonly Lazy<Vector3[]> body;
    readonly Lazy<BindTriangle[][]> faces;
    readonly Lazy<List<int>[][]> neighbors,touching;
    readonly Dictionary<Vector3,float> jointDistances=[];
    internal float Height {get;}
    internal Vector3[] Body=>body.Value;
    internal BindTriangle[][] Faces=>faces.Value;
    internal List<int>[][] Neighbors=>neighbors.Value;
    internal List<int>[][] Touching=>touching.Value;
    internal ValidationGeometry(ImportedCharacter character)
    {
        Height=character.AnatomicalHeight;
        body=new(()=>character.Meshes.Where(m=>m.Kind==MeshKind.Body).SelectMany(m=>m.Vertices).ToArray());
        faces=new(()=>character.Meshes.Select(BindTriangle.Measure).ToArray());
        neighbors=new(()=>character.Meshes.Select(m=>Geometry.Neighbors(m)).ToArray());
        touching=new(()=>
        {
            var result=character.Meshes.Select(m=>m.Vertices.Select(_=>new List<int>()).ToArray()).ToArray();
            for(int p=0;p<Faces.Length;p++)for(int t=0;t<Faces[p].Length;t++)
            {var f=Faces[p][t];result[p][f.A].Add(t);result[p][f.B].Add(t);result[p][f.C].Add(t);}
            return result;
        });
    }
    internal float JointDistanceSquared(Vector3 point)
    {
        if(!jointDistances.TryGetValue(point,out float distance))jointDistances[point]=distance=Body.Min(p=>Vector3.DistanceSquared(p,point));
        return distance;
    }
}