86 lines
3.9 KiB
C#
86 lines
3.9 KiB
C#
using System;
|
|
|
|
namespace MultiWheelC.TrajectoryPlanning.EMPlanner;
|
|
|
|
/// <summary>绑定一次滚动周期的不可变版本身份;所有字段必须同时匹配,旧结果才可发布。</summary>
|
|
public sealed class PlanningCycleIdentity : IEquatable<PlanningCycleIdentity>
|
|
{
|
|
/// <summary>创建完整周期身份。</summary>
|
|
/// <param name="mapSnapshotId">规划地图快照的非负版本 ID。</param>
|
|
/// <param name="referencePathId">平滑参考路径的非空版本 ID。</param>
|
|
/// <param name="vehicleStateSequenceId">调用方捕获的车辆状态非负序列号。</param>
|
|
/// <param name="previousTrajectoryId">上一条轨迹 ID;没有时使用空字符串。</param>
|
|
/// <param name="segmentIndex">当前前进或倒车方向段的非负索引。</param>
|
|
public PlanningCycleIdentity(long mapSnapshotId, string referencePathId, long vehicleStateSequenceId,
|
|
string previousTrajectoryId, int segmentIndex)
|
|
{
|
|
if (mapSnapshotId < 0)
|
|
throw new ArgumentOutOfRangeException(nameof(mapSnapshotId));
|
|
if (string.IsNullOrWhiteSpace(referencePathId))
|
|
throw new ArgumentException("A reference path ID is required.", nameof(referencePathId));
|
|
if (vehicleStateSequenceId < 0)
|
|
throw new ArgumentOutOfRangeException(nameof(vehicleStateSequenceId));
|
|
if (segmentIndex < 0)
|
|
throw new ArgumentOutOfRangeException(nameof(segmentIndex));
|
|
|
|
MapSnapshotId = mapSnapshotId;
|
|
ReferencePathId = referencePathId;
|
|
VehicleStateSequenceId = vehicleStateSequenceId;
|
|
PreviousTrajectoryId = previousTrajectoryId ?? string.Empty;
|
|
SegmentIndex = segmentIndex;
|
|
}
|
|
|
|
/// <summary>规划地图快照版本 ID。</summary>
|
|
public long MapSnapshotId { get; }
|
|
|
|
public string ReferencePathId { get; }
|
|
|
|
public long VehicleStateSequenceId { get; }
|
|
|
|
public string PreviousTrajectoryId { get; }
|
|
|
|
public int SegmentIndex { get; }
|
|
|
|
/// <summary>从已冻结的 EM 请求派生发布身份。</summary>
|
|
/// <param name="request">必须携带地图和车辆状态快照的 EM 请求。</param>
|
|
/// <returns>包含请求地图、路径、状态、上一轨迹和方向段字段的不可变身份。</returns>
|
|
public static PlanningCycleIdentity FromRequest(EmPlanningRequest request)
|
|
{
|
|
if (request == null)
|
|
throw new ArgumentNullException(nameof(request));
|
|
if (request.Map == null)
|
|
throw new ArgumentException("A planning map is required for a rolling cycle.", nameof(request));
|
|
if (request.VehicleState == null)
|
|
throw new ArgumentException("A vehicle state is required for a rolling cycle.", nameof(request));
|
|
|
|
return new PlanningCycleIdentity(request.Map.SnapshotId, request.ReferencePathId,
|
|
request.VehicleState.SequenceId, request.PreviousTrajectoryId, request.SegmentIndex);
|
|
}
|
|
|
|
public bool Equals(PlanningCycleIdentity other)
|
|
{
|
|
return other != null && MapSnapshotId == other.MapSnapshotId &&
|
|
string.Equals(ReferencePathId, other.ReferencePathId, StringComparison.Ordinal) &&
|
|
VehicleStateSequenceId == other.VehicleStateSequenceId &&
|
|
string.Equals(PreviousTrajectoryId, other.PreviousTrajectoryId, StringComparison.Ordinal) &&
|
|
SegmentIndex == other.SegmentIndex;
|
|
}
|
|
|
|
public override bool Equals(object obj)
|
|
{
|
|
return Equals(obj as PlanningCycleIdentity);
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
unchecked
|
|
{
|
|
int hash = MapSnapshotId.GetHashCode();
|
|
hash = (hash * 397) ^ StringComparer.Ordinal.GetHashCode(ReferencePathId);
|
|
hash = (hash * 397) ^ VehicleStateSequenceId.GetHashCode();
|
|
hash = (hash * 397) ^ StringComparer.Ordinal.GetHashCode(PreviousTrajectoryId);
|
|
return (hash * 397) ^ SegmentIndex;
|
|
}
|
|
}
|
|
}
|