Code/Core/Mapping/HandRigDefinition.cs
#nullable enable
namespace HumanoidHandRetargeter.Mapping;
public enum HandSide { Left, Right }
public enum DigitRole { Thumb, Index, Middle, Ring, Pinky, Extra }
/// <summary>Ordered anatomical joints; optional palm and terminal bones are explicit.</summary>
public sealed class DigitChain
{
public DigitRole Role { get; }
public string ExtraSlot { get; }
public IReadOnlyList<int> Segments { get; }
public int? Metacarpal { get; }
public int? Tip { get; }
public DigitChain(DigitRole role, IEnumerable<int> segments,
int? metacarpal = null, int? tip = null, string extraSlot = "")
{
ArgumentNullException.ThrowIfNull(segments);
Role = role;
Segments = Array.AsReadOnly(segments.ToArray());
Metacarpal = metacarpal;
Tip = tip;
ExtraSlot = extraSlot ?? "";
}
public IEnumerable<int> Bones
{
get
{
if (Metacarpal is int palm) yield return palm;
foreach (var segment in Segments) yield return segment;
if (Tip is int tip) yield return tip;
}
}
}
/// <summary>A single hand; rigs with only one side do not need a placeholder other hand.</summary>
public sealed class HandRigDefinition
{
public HandSide Side { get; }
public int Wrist { get; }
public int? Clavicle { get; }
public int? UpperArm { get; }
public int? Forearm { get; }
public IReadOnlyList<DigitChain> Digits { get; }
public IReadOnlyList<int> TwistOrHelperBones { get; }
public HandRigDefinition(HandSide side, int wrist, IEnumerable<DigitChain> digits,
int? clavicle = null, int? upperArm = null, int? forearm = null,
IEnumerable<int>? twistOrHelperBones = null)
{
ArgumentNullException.ThrowIfNull(digits);
Side = side;
Wrist = wrist;
Clavicle = clavicle;
UpperArm = upperArm;
Forearm = forearm;
Digits = Array.AsReadOnly(digits.ToArray());
TwistOrHelperBones = Array.AsReadOnly((twistOrHelperBones ?? Array.Empty<int>()).ToArray());
}
}