/******************************************************************************
* Copyright (C) Ultraleap, Inc. 2011-2021. *
* *
* Use subject to the terms of the Apache License 2.0 available at *
* http://www.apache.org/licenses/LICENSE-2.0, or another agreement *
* between Ultraleap and you, your company or other organization. *
******************************************************************************/
using UnityEngine;
namespace Leap.Unity
{
///
/// Implements a resample-able transform history.
///
public class TransformHistory
{
public RingBuffer history;
public TransformHistory(int capacity = 32)
{
history = new RingBuffer(capacity);
}
//Store current Transform in History
public void UpdateDelay(Pose curPose, long timestamp)
{
TransformData currentTransform =
new TransformData()
{
time = timestamp,
position = curPose.position,
rotation = curPose.rotation,
};
history.Add(currentTransform);
}
//Calculate delayed Transform
public void SampleTransform(long timestamp, out Vector3 delayedPos, out Quaternion delayedRot)
{
TransformData desiredTransform = TransformData.GetTransformAtTime(history, timestamp);
delayedPos = desiredTransform.position;
delayedRot = desiredTransform.rotation;
}
public struct TransformData
{
public long time; // microseconds
public Vector3 position; //meters
public Quaternion rotation; //magic
public static TransformData Lerp(TransformData from, TransformData to, long time)
{
if (from.time == to.time)
{
return from;
}
float fraction = (float)(((double)(time - from.time)) / ((double)(to.time - from.time)));
return new TransformData()
{
time = time,
position = Vector3.Lerp(from.position, to.position, fraction),
rotation = Quaternion.Slerp(from.rotation, to.rotation, fraction)
};
}
public static TransformData GetTransformAtTime(RingBuffer history, long desiredTime)
{
for (int i = history.Count - 1; i > 0; i--)
{
if (history.Get(i).time >= desiredTime && history.Get(i - 1).time < desiredTime)
{
return Lerp(history.Get(i - 1), history.Get(i), desiredTime);
}
}
if (history.Count > 0)
{
return history.GetLatest();
}
else
{
// No history data available.
return new TransformData()
{
time = desiredTime,
position = Vector3.zero,
rotation = Quaternion.identity
};
}
}
}
}
}