AR Design
UBC EML collab with UBC SALA - visualizing IoT data in AR
InterpolatedValue.cs
Go to the documentation of this file.
1 // Copyright (c) Microsoft Corporation. All rights reserved.
2 // Licensed under the MIT License. See LICENSE in the project root for license information.
3 
4 using System;
5 using UnityEngine;
6 
7 namespace HoloToolkit.Unity
8 {
15  [Serializable]
16  public abstract class InterpolatedValue<T>
17  {
18  public const float SmallNumber = 0.0000001f;
19  public const float SmallNumberSquared = SmallNumber * SmallNumber;
20 
25  public static implicit operator T(InterpolatedValue<T> interpolatedValue)
26  {
27  return interpolatedValue.Value;
28  }
29 
33  public event Action<InterpolatedValue<T>> Started;
34 
38  public event Action<InterpolatedValue<T>> Completed;
39 
43  public event Action<InterpolatedValue<T>> ValueChanged;
44 
45  private T targetValue;
46  private T startValue;
47  private float timeInterpolationStartedAt;
48  private bool firstUpdateFrameSkipped;
49  private bool skipFirstUpdateFrame;
50  private bool performingInterpolativeSnap;
51 
52  [SerializeField]
53  [Tooltip("Time the interpolator takes to get from current value to the target value")]
54  private float duration = 1.0f;
55 
59  public float Duration
60  {
61  get { return duration; }
62  set { duration = value; }
63  }
64 
65  [SerializeField]
66  [Tooltip("Time the interpolator takes to get from current value to the target value")]
67  private AnimationCurve curve = null;
68 
72  public AnimationCurve Curve
73  {
74  get { return curve; }
75  set { curve = value; }
76  }
77 
81  public bool IsValid { get { return Curve != null; } }
82 
86  public bool IsRunning { get; private set; }
87 
88  private T value;
89 
93  public T Value
94  {
95  get { return value; }
96  private set
97  {
98  if (!DoValuesEqual(this.value, value))
99  {
100  this.value = value;
101  ValueChanged.RaiseEvent(this);
102  }
103  }
104  }
105 
109  public T Target
110  {
111  get { return targetValue; }
112  }
113 
117  protected float CurrentTime
118  {
119  get
120  {
121 #if UNITY_EDITOR
122  return !Application.isPlaying ? (float)UnityEditor.EditorApplication.timeSinceStartup : Time.time;
123 #else
124  return Time.time;
125 #endif
126  }
127  }
128 
134  public InterpolatedValue(T initialValue, bool skipFirstUpdateFrame)
135  {
136  IsRunning = false;
137  Value = targetValue = initialValue;
138  Duration = 1.0f;
139  firstUpdateFrameSkipped = false;
140  this.skipFirstUpdateFrame = skipFirstUpdateFrame;
141  performingInterpolativeSnap = false;
142  }
143 
148  public void UpdateTarget(T updateTargetValue)
149  {
150  UpdateTarget(updateTargetValue, false);
151  }
152 
158  public void UpdateTarget(T updateTargetValue, bool forceUpdate)
159  {
160  performingInterpolativeSnap = false;
161 
162  targetValue = updateTargetValue;
163 
164  startValue = Value;
165  timeInterpolationStartedAt = CurrentTime;
166 
167  if (!DoValuesEqual(updateTargetValue, Value))
168  {
169  EnsureEnabled();
170  }
171  else if (forceUpdate && !IsRunning)
172  {
173  ValueChanged.RaiseEvent(this);
174  }
175  }
176 
180  public void SnapToTarget()
181  {
182  SnapToTarget(targetValue);
183  }
184 
189  public void SnapToTarget(T snapTargetValue)
190  {
191  performingInterpolativeSnap = false;
192  Value = startValue = snapTargetValue;
193  EnsureDisabled();
194  }
195 
201  public void InterpolateThenSnapToTarget(T snapTargetValue)
202  {
203  if (performingInterpolativeSnap)
204  {
205  // If we are running, just update the target, otherwise just snap to target
206  if (IsRunning)
207  {
208  targetValue = snapTargetValue;
209  }
210  else
211  {
212  Value = startValue = snapTargetValue;
213  }
214  }
215  else
216  {
217  UpdateTarget(snapTargetValue);
218  performingInterpolativeSnap = true;
219  }
220  }
221 
226  public void EnsureEnabled()
227  {
228  if (!IsRunning)
229  {
230  if (skipFirstUpdateFrame)
231  {
232  firstUpdateFrameSkipped = false;
233  }
234 
235  IsRunning = true;
236 
237  Started.RaiseEvent(this);
238  }
239  }
240 
245  public void EnsureDisabled()
246  {
247  if (IsRunning)
248  {
249  IsRunning = false;
250 
251  Completed.RaiseEvent(this);
252  }
253  }
254 
260  public T FrameUpdate()
261  {
262  if (IsRunning)
263  {
264  if (skipFirstUpdateFrame && !firstUpdateFrameSkipped)
265  {
266  firstUpdateFrameSkipped = true;
267  timeInterpolationStartedAt = CurrentTime;
268  return Value;
269  }
270 
271  float timeDelta = CurrentTime - timeInterpolationStartedAt;
272 
273  // Normalize the delta to curve duration
274  timeDelta *= Curve.Duration() / Duration;
275 
276  Value = ApplyCurveValue(startValue, targetValue, Curve.Evaluate(timeDelta));
277  if (timeDelta >= Curve.Duration())
278  {
279  EnsureDisabled();
280  }
281  }
282 
283  return Value;
284  }
285 
293  public abstract bool DoValuesEqual(T one, T other);
294 
303  public abstract T ApplyCurveValue(T startValue, T targetValue, float curveValue);
304  }
305 }
void EnsureEnabled()
Starts interpolation if it is not currently running.
void EnsureDisabled()
Stops the interpolation if it is currently running.
void UpdateTarget(T updateTargetValue)
Updates the target value and starts the interpolator if it is not running already.
void UpdateTarget(T updateTargetValue, bool forceUpdate)
Updates the target value and starts the interpolator if it is not running already.
T Value
Returns the current interpolated value.
Action< InterpolatedValue< T > > Completed
Event that is triggered when interpolation completes.
Action< InterpolatedValue< T > > Started
Event that is triggered when interpolation starts.
void SnapToTarget(T snapTargetValue)
Update the target to a new value and snap (set) the interpolated value to it.
Action< InterpolatedValue< T > > ValueChanged
Event that is triggered when the current interpolated value is changed.
InterpolatedValue(T initialValue, bool skipFirstUpdateFrame)
Instantiates a new InterpolatedValue with an initial value and a setting of whether to skip first upd...
T FrameUpdate()
Increments the interpolation step. This function should be called each frame.
Base class that provides the common logic for interpolating between values. This class does not inher...
void SnapToTarget()
Snap (set) the interpolated value to the current target value.
void InterpolateThenSnapToTarget(T snapTargetValue)
Interpolative snap to target will interpolate until it reaches the given target value, after which subsequent calls to this method it will snap to the target value given.