// Copyright (c) Meta Platforms, Inc. and affiliates. All rights reserved.
using System;
using System.Collections.Generic;
using System.Linq;
namespace Meta.XR.Movement.FaceTracking.Samples
{
///
/// Mapper class. Used by to map from
/// weights provider names to drivers (or blendshapes on character).
///
public class Mapper
{
private class Rule
{
public int FirstIndex;
public int SecondIndex;
public Rule(int first, int second)
{
FirstIndex = first;
SecondIndex = second;
}
}
private readonly Rule[] _rules;
private readonly int _expectedSrcSize, _expectedDstSize;
///
/// Main constructor where source and destination names are mapped to each other and stored.
///
/// Source names.
/// Destination names.
/// Warning in case source name is not found in destination.
/// Warning if any names rename in destination after mapping has completed.
public Mapper(IList src, IList dest, Action> warnIfSrcNotFound, Action> warnIfDestNotDriven)
{
_expectedSrcSize = src.Count;
_expectedDstSize = dest.Count;
var notFound = new SortedSet();
var remainderInDest = dest.ToHashSet();
if (src.Count == 0)
{
foreach (var s in src)
{
notFound.Add(s);
}
}
if (dest.Count > 0 && src.Count > 0)
{
List rules = new List();
for (var i = 0; i < src.Count; ++i)
{
var index = dest.IndexOf(src[i]);
if (index < 0)
{
notFound.Add(src[i]);
}
else
{
rules.Add(new Rule(i, index));
remainderInDest.Remove(dest[index]);
}
}
_rules = rules.ToArray();
}
if (notFound.Count > 0 && warnIfSrcNotFound != null)
{
warnIfSrcNotFound(notFound);
}
if (remainderInDest.Count > 0 && warnIfDestNotDriven != null)
{
warnIfDestNotDriven(remainderInDest);
}
}
///
/// Uses stored mapping to map from source to destination.
///
/// Source values.
/// Destination values.
/// Exception thrown if a problem is encountered.
public void Map(float[] src, float[] dest)
{
if (src.Length != _expectedSrcSize)
{
throw new ArgumentException($"Expected source to be of length {_expectedSrcSize}, got {src.Length}");
}
if (dest.Length != _expectedDstSize)
{
throw new ArgumentException($"Expected destination to be of length {_expectedDstSize}, got {dest.Length}");
}
foreach (var t in _rules)
{
dest[t.SecondIndex] = src[t.FirstIndex];
}
}
}
}