feat: add bounded visualization snapshots
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace TrajectoryPlanningVisualization;
|
||||
|
||||
public sealed class BoundedCycleHistory
|
||||
{
|
||||
private readonly object sync = new object();
|
||||
private readonly int capacity;
|
||||
private readonly Queue<VisualizationCycleSummary> entries = new Queue<VisualizationCycleSummary>();
|
||||
private readonly HashSet<long> versions = new HashSet<long>();
|
||||
|
||||
public BoundedCycleHistory(int capacity)
|
||||
{
|
||||
if (capacity <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(capacity));
|
||||
}
|
||||
|
||||
this.capacity = capacity;
|
||||
}
|
||||
|
||||
public void Add(VisualizationCycleSummary summary)
|
||||
{
|
||||
if (summary == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(summary));
|
||||
}
|
||||
|
||||
lock (sync)
|
||||
{
|
||||
if (!versions.Add(summary.CycleVersion))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
entries.Enqueue(summary);
|
||||
while (entries.Count > capacity)
|
||||
{
|
||||
VisualizationCycleSummary removed = entries.Dequeue();
|
||||
versions.Remove(removed.CycleVersion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IReadOnlyList<VisualizationCycleSummary> Snapshot()
|
||||
{
|
||||
lock (sync)
|
||||
{
|
||||
return new ReadOnlyCollection<VisualizationCycleSummary>(
|
||||
new List<VisualizationCycleSummary>(entries));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace TrajectoryPlanningVisualization;
|
||||
|
||||
public sealed class VisualizationFrame
|
||||
{
|
||||
public VisualizationFrame(long version, PlanningVisualizationDynamicSnapshot snapshot)
|
||||
{
|
||||
Version = version;
|
||||
Snapshot = snapshot ?? throw new ArgumentNullException(nameof(snapshot));
|
||||
}
|
||||
|
||||
public long Version { get; }
|
||||
public PlanningVisualizationDynamicSnapshot Snapshot { get; }
|
||||
}
|
||||
|
||||
public sealed class LatestVisualizationFrameStore
|
||||
{
|
||||
private VisualizationFrame latest;
|
||||
private long nextVersion;
|
||||
|
||||
public void Publish(PlanningVisualizationDynamicSnapshot snapshot)
|
||||
{
|
||||
if (snapshot == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(snapshot));
|
||||
}
|
||||
|
||||
long version = Interlocked.Increment(ref nextVersion);
|
||||
Interlocked.Exchange(ref latest, new VisualizationFrame(version, snapshot));
|
||||
}
|
||||
|
||||
public bool TryReadAfter(long version, out VisualizationFrame frame)
|
||||
{
|
||||
VisualizationFrame current = Volatile.Read(ref latest);
|
||||
if (current == null || current.Version <= version)
|
||||
{
|
||||
frame = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
frame = current;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
|
||||
namespace TrajectoryPlanningVisualization;
|
||||
|
||||
public sealed class PlanningVisualizationOptions
|
||||
{
|
||||
public int Port { get; set; } = 0;
|
||||
public int RefreshRateHz { get; set; } = 10;
|
||||
public int HistoryCycleLimit { get; set; } = 60;
|
||||
|
||||
public PlanningVisualizationOptionsSnapshot CreateValidatedSnapshot()
|
||||
{
|
||||
if (Port < 0 || Port > 65535)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Port), "Port must be in the range 0 to 65535.");
|
||||
}
|
||||
|
||||
if (RefreshRateHz <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(RefreshRateHz), "Refresh rate must be positive.");
|
||||
}
|
||||
|
||||
if (HistoryCycleLimit <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(HistoryCycleLimit), "History cycle limit must be positive.");
|
||||
}
|
||||
|
||||
return new PlanningVisualizationOptionsSnapshot(Port, RefreshRateHz, HistoryCycleLimit);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class PlanningVisualizationOptionsSnapshot
|
||||
{
|
||||
internal PlanningVisualizationOptionsSnapshot(int port, int refreshRateHz, int historyCycleLimit)
|
||||
{
|
||||
Port = port;
|
||||
RefreshRateHz = refreshRateHz;
|
||||
HistoryCycleLimit = historyCycleLimit;
|
||||
}
|
||||
|
||||
public int Port { get; }
|
||||
public int RefreshRateHz { get; }
|
||||
public int HistoryCycleLimit { get; }
|
||||
public int MaximumClients => 2;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System.Globalization;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace TrajectoryPlanningVisualization;
|
||||
|
||||
public static class VisualizationJson
|
||||
{
|
||||
private static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
|
||||
{
|
||||
ContractResolver = new CamelCasePropertyNamesContractResolver(),
|
||||
Culture = CultureInfo.InvariantCulture,
|
||||
DateFormatHandling = DateFormatHandling.IsoDateFormat,
|
||||
Formatting = Formatting.None
|
||||
};
|
||||
|
||||
public static string Serialize(object value)
|
||||
{
|
||||
return JsonConvert.SerializeObject(value, Settings);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user