using System; namespace MultiWheelC.TrajectoryPlanning.CoarsePath.Search; /// /// Hybrid A* 运行期节点。 /// 节点保留连续位姿和其离散闭集键;搜索过程中不会修改已创建节点,改进代价时会追加新节点并使旧 Open List 条目失效。 /// public sealed class HybridAStarNode { /// /// 创建一个搜索节点。 /// 参数:nodeIndex 为本次搜索内稳定索引;key 为离散状态;pose 为连续车辆中心位姿;parentNodeIndex 为父节点索引,根节点使用 -1; /// incomingPrimitive 为父节点到本节点的原语,根节点为 null;curvaturePerMeter、gCostMeters 和 hCostMeters 均使用规划器的标准单位。 /// public HybridAStarNode( int nodeIndex, HybridAStarNodeKey key, Pose2D pose, int parentNodeIndex, MotionPrimitive incomingPrimitive, double curvaturePerMeter, double gCostMeters, double hCostMeters) : this(nodeIndex, key, pose, parentNodeIndex, incomingPrimitive, curvaturePerMeter, gCostMeters, hCostMeters, false) { } /// /// 创建一个搜索节点,并显式指定它是否为原语内部命中的终点候选。 /// 参数:isGoalCandidate 为 true 时,本节点不参与普通离散状态的最优 G 值支配;它仍必须在从 Open List 出队后重新通过连续终点和碰撞检查才能成功。 /// public HybridAStarNode( int nodeIndex, HybridAStarNodeKey key, Pose2D pose, int parentNodeIndex, MotionPrimitive incomingPrimitive, double curvaturePerMeter, double gCostMeters, double hCostMeters, bool isGoalCandidate) { if (key == null) throw new ArgumentNullException(nameof(key)); if (pose == null) throw new ArgumentNullException(nameof(pose)); NodeIndex = nodeIndex; Key = key; Pose = pose; ParentNodeIndex = parentNodeIndex; IncomingPrimitive = incomingPrimitive; CurvaturePerMeter = curvaturePerMeter; GCostMeters = gCostMeters; HCostMeters = hCostMeters; IsGoalCandidate = isGoalCandidate; } /// 本次搜索节点数组中的稳定索引。 public int NodeIndex { get; } /// 本节点用于 Open/Closed 状态管理的离散键。 public HybridAStarNodeKey Key { get; } /// 未量化的连续车辆中心位姿。 public Pose2D Pose { get; } /// 父节点稳定索引;根节点为 -1。 public int ParentNodeIndex { get; } /// 由父节点驶入本节点的已连续碰撞检查原语;根节点为 null。 public MotionPrimitive IncomingPrimitive { get; } /// 含义相同的原语别名。 public MotionPrimitive Primitive { get { return IncomingPrimitive; } } /// 当前末段采用的车辆曲率,单位 1/m。 public double CurvaturePerMeter { get; } /// 当前节点的累计等效米代价。 public double GCostMeters { get; } /// 当前节点的二维启发式等效米代价。 public double HCostMeters { get; } /// /// 本节点是否由原语内部首次满足终点条件而生成。 /// 终点候选必须保留连续位姿,不能因同一离散键的普通低代价节点而被 Open List 准入规则压制。 /// public bool IsGoalCandidate { get; } /// Open List 排序使用的总等效米代价。 public double FCostMeters { get { return GCostMeters + HCostMeters; } } /// 本节点末段的行驶方向。 public TravelDirection Direction { get { return Key.Direction; } } /// 本节点末段的曲率等级索引。 public int CurvatureLevelIndex { get { return Key.CurvatureLevelIndex; } } }