Code/AutoRig/Solve/Organic/GraphSkeletonBuilder.cs

Builds a generic RigSkeleton from a curve SkeletonGraph by creating one RigJoint per graph node. It BFS-traverses from the core, assigns a root joint, groups nodes into branch chains when leaving the core or at junctions, names joints like "limb{branch}_{link:00}", sets parent indices and positions, then validates and returns the skeleton.

NetworkingFile AccessHttp Calls
using AutoRig.Rig;

namespace AutoRig.Solve.Organic;

/// <summary>
/// Builds a generic rig straight from the curve skeleton: one joint per graph node,
/// rooted at the core, chains named per branch ("limb1_01", …). Used for organic
/// categories without a dedicated template.
/// </summary>
public static class GraphSkeletonBuilder
{
    public static RigSkeleton Build( SkeletonGraph graph )
    {
        ArgumentNullException.ThrowIfNull( graph );

        var skeleton = new RigSkeleton();
        if ( graph.Nodes.Count == 0 )
            throw new FormatException( "Curve skeleton has no nodes." );

        var jointOf = new int[graph.Nodes.Count];
        Array.Fill( jointOf, -1 );

        // BFS from core so parents precede children.
        var queue = new Queue<int>();
        queue.Enqueue( graph.Core );
        jointOf[graph.Core] = 0;
        skeleton.Joints.Add( new RigJoint
        {
            Name = "root",
            Parent = -1,
            Position = graph.Nodes[graph.Core].Position,
        } );

        var branchCounter = 0;
        var branchOf = new int[graph.Nodes.Count];        // branch id per node
        var linkOf = new int[graph.Nodes.Count];          // index within its branch chain
        branchOf[graph.Core] = -1;

        while ( queue.Count > 0 )
        {
            var current = queue.Dequeue();
            foreach ( var next in graph.Nodes[current].Neighbors.OrderBy( n => n ) )
            {
                if ( jointOf[next] >= 0 )
                    continue;

                // New branch starts when leaving the core or a junction.
                int branch, link;
                if ( current == graph.Core || graph.Nodes[current].Neighbors.Count >= 3 )
                {
                    branch = ++branchCounter;
                    link = 1;
                }
                else
                {
                    branch = branchOf[current];
                    link = linkOf[current] + 1;
                }
                branchOf[next] = branch;
                linkOf[next] = link;

                jointOf[next] = skeleton.Joints.Count;
                skeleton.Joints.Add( new RigJoint
                {
                    Name = $"limb{branch}_{link:00}",
                    Parent = jointOf[current],
                    Position = graph.Nodes[next].Position,
                } );
                queue.Enqueue( next );
            }
        }

        skeleton.Validate();
        return skeleton;
    }
}