using System; using System.Collections.Generic; using System.Collections.ObjectModel; namespace TrajectoryPlanningVisualization; public sealed class VisualizationPoint { public VisualizationPoint(double x, double y) { VisualizationContract.RequireFinite(x, nameof(x)); VisualizationContract.RequireFinite(y, nameof(y)); X = x; Y = y; } public double X { get; } public double Y { get; } } public sealed class VisualizationPose { public VisualizationPose(double x, double y, double headingRadians) { VisualizationContract.RequireFinite(x, nameof(x)); VisualizationContract.RequireFinite(y, nameof(y)); VisualizationContract.RequireFinite(headingRadians, nameof(headingRadians)); X = x; Y = y; HeadingRadians = headingRadians; } public double X { get; } public double Y { get; } public double HeadingRadians { get; } } public sealed class VisualizationBounds { public VisualizationBounds(double xMin, double xMax, double yMin, double yMax) { VisualizationContract.RequireFinite(xMin, nameof(xMin)); VisualizationContract.RequireFinite(xMax, nameof(xMax)); VisualizationContract.RequireFinite(yMin, nameof(yMin)); VisualizationContract.RequireFinite(yMax, nameof(yMax)); if (xMax < xMin || yMax < yMin) { throw new ArgumentOutOfRangeException(nameof(xMax), "Bounds maxima must not precede minima."); } XMin = xMin; XMax = xMax; YMin = yMin; YMax = yMax; } public double XMin { get; } public double XMax { get; } public double YMin { get; } public double YMax { get; } } public sealed class VisualizationValue { public VisualizationValue(string chineseName, string rawName, string value, string unit, string severity) { ChineseName = VisualizationContract.RequireText(chineseName, nameof(chineseName)); RawName = VisualizationContract.RequireText(rawName, nameof(rawName)); Value = VisualizationContract.RequireText(value, nameof(value)); Unit = VisualizationContract.RequireText(unit, nameof(unit)); if (severity != "normal" && severity != "notice" && severity != "failure") { throw new ArgumentOutOfRangeException(nameof(severity), "Severity must be normal, notice, or failure."); } Severity = severity; } public string ChineseName { get; } public string RawName { get; } public string Value { get; } public string Unit { get; } public string Severity { get; } } public sealed class VisualizationConfigurationGroup { public VisualizationConfigurationGroup(string chineseTitle, IReadOnlyList entries) { ChineseTitle = VisualizationContract.RequireText(chineseTitle, nameof(chineseTitle)); Entries = VisualizationContract.Copy(entries, nameof(entries)); } public string ChineseTitle { get; } public IReadOnlyList Entries { get; } } internal static class VisualizationContract { public static string RequireText(string value, string parameterName) { if (value == null) { throw new ArgumentNullException(parameterName); } return value; } public static void RequireFinite(double value, string parameterName) { if (double.IsNaN(value) || double.IsInfinity(value)) { throw new ArgumentOutOfRangeException(parameterName, "Value must be finite."); } } public static void RequireFinite(double? value, string parameterName) { if (value.HasValue) { RequireFinite(value.Value, parameterName); } } public static IReadOnlyList Copy(IReadOnlyList values, string parameterName) { if (values == null) { throw new ArgumentNullException(parameterName); } var copy = new List(values.Count); for (var index = 0; index < values.Count; index++) { T value = values[index]; if (value is null) { throw new ArgumentException("Collections cannot contain null elements.", parameterName); } copy.Add(value); } return new ReadOnlyCollection(copy); } }