/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* Licensed under the Oculus SDK License Agreement (the "License");
* you may not use the Oculus SDK except in compliance with the License,
* which is provided at the time of installation or download, or which
* otherwise accompanies this software in either electronic or hard copy form.
*
* You may obtain a copy of the License at
*
* https://developer.oculus.com/licenses/oculussdk/
*
* Unless required by applicable law or agreed to in writing, the Oculus SDK
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Collections.Generic;
using System.Linq;
using UnityEngine.Assertions;
using Oculus.Interaction.Collections;
namespace Oculus.Interaction.Body.Input
{
///
/// Maps a skeleton with joint id to BodyJointId,
/// and exposes parent/child relationships within the skeleton.
///
/// The enum joint type of the source skeleton
public abstract class BodySkeletonMapping : ISkeletonMapping
where TSourceJointId : System.Enum
{
public IEnumerableHashSet Joints => _joints;
public bool TryGetParentJointId(BodyJointId jointId, out BodyJointId parentJointId)
{
return _jointToParent.TryGetValue(jointId, out parentJointId);
}
public bool TryGetSourceJointId(BodyJointId jointId, out TSourceJointId sourceJointId)
{
return _reverseMap.TryGetValue(jointId, out sourceJointId);
}
public bool TryGetBodyJointId(TSourceJointId jointId, out BodyJointId bodyJointId)
{
return _forwardMap.TryGetValue(jointId, out bodyJointId);
}
protected TSourceJointId GetSourceJointFromBodyJoint(BodyJointId jointId)
{
return _reverseMap[jointId];
}
protected BodyJointId GetBodyJointFromSourceJoint(TSourceJointId sourceJointId)
{
return _forwardMap[sourceJointId];
}
protected BodySkeletonMapping(TSourceJointId root,
IReadOnlyDictionary jointMapping)
{
_tree = new SkeletonTree(root, jointMapping);
_joints = new EnumerableHashSet(_tree.Nodes.Select(n => n.BodyJointId));
_forwardMap = _tree.Nodes.ToDictionary((n) => n.SourceJointId, (n) => n.BodyJointId);
_reverseMap = _tree.Nodes.ToDictionary((n) => n.BodyJointId, (n) => n.SourceJointId);
_jointToParent = _tree.Nodes.ToDictionary((n) => n.BodyJointId, (n) => n.Parent.BodyJointId);
}
private readonly SkeletonTree _tree;
private readonly IEnumerableHashSet _joints;
private readonly IReadOnlyDictionary _forwardMap;
private readonly IReadOnlyDictionary _reverseMap;
private readonly IReadOnlyDictionary _jointToParent;
private class SkeletonTree
{
public readonly Node Root;
public readonly IReadOnlyList Nodes;
public SkeletonTree(TSourceJointId root,
IReadOnlyDictionary mapping)
{
Dictionary nodes = new Dictionary();
foreach (var map in mapping)
{
BodyJointId jointId = map.Key;
JointInfo jointInfo = map.Value;
Assert.IsFalse(nodes.ContainsKey(jointInfo.SourceJointId),
"Duplicate Joint ID in Mapping");
nodes[jointInfo.SourceJointId] =
new Node(jointInfo.SourceJointId, jointId);
}
foreach (var jointInfo in mapping.Values)
{
Node thisNode = nodes[jointInfo.SourceJointId];
thisNode.Parent = nodes[jointInfo.ParentJointId];
thisNode.Parent.Children.Add(thisNode);
}
Nodes = new List(nodes.Values);
Root = nodes[root];
}
public class Node
{
public readonly TSourceJointId SourceJointId;
public readonly BodyJointId BodyJointId;
public Node Parent;
public List Children = new List();
public Node(TSourceJointId sourceJointId, BodyJointId bodyJointId)
{
SourceJointId = sourceJointId;
BodyJointId = bodyJointId;
}
}
}
protected readonly struct JointInfo
{
public readonly TSourceJointId SourceJointId;
public readonly TSourceJointId ParentJointId;
public JointInfo(
TSourceJointId sourceJointId,
TSourceJointId parentJointId)
{
SourceJointId = sourceJointId;
ParentJointId = parentJointId;
}
}
}
}