Code/AutoRig/Solve/AutoRigger.cs

Facade that chooses and runs an appropriate rigging solver for an analyzed mesh. It routes based on explicit RigMode or a classifier, validates results, and falls back to geometric or floor rigs on failure or if required resources are missing.

Reflection
using AutoRig.Analyze;
using AutoRig.Rig;

namespace AutoRig.Solve;

/// <summary>Which solver family to use. Auto lets the classifier route.</summary>
public enum RigMode
{
    Auto,
    Mechanical,
    Organic,
    Floor,
    /// <summary>Neural rigging; needs an installed model (see <see cref="RigNetBundle"/>).</summary>
    DeepLearning,
    /// <summary>Copy skeleton + weights from a rigged donor model (see <see cref="Rig.DonorRig"/>).</summary>
    Transfer,
}

/// <summary>
/// The solver façade: routes an analyzed mesh to the right solver and guarantees a
/// valid result for any mesh that passed <see cref="Mesh.RigMesh.Validate"/> — solver
/// failures degrade to the floor rig instead of throwing.
/// </summary>
public static class AutoRigger
{
    /// <param name="deepLearning">Loaded neural model; required for
    /// <see cref="RigMode.DeepLearning"/>. Without one that mode degrades to the
    /// geometric route (marked Degraded with an explanation).</param>
    /// <param name="donor">Rigged donor; required for <see cref="RigMode.Transfer"/>
    /// (same degrade rule).</param>
    public static RigResult Rig(
        AnalysisResult analysis, RigMode mode = RigMode.Auto,
        RigNetBundle deepLearning = null, Rig.DonorRig donor = null )
    {
        ArgumentNullException.ThrowIfNull( analysis );

        if ( (mode == RigMode.DeepLearning && deepLearning is null)
            || (mode == RigMode.Transfer && donor is null) )
        {
            var geometric = Rig( analysis, RigMode.Auto );
            return new RigResult
            {
                Skeleton = geometric.Skeleton,
                Weights = geometric.Weights,
                SolverName = geometric.SolverName,
                Degraded = true,
                Explanation = (mode == RigMode.Transfer
                        ? "No donor model was picked - used the geometric solver instead. "
                        : "No deep-learning model is installed - used the geometric solver instead. ")
                    + geometric.Explanation,
            };
        }

        try
        {
            var result = mode switch
            {
                RigMode.Mechanical => MechanicalSolver.Rig( analysis ),
                RigMode.Organic => OrganicSolver.Rig( analysis ),
                RigMode.Floor => FloorSolver.Rig( analysis ),
                RigMode.DeepLearning => DeepLearningSolver.Rig( analysis, deepLearning ),
                RigMode.Transfer => TransferSolver.Rig( analysis, donor ),
                _ => analysis.Classification.Kind == MeshKind.Mechanical
                    ? MechanicalSolver.Rig( analysis )
                    : OrganicSolver.Rig( analysis ),
            };
            result.Skeleton.Validate();
            result.Weights.Validate( analysis.Mesh, result.Skeleton );
            return result;
        }
        catch ( Exception e )
        {
            // Failed neural/transfer rigs fall back to the geometric route first.
            if ( mode is RigMode.DeepLearning or RigMode.Transfer )
            {
                var geometric = Rig( analysis, RigMode.Auto );
                return new RigResult
                {
                    Skeleton = geometric.Skeleton,
                    Weights = geometric.Weights,
                    SolverName = geometric.SolverName,
                    Degraded = true,
                    Explanation = $"The {mode} solver failed ({FirstLine( e.Message )}) - "
                        + "used the geometric solver instead.",
                };
            }
            var floor = FloorSolver.Rig( analysis );
            return new RigResult
            {
                Skeleton = floor.Skeleton,
                Weights = floor.Weights,
                SolverName = floor.SolverName,
                Degraded = true,
                Explanation = $"The {mode} solver failed ({FirstLine( e.Message )}) - "
                    + "produced a single-bone rig instead.",
            };
        }
    }

    static string FirstLine( string text )
    {
        var i = text.IndexOfAny( [ '\r', '\n' ] );
        return i < 0 ? text : text[..i];
    }
}