using System; using System.Collections.Generic; using System.Collections.ObjectModel; using MultiWheelC.TrajectoryPlanning.Utils; namespace MultiWheelC.TrajectoryPlanning.PathSmoothing.LocalG2; /// 把稳定报告顺序转换为不会使后续原始局部弧长错位的工作顺序。 internal sealed class LocalG2RegionWorkOrder { internal bool TryCreate( IReadOnlyList reportOrder, out IReadOnlyList workOrder, out string reason) { workOrder = Empty(); reason = string.Empty; if (reportOrder == null) { reason = "局部 G2 区域工作顺序输入无效。"; return false; } var indexed = new List(reportOrder.Count); for (int index = 0; index < reportOrder.Count; index++) { LocalG2SmoothingRegion region = reportOrder[index]; if (!TryValidate(region, out double firstArc, out reason)) return false; indexed.Add(new IndexedRegion(region, index, firstArc)); } indexed.Sort(Compare); var ordered = new List(indexed.Count); for (int index = 0; index < indexed.Count; index++) ordered.Add(indexed[index].Region); workOrder = new ReadOnlyCollection(ordered); return true; } private static bool TryValidate( LocalG2SmoothingRegion region, out double firstArc, out string reason) { firstArc = 0d; reason = string.Empty; if (region == null || region.SegmentIndex < 0 || region.Transitions == null || region.Transitions.Count == 0 || region.WindowVariants == null || region.WindowVariants.Count == 0) { reason = "局部 G2 工作顺序包含空区域或空窗口集。"; return false; } double previousArc = -1d; for (int index = 0; index < region.Transitions.Count; index++) { CurvatureTransition transition = region.Transitions[index]; if (transition == null || transition.SegmentIndex != region.SegmentIndex || !NumericGuard.IsFinite(transition.LocalArcLengthMeters) || transition.LocalArcLengthMeters < previousArc) { reason = "局部 G2 工作顺序要求区域事件有限、同段且按弧长升序。"; return false; } previousArc = transition.LocalArcLengthMeters; } firstArc = region.Transitions[0].LocalArcLengthMeters; return true; } private static int Compare(IndexedRegion left, IndexedRegion right) { int segment = left.Region.SegmentIndex.CompareTo(right.Region.SegmentIndex); if (segment != 0) return segment; int descendingArc = right.FirstArc.CompareTo(left.FirstArc); return descendingArc != 0 ? descendingArc : left.ReportIndex.CompareTo(right.ReportIndex); } private static IReadOnlyList Empty() { return new ReadOnlyCollection( new List()); } private sealed class IndexedRegion { internal IndexedRegion( LocalG2SmoothingRegion region, int reportIndex, double firstArc) { Region = region; ReportIndex = reportIndex; FirstArc = firstArc; } internal LocalG2SmoothingRegion Region { get; } internal int ReportIndex { get; } internal double FirstArc { get; } } }