using System; using System.Collections.Generic; using System.Collections.ObjectModel; using MultiWheelC.TrajectoryPlanning.Utils; namespace MultiWheelC.TrajectoryPlanning.PathSmoothing.LocalG2; /// 一个局部 G2 候选可替换的弧长窗口。 internal sealed class LocalG2WindowVariant { /// 创建同一平滑区域内一个可尝试替换的弧长窗口变体。 /// 区域内候选的稳定从零开始索引。 /// 窗口起点弧长,单位 m。 /// 窗口终点弧长,单位 m。 /// 过渡点左侧窗口长度,单位 m。 /// 过渡点右侧窗口长度,单位 m。 internal LocalG2WindowVariant(int candidateIndex, double startArcLengthMeters, double endArcLengthMeters, double leftWindowLengthMeters, double rightWindowLengthMeters) { if (candidateIndex < 0 || startArcLengthMeters < 0d || endArcLengthMeters < startArcLengthMeters || leftWindowLengthMeters < 0d || rightWindowLengthMeters < 0d) { throw new ArgumentOutOfRangeException(nameof(candidateIndex)); } CandidateIndex = candidateIndex; StartArcLengthMeters = startArcLengthMeters; EndArcLengthMeters = endArcLengthMeters; LeftWindowLengthMeters = leftWindowLengthMeters; RightWindowLengthMeters = rightWindowLengthMeters; } internal int CandidateIndex { get; } internal double StartArcLengthMeters { get; } internal double EndArcLengthMeters { get; } internal double LeftWindowLengthMeters { get; } internal double RightWindowLengthMeters { get; } } /// 至少存在一个联合合法生成窗口变体的一组曲率过渡。 internal sealed class LocalG2SmoothingRegion { /// 创建一个包含共同可用窗口变体的局部曲率过渡区域。 /// 所属方向段在预处理路径中的从零开始索引。 /// 归并到该区域的曲率跳变集合。 /// 所有候选允许的最晚窗口起点,单位 m。 /// 所有候选允许的最早窗口终点,单位 m。 /// 至少一个合法的窗口变体集合。 internal LocalG2SmoothingRegion( int segmentIndex, IReadOnlyList transitions, double maximumStartArcLengthMeters, double maximumEndArcLengthMeters, IReadOnlyList windowVariants) { if (segmentIndex < 0 || transitions == null || transitions.Count == 0 || !NumericGuard.IsFinite(maximumStartArcLengthMeters) || !NumericGuard.IsFinite(maximumEndArcLengthMeters) || maximumStartArcLengthMeters < 0d || maximumEndArcLengthMeters < maximumStartArcLengthMeters || windowVariants == null || windowVariants.Count == 0) { throw new ArgumentOutOfRangeException(nameof(transitions)); } SegmentIndex = segmentIndex; Transitions = Copy(transitions); MaximumStartArcLengthMeters = maximumStartArcLengthMeters; MaximumEndArcLengthMeters = maximumEndArcLengthMeters; WindowVariants = Copy(windowVariants); } internal int SegmentIndex { get; } internal IReadOnlyList Transitions { get; } internal double MaximumStartArcLengthMeters { get; } internal double MaximumEndArcLengthMeters { get; } internal IReadOnlyList WindowVariants { get; } private static IReadOnlyList Copy(IReadOnlyList source) { var copy = new List(source.Count); for (int index = 0; index < source.Count; index++) copy.Add(source[index]); return new ReadOnlyCollection(copy); } }