private void RecordHistory() { var historyPoint = new HistoryDataPoint( LocalTime.Value, Owner.transform.position, Owner.transform.rotation.eulerAngles.z ); if (history.Count < 2) { // We added a first point when the recording started. Add a second one. history.Add(historyPoint); } else { HistoryDataPoint point_n_1 = history[history.Count - 1]; HistoryDataPoint point_n_2 = history[history.Count - 2]; if (Mathf.Abs(point_n_1.Time - point_n_2.Time) >= TimeResolution) { // There is enough gap between the last two measures ; add one more. history.Add(historyPoint); LogDebug($"Recorded new point at index {history.Count - 1}: {historyPoint}"); } else { // The last two points were very close; replace the most recent one. history[history.Count - 1] = historyPoint; LogDebug($"Updated index {history.Count - 1}: {historyPoint}"); } } }
public static HistoryDataPoint Lerp(HistoryDataPoint p1, HistoryDataPoint p2, float ratio) { if (ratio < 0 || ratio > 1) { throw new ArgumentOutOfRangeException($"Interpolation ratio only has meaning in the [0, 1] range ({ratio} given)."); } return(new HistoryDataPoint( (1 - ratio) * p1.Time + ratio * p2.Time, Vector3.Lerp(p1.Position, p2.Position, ratio), (1 - ratio) * p1.Angle + ratio * p2.Angle )); }
/// <summary> /// Ratio of the current time in the specified interval. May go beyond [0, 1] /// </summary> private float GetUnboundedRatioInInterval(HistoryDataPoint p1, HistoryDataPoint p2) { float p1Time = p1.Time; float p2Time = p2.Time; if (p1Time != p2Time) { return(Mathf.Sign(p2Time - p2Time) * (LocalTime.Value - p1Time) / (p2Time - p1Time)); } else if (LocalTime.Value == p1Time) { // Anything between 0 and 1 would do. return(0.5f); } else { // What is the ratio if we're outside of a zero-width interval !? throw new ArgumentException("Invalid ratio computation using a zero-width interval"); } }
internal IEnumerable <HistoryDataPoint> PrepareDataPoints(uint contractId, TimeBarReport report) { if (report.time_bar == null) { yield break; } foreach (var bar in report.time_bar) { var dataPoint = new HistoryDataPoint( adapter.ResolveDateTime(bar.bar_utc_time), instrumentResolver.ConvertPriceBack(contractId, bar.high_price), instrumentResolver.ConvertPriceBack(contractId, bar.low_price), instrumentResolver.ConvertPriceBack(contractId, bar.open_price), instrumentResolver.ConvertPriceBack(contractId, bar.close_price), (int)bar.volume, (int)bar.open_interest); yield return(dataPoint); } }
private bool IsCurrentInterval(HistoryDataPoint p1, HistoryDataPoint p2) { float timeNow = LocalTime.Value; return((p1.Time - timeNow) * (p2.Time - timeNow) <= 0); }
private void DoPlayback() { int nPoints = history.Count; int ivMinIndex = 0; int ivMaxIndex = nPoints - 2; // -1 because indices; -1 because there is one less intervals than points. if (ivMaxIndex >= 0) { float timeNow = LocalTime.Value; int? properIntervalIndex = null; while (true) { int pivotIndex = (ivMinIndex + ivMaxIndex) / 2; HistoryDataPoint pivotBound1 = history[pivotIndex]; HistoryDataPoint pivotBound2 = history[pivotIndex + 1]; if (IsCurrentInterval(pivotBound1, pivotBound2)) { // Check the pivot interval. If it matches, exit the loop properIntervalIndex = pivotIndex; break; } else if (ivMinIndex != ivMaxIndex) { // There are more intervals to explore, let's split the search space either on the left or right bool checkLeft = (TimeDirectionSign * (timeNow - pivotBound1.Time) < 0); if (checkLeft && ivMinIndex == pivotIndex || !checkLeft && ivMaxIndex == pivotIndex) { LogError($"Failed to locate the interval for local time {timeNow} in the history."); break; } else { if (checkLeft) { ivMaxIndex = pivotIndex - 1; } else { ivMinIndex = pivotIndex + 1; } } } else { LogError("Unable to locate the interval where a value should be taken in the history."); break; } } if (properIntervalIndex.HasValue) { // Get the position and rotation to apply HistoryDataPoint p1 = history[properIntervalIndex.Value]; HistoryDataPoint p2 = history[properIntervalIndex.Value + 1]; float intervalRatio = GetUnboundedRatioInInterval(p1, p2); HistoryDataPoint interpolation = HistoryDataPoint.Lerp(p1, p2, intervalRatio); LogDebug($"Applying saved point: {interpolation}"); // Apply these to the object var rb = GetTargetRigidbody(); rb.MovePosition(interpolation.Position); rb.MoveRotation(interpolation.Angle); // Discard things that were played back while (history.Count > properIntervalIndex.Value + 2) { history.RemoveAt(history.Count - 1); } } } else { LogError( "Unable to playback an (almost) empty history. This action should have maybe be completed by now.\n" + $" * History times = [{history.Aggregate("", (s, p) => (string.IsNullOrEmpty(s) ? s : s + ", ") + p.Time.ToString())}], " + $"time now = {LocalTime}."); } }
public void AddPoint(int tickerId, HistoryDataPoint point) => GetHandler(tickerId, remove: false)?.AddPoint(point);