70 const std::vector<SimplePathPoint>& base_path_points) {
71 if (base_path_points.size() < 2) {
75 const geometry_msgs::msg::TransformStamped tf =
79 std::vector<Eigen::Vector2d> grid_frame_path_points;
80 grid_frame_path_points.reserve(base_path_points.size());
81 for (
const auto& point : base_path_points) {
82 geometry_msgs::msg::PointStamped point_msg;
83 geometry_msgs::msg::PointStamped transformed_point_msg;
84 point_msg.header = target_header;
85 point_msg.point.x = point.position.x();
86 point_msg.point.y = point.position.y();
87 point_msg.point.z = 0.0;
88 tf2::doTransform(point_msg, transformed_point_msg, tf);
89 grid_frame_path_points.emplace_back(transformed_point_msg.point.x, transformed_point_msg.point.y);
92 const double resolution =
static_cast<double>(
grid_map_.info.resolution);
93 const Eigen::Vector2d grid_origin(
grid_map_.info.origin.position.x,
grid_map_.info.origin.position.y);
94 const double grid_origin_yaw = tf2::getYaw(
grid_map_.info.origin.orientation);
95 const double grid_length_x =
static_cast<double>(
grid_map_.info.width) * resolution;
96 const double grid_length_y =
static_cast<double>(
grid_map_.info.height) * resolution;
97 const Eigen::Vector2d ego_center_offset(
ego_data_.state.reference_point.translation_to_geometric_center.x,
98 ego_data_.state.reference_point.translation_to_geometric_center.y);
101 const Eigen::Vector2d ego_reference_position = Eigen::Vector2d::Zero();
102 double ego_path_s = 0.0;
103 double best_dist_sq = std::numeric_limits<double>::max();
104 for (
size_t i = 0; i + 1 < base_path_points.size(); ++i) {
105 const Eigen::Vector2d segment = base_path_points[i + 1].position - base_path_points[i].position;
106 const double segment_length_sq = segment.squaredNorm();
107 if (segment_length_sq < 1e-9) {
112 std::clamp((ego_reference_position - base_path_points[i].position).dot(segment) / segment_length_sq, 0.0, 1.0);
113 const Eigen::Vector2d projected = base_path_points[i].position + alpha * segment;
114 const double dist_sq = (projected - ego_reference_position).squaredNorm();
115 if (dist_sq >= best_dist_sq) {
119 best_dist_sq = dist_sq;
120 ego_path_s = base_path_points[i].s + alpha * (base_path_points[i + 1].s - base_path_points[i].s);
123 std::optional<double> last_safe_s;
124 for (
size_t i = 0; i + 1 < base_path_points.size(); ++i) {
125 const Eigen::Vector2d segment = grid_frame_path_points[i + 1] - grid_frame_path_points[i];
126 const double segment_length = segment.norm();
127 if (segment_length <= 1e-3) {
131 const Eigen::Vector2d tangent = segment / segment_length;
132 const auto sample_count =
static_cast<size_t>(std::ceil(segment_length / resolution));
133 for (
size_t sample_idx = 0; sample_idx <= sample_count; ++sample_idx) {
134 const double sampled_distance = std::min(
static_cast<double>(sample_idx) * resolution, segment_length);
135 const double alpha = sampled_distance / segment_length;
136 const double sample_s = base_path_points[i].s + alpha * (base_path_points[i + 1].s - base_path_points[i].s);
137 if (sample_s < ego_path_s) {
141 const Eigen::Vector2d reference_point = grid_frame_path_points[i] + alpha * segment;
142 const double yaw =
wrap_angle_rad(std::atan2(tangent.y(), tangent.x()));
143 const Eigen::Vector2d ego_center = reference_point +
rotate(ego_center_offset, yaw);
149 double min_local_x = std::numeric_limits<double>::max();
150 double max_local_x = std::numeric_limits<double>::lowest();
151 double min_local_y = std::numeric_limits<double>::max();
152 double max_local_y = std::numeric_limits<double>::lowest();
153 for (
const auto& corner : expanded_corners) {
154 const Eigen::Vector2d local_corner =
rotate(corner - grid_origin, -grid_origin_yaw);
155 min_local_x = std::min(min_local_x, local_corner.x());
156 max_local_x = std::max(max_local_x, local_corner.x());
157 min_local_y = std::min(min_local_y, local_corner.y());
158 max_local_y = std::max(max_local_y, local_corner.y());
161 const bool box_out_of_grid =
162 min_local_x < 0.0 || min_local_y < 0.0 || max_local_x >= grid_length_x || max_local_y >= grid_length_y;
164 return last_safe_s.value_or(ego_path_s);
167 const bool box_fully_outside =
168 max_local_x < 0.0 || max_local_y < 0.0 || min_local_x >= grid_length_x || min_local_y >= grid_length_y;
169 if (!box_fully_outside) {
170 const size_t min_cell_x =
static_cast<size_t>(std::floor(std::max(min_local_x, 0.0) / resolution));
171 const size_t max_cell_x =
172 std::min(
static_cast<size_t>(std::floor(max_local_x / resolution)),
static_cast<size_t>(
grid_map_.info.width) - 1);
173 const size_t min_cell_y =
static_cast<size_t>(std::floor(std::max(min_local_y, 0.0) / resolution));
174 const size_t max_cell_y =
175 std::min(
static_cast<size_t>(std::floor(max_local_y / resolution)),
static_cast<size_t>(
grid_map_.info.height) - 1);
177 for (
size_t cell_y = min_cell_y; cell_y <= max_cell_y; ++cell_y) {
178 for (
size_t cell_x = min_cell_x; cell_x <= max_cell_x; ++cell_x) {
184 const Eigen::Vector2d cell_center_local((
static_cast<double>(cell_x) + 0.5) * resolution,
185 (
static_cast<double>(cell_y) + 0.5) * resolution);
186 const Eigen::Vector2d cell_center = grid_origin +
rotate(cell_center_local, grid_origin_yaw);
188 if (
overlaps(ego_safety_box, cell_box)) {
189 return last_safe_s.value_or(ego_path_s);
195 last_safe_s = sample_s;