10#include <unordered_map>
11#include <unordered_set>
14#include <lanelet2_core/geometry/LaneletMap.h>
15#include <lanelet2_core/utility/Units.h>
16#include <lanelet2_routing/Route.h>
17#include <lanelet2_traffic_rules/TrafficRulesFactory.h>
18#include <route_planning_msgs_utils/route_access.hpp>
26std::optional<lanelet::routing::Route>
getRoute(
const lanelet::routing::RoutingGraphUPtr& routing_graph,
27 const std::vector<lanelet::ConstLanelet>& route_lanelets) {
28 if (route_lanelets.empty()) {
32 const lanelet::ConstLanelet& start_lanelet = route_lanelets.front();
33 std::vector<lanelet::ConstLanelet> intermediate_lanelets(route_lanelets.begin() + 1, route_lanelets.end() - 1);
34 const lanelet::ConstLanelet& destination_lanelet = route_lanelets.back();
37 const int routing_cost_id = 0;
38 const bool with_lane_changes =
true;
40 routing_graph->getRouteVia(start_lanelet, intermediate_lanelets, destination_lanelet, routing_cost_id, with_lane_changes);
43 auto route_alternative1 =
44 routing_graph->getRouteVia(start_lanelet.invert(), intermediate_lanelets, destination_lanelet, routing_cost_id);
45 auto route_alternative2 =
46 routing_graph->getRouteVia(start_lanelet, intermediate_lanelets, destination_lanelet.invert(), routing_cost_id);
47 auto route_alternative3 =
48 routing_graph->getRouteVia(start_lanelet.invert(), intermediate_lanelets, destination_lanelet.invert(), routing_cost_id);
49 std::vector<lanelet::routing::Route> route_alternatives;
50 if (route) route_alternatives.push_back(std::move(*route));
51 if (route_alternative1) route_alternatives.push_back(std::move(*route_alternative1));
52 if (route_alternative2) route_alternatives.push_back(std::move(*route_alternative2));
53 if (route_alternative3) route_alternatives.push_back(std::move(*route_alternative3));
56 auto shortest_route_ptr = std::min_element(
57 route_alternatives.begin(), route_alternatives.end(),
58 [](
const lanelet::routing::Route& a,
const lanelet::routing::Route& b) { return a.length2d() < b.length2d(); });
60 if (shortest_route_ptr == route_alternatives.end()) {
63 auto shortest_route = std::optional<lanelet::routing::Route>(std::move(*shortest_route_ptr));
64 return shortest_route;
68 const Eigen::Vector2d& point,
69 const bool consider_order,
71 if (line_string.empty()) {
76 size_t idx_closest = 0;
77 double min_distance = std::numeric_limits<double>::infinity();
78 for (
size_t i = 0; i < line_string.size(); ++i) {
79 double distance = (line_string[i] - point).norm();
80 if (distance < min_distance) {
81 min_distance = distance;
95 const Eigen::Vector2d& point,
96 const size_t idx_indication,
97 const bool consider_order,
99 if (line_string.empty()) {
104 const double max_delta_s = 10.0;
105 const double max_local_distance = 10.0;
107 size_t idx_closest = 0;
108 double min_distance = std::numeric_limits<double>::infinity();
109 const size_t start_idx = std::min(idx_indication, line_string.size() - 1);
112 for (
int direction : {1, -1}) {
113 double delta_s = 0.0;
114 size_t idx = start_idx;
116 while (delta_s <= max_delta_s && idx < line_string.size()) {
117 double distance = (line_string[idx] - point).norm();
118 if (distance < min_distance) {
119 min_distance = distance;
122 if (direction == 1) {
123 if (idx + 1 >= line_string.size())
break;
124 delta_s += (line_string[idx + 1] - line_string[idx]).norm();
127 delta_s += (line_string[idx] - line_string[idx - 1]).norm();
134 if (min_distance > max_local_distance) {
136 }
else if (consider_order) {
145 const Eigen::Vector2d& point,
146 const size_t idx_closest,
148 if (line_string.empty()) {
152 size_t new_idx_closest = idx_closest;
153 Eigen::Vector2d closest_point_to_next;
154 const Eigen::Vector2d closest_point_to_point = point - line_string[idx_closest];
155 if (idx_closest + 1 < line_string.size()) {
156 closest_point_to_next = line_string[idx_closest + 1] - line_string[idx_closest];
157 }
else if (idx_closest > 0) {
158 closest_point_to_next = line_string[idx_closest] - line_string[idx_closest - 1];
165 if (behind && std::abs(angle) > M_PI_2) {
166 new_idx_closest = idx_closest > 0 ? idx_closest - 1 : 0;
167 }
else if (!behind && std::abs(angle) < M_PI_2) {
168 new_idx_closest = idx_closest + 1;
170 new_idx_closest = idx_closest;
172 new_idx_closest = std::clamp(new_idx_closest,
size_t{0}, line_string.size() - 1);
174 return new_idx_closest;
178 const Eigen::Vector2d& next_point,
179 const double sampling_distance) {
180 const double epsilon = 1e-6;
181 return ((next_point - point).norm() > (sampling_distance + epsilon));
185 const lanelet::routing::RoutingGraphUPtr& routing_graph,
187 bool sort_from_left) {
188 std::vector<lanelet::ConstLanelet> adjacent_lanelets;
189 const int routing_cost_id = 0;
190 lanelet::routing::LaneletRelations relations =
191 left ? routing_graph->leftRelations(lanelet, routing_cost_id) : routing_graph->rightRelations(lanelet, routing_cost_id);
192 for (
const auto& relation : relations) {
193 if ((left && (relation.relationType == lanelet::routing::RelationType::Left ||
194 relation.relationType == lanelet::routing::RelationType::AdjacentLeft)) ||
195 (!left && (relation.relationType == lanelet::routing::RelationType::Right ||
196 relation.relationType == lanelet::routing::RelationType::AdjacentRight))) {
197 adjacent_lanelets.push_back(relation.lanelet);
201 if ((left && sort_from_left) || (!left && !sort_from_left)) {
202 std::reverse(adjacent_lanelets.begin(), adjacent_lanelets.end());
205 return adjacent_lanelets;
209 const Eigen::Vector2d& prev_point,
210 const Eigen::Vector2d& next_point,
211 const std::vector<lanelet::ConstLanelet>& lanelets,
212 const rclcpp::Logger& logger) {
213 std::vector<ProjectedLaneletPoints> projected_points_per_lanelet;
216 for (
const auto& lanelet : lanelets) {
221 toEigen(lanelet.leftBound2d().basicLineString()))) {
224 RCLCPP_WARN(logger,
"Failed to project point (%.3f, %.3f) to left bounds of lanelet %ld", point.x(), point.y(),
230 toEigen(lanelet.centerline2d().basicLineString()))) {
233 RCLCPP_WARN(logger,
"Failed to project point (%.3f, %.3f) to centerline of lanelet %ld", point.x(), point.y(),
239 toEigen(lanelet.rightBound2d().basicLineString()))) {
242 RCLCPP_WARN(logger,
"Failed to project point (%.3f, %.3f) to right bounds of lanelet %ld", point.x(), point.y(),
246 projected_points_per_lanelet.push_back(projected_points);
249 return projected_points_per_lanelet;
253 const lanelet::ConstLanelet& lanelet_of_next_point,
254 const lanelet::routing::RoutingGraphUPtr& routing_graph) {
255 int following_lane_idx_offset = 0;
256 if (lanelet_of_next_point.id() != lanelet.id()) {
260 const int suggested_lane_idx =
static_cast<int>(adjacent_left_lanelets.size());
263 std::vector<lanelet::ConstLanelet> adjacent_left_lanelets_of_next_lanelet =
265 std::vector<lanelet::ConstLanelet> adjacent_right_lanelets_of_next_lanelet =
267 std::vector<lanelet::ConstLanelet> adjacent_lanelets_of_next_lanelet = adjacent_left_lanelets_of_next_lanelet;
268 adjacent_lanelets_of_next_lanelet.push_back(lanelet_of_next_point);
269 adjacent_lanelets_of_next_lanelet.insert(adjacent_lanelets_of_next_lanelet.end(),
270 adjacent_right_lanelets_of_next_lanelet.begin(),
271 adjacent_right_lanelets_of_next_lanelet.end());
274 std::vector<std::vector<lanelet::ConstLanelet>> lanelet_groups = {{lanelet}, adjacent_left_lanelets, adjacent_right_lanelets};
275 std::vector<int> lanelet_group_offset_factors = {0, 1, -1};
276 following_lane_idx_offset = std::numeric_limits<int>::max();
279 for (
size_t group_idx = 0; group_idx < lanelet_groups.size(); ++group_idx) {
280 const auto& lanelet_group = lanelet_groups[group_idx];
281 int group_offset_factor = lanelet_group_offset_factors[group_idx];
284 for (
size_t a = 0; a < lanelet_group.size(); ++a) {
285 auto following_lanelets = routing_graph->following(lanelet_group[a],
false);
286 if (following_lanelets.empty()) {
289 auto following_lanelet = following_lanelets.front();
290 size_t following_lanelet_idx = 0;
291 size_t follow_further_idx =
293 size_t max_follow_further_iterations = 3;
296 while (following_lane_idx_offset == std::numeric_limits<int>::max()) {
298 for (
size_t l = 0; l < adjacent_lanelets_of_next_lanelet.size(); ++l) {
299 if (following_lanelet.id() == adjacent_lanelets_of_next_lanelet[l].id()) {
300 following_lane_idx_offset =
301 static_cast<int>(l) - suggested_lane_idx + group_offset_factor *
static_cast<int>(a + 1);
307 follow_further_idx++;
308 if (follow_further_idx >= max_follow_further_iterations) {
313 following_lanelet_idx++;
314 if (following_lanelet_idx < following_lanelets.size()) {
315 following_lanelet = following_lanelets[following_lanelet_idx];
317 following_lanelets = routing_graph->following(following_lanelet,
false);
318 if (following_lanelets.empty()) {
321 following_lanelet = following_lanelets.front();
322 following_lanelet_idx = 0;
326 if (following_lane_idx_offset != std::numeric_limits<int>::max()) {
331 if (following_lane_idx_offset != std::numeric_limits<int>::max()) {
336 if (following_lane_idx_offset == std::numeric_limits<int>::max()) {
342 return following_lane_idx_offset;
346 const geometry_msgs::msg::Quaternion& orientation,
348 bool will_change_suggested_lane,
349 uint8_t speed_limit) {
351 route_planning_msgs::msg::RouteElement route_element_msg;
352 route_element_msg.suggested_lane_idx = 0;
353 route_element_msg.will_change_suggested_lane = will_change_suggested_lane;
354 route_element_msg.s = s;
355 route_element_msg.is_enriched =
false;
361 route_planning_msgs::msg::LaneElement lane_element_msg;
362 lane_element_msg.reference_pose.position = position;
363 lane_element_msg.reference_pose.orientation = orientation;
366 lane_element_msg.speed_limit = speed_limit;
368 lane_element_msg.following_lane_idx = 0;
369 lane_element_msg.has_following_lane_idx = !will_change_suggested_lane;
370 route_element_msg.lane_elements.push_back(lane_element_msg);
372 return route_element_msg;
375std::pair<Eigen::Vector2d, Eigen::Vector2d>
extractDrivableSpace(
const lanelet::LineStringLayer& line_string_layer,
377 const double max_distance) {
379 const lanelet::BasicLineString2d line_to_search_around = {point_sequence.
current, point_sequence.
next};
380 std::vector<std::pair<double, lanelet::ConstLineString3d>> line_strings_and_distances =
381 lanelet::geometry::findWithin2d(line_string_layer, line_to_search_around, max_distance);
384 const std::vector<Eigen::Vector2d> normal_line = {
387 std::vector<std::pair<Eigen::Vector2d, size_t>> projected_points_and_line_string_idcs;
388 for (
size_t l = 0; l < line_strings_and_distances.size(); ++l) {
389 const auto& line_string = line_strings_and_distances[l].second;
390 const std::vector<Eigen::Vector2d> line_string_2d =
to2d(
toEigen(line_string.basicLineString()));
391 for (
size_t i = 1; i < line_string_2d.size(); ++i) {
392 const std::vector<Eigen::Vector2d> line_segment = {line_string_2d[i - 1], line_string_2d[i]};
394 if (!intersection || !intersection->intersects_line2) {
398 const Eigen::Vector2d& projected_point = intersection->intersection;
399 if ((projected_point - point_sequence.
current).norm() > max_distance) {
403 projected_points_and_line_string_idcs.emplace_back(projected_point, l);
408 std::sort(projected_points_and_line_string_idcs.begin(), projected_points_and_line_string_idcs.end(),
409 [&point_sequence](
const auto& a,
const auto& b) {
410 return (a.first - point_sequence.current).norm() < (b.first - point_sequence.current).norm();
415 std::vector<std::pair<Eigen::Vector2d, size_t>> left_projected_points_and_line_string_idcs,
416 right_projected_points_and_line_string_idcs;
417 for (
const auto& projected_point_and_line_string_idx : projected_points_and_line_string_idcs) {
419 const Eigen::Vector2d point_to_projected_point = projected_point_and_line_string_idx.first - point_sequence.
current;
422 left_projected_points_and_line_string_idcs.emplace_back(projected_point_and_line_string_idx);
424 right_projected_points_and_line_string_idcs.emplace_back(projected_point_and_line_string_idx);
429 Eigen::Vector2d drivable_space_left, drivable_space_right;
430 bool is_drivable_space_left_limited_by_line_strings =
false;
431 bool is_drivable_space_right_limited_by_line_strings =
false;
432 for (
const auto& projected_point_and_line_string_idx : left_projected_points_and_line_string_idcs) {
433 const auto& line_string = line_strings_and_distances[projected_point_and_line_string_idx.second].second;
435 drivable_space_left = projected_point_and_line_string_idx.first;
436 is_drivable_space_left_limited_by_line_strings =
true;
440 for (
const auto& projected_point_and_line_string_idx : right_projected_points_and_line_string_idcs) {
441 const auto& line_string = line_strings_and_distances[projected_point_and_line_string_idx.second].second;
443 drivable_space_right = projected_point_and_line_string_idx.first;
444 is_drivable_space_right_limited_by_line_strings =
true;
451 if (!is_drivable_space_left_limited_by_line_strings) {
452 drivable_space_left = point_sequence.
current - normal * max_distance;
454 if (!is_drivable_space_right_limited_by_line_strings) {
455 drivable_space_right = point_sequence.
current + normal * max_distance;
458 return {drivable_space_left, drivable_space_right};
462 const std::unordered_set<std::string> drivable_types = {
"arrow",
"bike_marking",
"centerline",
"curbstone",
463 "lane_center",
"line_thick",
"line_thin",
"pedestrian_marking",
464 "roadpainting",
"stop_line",
"traffic_light",
"virtual",
466 if (line_string.hasAttribute(
"type")) {
467 std::string type = line_string.attribute(
"type").value();
468 if (drivable_types.count(type) > 0) {
469 if (type ==
"curbstone") {
470 if (!line_string.hasAttribute(
"subtype") || line_string.attribute(
"subtype").value() !=
"low") {
476 return line_string.hasAttribute(
"HoldingLine");
482 const std::vector<lanelet::ConstLanelet>& adjacent_left_lanelets,
483 const std::vector<lanelet::ConstLanelet>& adjacent_right_lanelets,
491 std::vector<lanelet::ConstLanelet> lanelets = adjacent_left_lanelets;
492 lanelets.push_back(lanelet);
493 lanelets.insert(lanelets.end(), adjacent_right_lanelets.begin(), adjacent_right_lanelets.end());
496 std::unordered_map<size_t, size_t> regulatory_element_msg_idx_by_id;
497 for (
size_t l = 0; l < lanelets.size(); ++l) {
498 const auto& current_lanelet = lanelets[l];
501 const auto regulatory_elements = current_lanelet.regulatoryElements();
502 for (
const auto& regulatory_element : regulatory_elements) {
504 route_planning_msgs::msg::RegulatoryElement regulatory_element_msg;
505 regulatory_element_msg.has_validity_stamp =
false;
506 regulatory_element_msg.validity_stamp = builtin_interfaces::msg::Time();
510 regulatory_element_msg.reference_line = *reference_line;
513 std::vector<Eigen::Vector2d> reference_line_2d = {
toEigen2d(reference_line->at(0)),
toEigen2d(reference_line->at(1))};
514 std::vector<Eigen::Vector2d> line_to_next_point = {point_sequence.
current, point_sequence.
next};
515 std::vector<Eigen::Vector2d> line_to_prev_point = {point_sequence.
current, point_sequence.
prev};
517 if (!result->intersects_line2) {
519 if (!inner_result->intersects_line2) {
531 std::tie(regulatory_element_msg.type, regulatory_element_msg.meta_value) =
regulatoryElementType(regulatory_element);
534 size_t regulatory_element_msg_idx = 0;
535 if (regulatory_element_msg_idx_by_id.count(regulatory_element->id()) > 0) {
536 regulatory_element_msg_idx = regulatory_element_msg_idx_by_id[regulatory_element->id()];
540 regulatory_element_msg_idx_by_id[regulatory_element->id()] = regulatory_element_msg_idx;
545 if (l < adjacent_left_lanelets.size()) {
547 }
else if (l < adjacent_left_lanelets.size() + 1) {
550 size_t l_right = l - adjacent_left_lanelets.size() - 1;
560 const std::shared_ptr<const lanelet::RegulatoryElement>& regulatory_element) {
561 const std::vector<lanelet::ConstLineString3d> reference_lines =
562 regulatory_element->getParameters<lanelet::ConstLineString3d>(lanelet::RoleName::RefLine);
563 if (reference_lines.empty()) {
566 const std::vector<Eigen::Vector3d> reference_line = reference_lines.front().basicLineString();
567 if (reference_line.size() < 2) {
570 std::array<geometry_msgs::msg::Point, 2> reference_line_ros = {
toRos(reference_line.front()),
toRos(reference_line.back())};
571 return reference_line_ros;
575 const std::shared_ptr<const lanelet::RegulatoryElement>& regulatory_element) {
576 const std::vector<lanelet::ConstLineString3d> cancel_lines =
577 regulatory_element->getParameters<lanelet::ConstLineString3d>(lanelet::RoleName::CancelLine);
578 if (cancel_lines.empty()) {
581 const std::vector<Eigen::Vector3d> cancel_line = cancel_lines.front().basicLineString();
582 if (cancel_line.size() < 2) {
585 std::array<geometry_msgs::msg::Point, 2> cancel_line_ros = {
toRos(cancel_line.front()),
toRos(cancel_line.back())};
586 return cancel_line_ros;
590 const std::shared_ptr<const lanelet::RegulatoryElement>& regulatory_element) {
591 std::vector<geometry_msgs::msg::Point> positions;
592 const std::vector<lanelet::ConstLineString3d> sign_lines =
593 regulatory_element->getParameters<lanelet::ConstLineString3d>(lanelet::RoleName::Refers);
594 for (
const auto& const_sign_line : sign_lines) {
595 const std::vector<Eigen::Vector3d> sign_line = const_sign_line.basicLineString();
596 if (!sign_line.empty()) {
597 positions.push_back(
toRos(sign_line.front()));
603std::pair<uint8_t, uint8_t>
regulatoryElementType(
const std::shared_ptr<const lanelet::RegulatoryElement>& regulatory_element) {
604 uint8_t type = route_planning_msgs::msg::RegulatoryElement::TYPE_UNKNOWN;
605 uint8_t meta_value = 0;
608 if (regulatory_element->hasAttribute(
"subtype")) {
609 std::string subtype = regulatory_element->attribute(
"subtype").value();
610 if (subtype ==
"traffic_light") {
611 type = route_planning_msgs::msg::RegulatoryElement::TYPE_TRAFFIC_LIGHT;
612 }
else if (subtype ==
"speed_limit") {
613 type = route_planning_msgs::msg::RegulatoryElement::TYPE_SPEED_LIMIT;
615 }
else if (subtype ==
"right_of_way") {
616 type = route_planning_msgs::msg::RegulatoryElement::TYPE_YIELD;
617 const auto traffic_signs = regulatory_element->getParameters<lanelet::ConstLineString3d>(lanelet::RoleName::Refers);
618 const bool has_stop_sign = std::any_of(traffic_signs.begin(), traffic_signs.end(), [](
const auto& traffic_sign) {
619 return traffic_sign.hasAttribute(
"subtype") && traffic_sign.attribute(
"subtype").value() ==
"de206";
622 type = route_planning_msgs::msg::RegulatoryElement::TYPE_STOP;
624 }
else if (subtype ==
"all_way_stop") {
625 type = route_planning_msgs::msg::RegulatoryElement::TYPE_STOP;
628 return {type, meta_value};
632 uint8_t speed_limit = route_planning_msgs::msg::RegulatoryElement::META_VALUE_SPEED_UNKNOWN;
635 if (regulatory_element->hasAttribute(
"subtype")) {
636 std::string subtype = regulatory_element->attribute(
"subtype").value();
637 if (subtype ==
"speed_limit") {
638 if (regulatory_element->hasAttribute(
"sign_type")) {
639 std::string sign_type = regulatory_element->attribute(
"sign_type").value();
641 std::regex regex(
"(\\d+)\\s*(km/h|mph|mps)");
642 if (std::regex_search(sign_type, match, regex)) {
643 int speed = std::stoi(match.str(1));
644 if (match.str(2) ==
"mph") {
645 speed =
static_cast<int>(speed * 1.60934);
646 }
else if (match.str(2) ==
"mps") {
647 speed =
static_cast<int>(speed * 3.6);
649 speed_limit =
static_cast<uint8_t
>(speed);
651 std::regex regex(
"(\\d+)");
652 if (std::regex_search(sign_type, match, regex)) {
653 speed_limit =
static_cast<uint8_t
>(std::stoi(match.str(1)));
660 uint8_t unlimited = route_planning_msgs::msg::RegulatoryElement::META_VALUE_SPEED_UNLIMITED;
661 speed_limit = std::clamp(speed_limit,
static_cast<uint8_t
>(0), unlimited);
667 uint8_t lane_boundary_type = route_planning_msgs::msg::LaneBoundary::TYPE_UNKNOWN;
670 lanelet::Attribute type;
671 if (line.hasAttribute(
"type")) {
672 type = line.attribute(
"type");
674 lane_boundary_type = route_planning_msgs::msg::LaneBoundary::TYPE_UNKNOWN;
675 return lane_boundary_type;
679 if (type ==
"road_boarder" || type ==
"barrier") {
680 lane_boundary_type = route_planning_msgs::msg::LaneBoundary::TYPE_CROSSING_RESTRICTED;
681 }
else if (type ==
"line_thin" || type ==
"line_thick") {
682 lane_boundary_type = route_planning_msgs::msg::LaneBoundary::TYPE_UNKNOWN;
683 if (line.hasAttribute(
"subtype")) {
684 lanelet::Attribute subtype = line.attribute(
"subtype");
685 if (subtype ==
"solid" || subtype ==
"solid_solid") {
686 lane_boundary_type = route_planning_msgs::msg::LaneBoundary::TYPE_CROSSING_RESTRICTED;
687 }
else if (subtype ==
"dashed") {
688 lane_boundary_type = route_planning_msgs::msg::LaneBoundary::TYPE_CROSSING_ALLOWED;
689 }
else if (subtype ==
"dashed_solid") {
690 lane_boundary_type = route_planning_msgs::msg::LaneBoundary::TYPE_CROSSING_ALLOWED_FROM_LEFT;
691 }
else if (subtype ==
"solid_dashed") {
692 lane_boundary_type = route_planning_msgs::msg::LaneBoundary::TYPE_CROSSING_ALLOWED_FROM_RIGHT;
695 }
else if (type ==
"virtual") {
696 lane_boundary_type = route_planning_msgs::msg::LaneBoundary::TYPE_UNKNOWN;
698 lane_boundary_type = route_planning_msgs::msg::LaneBoundary::TYPE_UNKNOWN;
701 return lane_boundary_type;
704uint8_t
speedLimit(
const lanelet::ConstLanelet& lanelet,
const bool consider_regulatory_elements) {
705 lanelet::traffic_rules::TrafficRulesPtr traffic_rules =
getTrafficRules();
706 lanelet::traffic_rules::SpeedLimitInformation speed_limit_info;
707 if (consider_regulatory_elements) {
708 speed_limit_info = traffic_rules->speedLimit(lanelet);
710 uint8_t unlimited = route_planning_msgs::msg::RegulatoryElement::META_VALUE_SPEED_UNLIMITED;
711 if (!lanelet.hasAttribute(lanelet::AttributeName::SpeedLimit)) {
714 auto speed_limit = lanelet.attribute(lanelet::AttributeName::SpeedLimit).asVelocity();
718 bool is_mandatory =
true;
719 const std::string speed_limit_mandatory_attribute =
720 lanelet::AttributeNamesString::SpeedLimitMandatory;
721 if (lanelet.hasAttribute(speed_limit_mandatory_attribute)) {
722 is_mandatory = lanelet.attribute(speed_limit_mandatory_attribute).value() != std::string(
"no");
724 speed_limit_info = lanelet::traffic_rules::SpeedLimitInformation{*speed_limit, is_mandatory};
726 uint8_t unlimited = route_planning_msgs::msg::RegulatoryElement::META_VALUE_SPEED_UNLIMITED;
727 if (speed_limit_info.isMandatory) {
728 int speed_limit =
static_cast<int>(std::round(lanelet::units::KmHQuantity(speed_limit_info.speedLimit).value()));
729 speed_limit = std::clamp(speed_limit, 0,
static_cast<int>(unlimited));
730 return static_cast<uint8_t
>(speed_limit);
735uint8_t
speedLimit(
const lanelet::ConstLanelet& lanelet,
const Eigen::Vector2d& point) {
736 uint8_t speed_limit = route_planning_msgs::msg::RegulatoryElement::META_VALUE_SPEED_UNLIMITED;
737 std::vector<Eigen::Vector2d> centerline =
toEigen(lanelet.centerline2d().basicLineString());
738 double best_reference_arc_length = 0.0;
739 bool found_valid_regulatory_element_speed_limit =
false;
740 bool found_future_reference_line =
false;
741 bool found_past_cancel_line =
false;
744 const auto regulatory_elements = lanelet.regulatoryElements();
745 for (
const auto& regulatory_element : regulatory_elements) {
747 uint8_t regulatory_element_type = route_planning_msgs::msg::RegulatoryElement::TYPE_UNKNOWN;
748 uint8_t regulatory_element_meta_value = route_planning_msgs::msg::RegulatoryElement::META_VALUE_UNKNOWN;
749 std::tie(regulatory_element_type, regulatory_element_meta_value) =
regulatoryElementType(regulatory_element);
750 if (regulatory_element_type != route_planning_msgs::msg::RegulatoryElement::TYPE_SPEED_LIMIT) {
756 std::vector<Eigen::Vector2d> reference_line_2d = {
toEigen2d(reference_line->at(0)),
toEigen2d(reference_line->at(1))};
759 bool reference_line_intersects_centerline =
false;
760 double reference_arc_length = 0.0;
761 for (
size_t i = 0; i < centerline.size() - 1; ++i) {
762 std::vector<Eigen::Vector2d> centerline_segment = {centerline[i], centerline[i + 1]};
764 if (result->intersects_line1 && result->intersects_line2) {
765 reference_arc_length =
766 lanelet::geometry::toArcCoordinates(lanelet.centerline2d(),
toLanelet(result->intersection)).length;
767 reference_line_intersects_centerline =
true;
774 bool cancel_line_intersects_centerline =
false;
775 double cancel_arc_length = 0.0;
777 std::vector<Eigen::Vector2d> cancel_line_2d = {
toEigen2d(cancel_line->at(0)),
toEigen2d(cancel_line->at(1))};
778 for (
size_t i = 0; i < centerline.size() - 1; ++i) {
779 std::vector<Eigen::Vector2d> centerline_segment = {centerline[i], centerline[i + 1]};
781 if (result->intersects_line1 && result->intersects_line2) {
783 lanelet::geometry::toArcCoordinates(lanelet.centerline2d(),
toLanelet(result->intersection)).length;
784 cancel_line_intersects_centerline =
true;
792 double point_arc_length = lanelet::geometry::toArcCoordinates(lanelet.centerline2d(),
toLanelet(point)).length;
793 bool point_is_behind_reference_line = (!reference_line_intersects_centerline || (point_arc_length >= reference_arc_length));
794 bool point_is_before_cancel_line = (!cancel_line_intersects_centerline || (point_arc_length < cancel_arc_length));
795 if (!point_is_behind_reference_line) {
796 found_future_reference_line =
true;
798 if (!point_is_before_cancel_line) {
799 found_past_cancel_line =
true;
801 if (point_is_behind_reference_line && point_is_before_cancel_line) {
802 if (!found_valid_regulatory_element_speed_limit || reference_arc_length > best_reference_arc_length) {
805 speed_limit = regulatory_element_meta_value;
806 best_reference_arc_length = reference_arc_length;
807 found_valid_regulatory_element_speed_limit =
true;
819 if (!found_valid_regulatory_element_speed_limit) {
820 if (found_future_reference_line || found_past_cancel_line) {
828 std::clamp(speed_limit,
static_cast<uint8_t
>(0), route_planning_msgs::msg::RegulatoryElement::META_VALUE_SPEED_UNLIMITED);
833std::tuple<uint8_t, int>
suggestedTurnSignal(
const lanelet::ConstLanelet& lanelet,
const rclcpp::Logger& logger) {
834 uint8_t suggested_turn_signal = route_planning_msgs::msg::LaneElement::SUGGESTED_TURN_SIGNAL_NONE;
835 int suggested_turn_signal_distance_ahead = -1;
838 if (lanelet.hasAttribute(
"suggested_turn_signal")) {
839 std::string suggested_turn_signal_str = lanelet.attribute(
"suggested_turn_signal").value();
840 if (suggested_turn_signal_str ==
"left") {
841 suggested_turn_signal = route_planning_msgs::msg::LaneElement::SUGGESTED_TURN_SIGNAL_LEFT;
842 }
else if (suggested_turn_signal_str ==
"right") {
843 suggested_turn_signal = route_planning_msgs::msg::LaneElement::SUGGESTED_TURN_SIGNAL_RIGHT;
844 }
else if (suggested_turn_signal_str ==
"hazard") {
845 suggested_turn_signal = route_planning_msgs::msg::LaneElement::SUGGESTED_TURN_SIGNAL_HAZARD;
847 suggested_turn_signal = route_planning_msgs::msg::LaneElement::SUGGESTED_TURN_SIGNAL_NONE;
848 RCLCPP_ERROR(logger,
"Could not parse 'suggested_turn_signal' attribute value of lanelet '%ld': '%s'", lanelet.id(),
849 suggested_turn_signal_str.c_str());
850 return std::make_tuple(suggested_turn_signal, suggested_turn_signal_distance_ahead);
854 if (lanelet.hasAttribute(
"suggested_turn_signal_distance_ahead")) {
855 std::string suggested_turn_signal_distance_ahead_str = lanelet.attribute(
"suggested_turn_signal_distance_ahead").value();
857 suggested_turn_signal_distance_ahead = std::stoi(suggested_turn_signal_distance_ahead_str);
858 }
catch (
const std::exception&) {
859 RCLCPP_ERROR(logger,
"Could not parse 'suggested_turn_signal_distance_ahead' attribute value of lanelet '%ld': '%s'",
860 lanelet.id(), suggested_turn_signal_distance_ahead_str.c_str());
861 return std::make_tuple(suggested_turn_signal, suggested_turn_signal_distance_ahead);
863 if (suggested_turn_signal_distance_ahead < 0) {
865 "'suggested_turn_signal_distance_ahead' attribute value of lanelet '%ld' is negative, clamping to 0: %d",
866 lanelet.id(), suggested_turn_signal_distance_ahead);
867 suggested_turn_signal_distance_ahead = 0;
871 "Lanelet '%ld' has 'suggested_turn_signal' attribute but no 'suggested_turn_signal_distance_ahead', ignoring "
872 "suggested turn signal",
876 return std::make_tuple(suggested_turn_signal, suggested_turn_signal_distance_ahead);
880 auto location = lanelet::Locations::Germany;
881 auto vehicle_type = std::string(lanelet::Participants::Vehicle);
882 return lanelet::traffic_rules::TrafficRulesFactory::create(location, vehicle_type);
886 const lanelet::LaneletMapConstPtr& map,
887 const std::optional<lanelet::traffic_rules::TrafficRulesPtr> traffic_rules) {
889 const unsigned int number_of_nearest_lanelets = 5;
890 const double max_lanelet_matching_distance = 5.0;
893 std::vector<std::pair<double, lanelet::ConstLanelet>> nearest_lanelets =
894 lanelet::geometry::findNearest(map->laneletLayer, point, number_of_nearest_lanelets);
899 for (
const auto& nearest_lanelet : nearest_lanelets) {
900 if (nearest_lanelet.first <= max_lanelet_matching_distance && traffic_rules.value()->canPass(nearest_lanelet.second)) {
901 return nearest_lanelet.second;
904 }
else if (!nearest_lanelets.empty()) {
906 if (nearest_lanelets[0].first <= max_lanelet_matching_distance) {
907 return nearest_lanelets[0].second;
915 const lanelet::ConstLanelet& lanelet,
916 const Eigen::Vector2d& position,
917 const double distance) {
918 lanelet::ConstLanelet followed_lanelet = lanelet;
919 double remaining_length = 0.0;
921 remaining_length =
static_cast<double>(lanelet::geometry::length(lanelet.centerline2d())) -
922 lanelet::geometry::toArcCoordinates(lanelet.centerline2d(), position).length;
924 remaining_length = lanelet::geometry::toArcCoordinates(lanelet.centerline2d(), position).length;
926 double remaining_distance = std::abs(distance);
928 while (remaining_distance > remaining_length) {
929 lanelet::ConstLanelets next_lanelets;
931 next_lanelets = routing_graph->following(followed_lanelet,
false);
933 next_lanelets = routing_graph->previous(followed_lanelet);
935 if (next_lanelets.empty()) {
938 followed_lanelet = next_lanelets.front();
939 remaining_distance -= remaining_length;
940 remaining_length =
static_cast<double>(lanelet::geometry::length(followed_lanelet.centerline2d()));
943 return followed_lanelet;
947 const double delta_s,
948 bool monotonically) {
951 double resampling_offset = 0.0;
952 Eigen::Vector2d prev_sampled_point = Eigen::Vector2d(0.0, 0.0);
953 Eigen::Vector2d prev_sampled_point_orientation = Eigen::Vector2d(0.0, 0.0);
956 for (
size_t l = 0; l < path.size(); ++l) {
958 const lanelet::ConstLanelet& lanelet = path[l];
959 lanelet::BasicLineString3d centerline = lanelet.centerline().basicLineString();
962 if (monotonically && !result.
centerline.empty()) {
963 for (
auto cit = centerline.begin(); cit != centerline.end();) {
964 auto& centerline_point = *cit;
965 if ((
to2d(centerline_point) - prev_sampled_point).dot(prev_sampled_point_orientation) < 0) {
966 cit = centerline.erase(cit);
975 result.
centerline.insert(result.
centerline.end(), resampled_centerline.begin(), resampled_centerline.end());
979 if (monotonically && !resampled_centerline.empty()) {
980 if (resampled_centerline.size() > 1) {
981 prev_sampled_point =
to2d(resampled_centerline[resampled_centerline.size() - 2]);
983 const Eigen::Vector2d current_sampled_point =
to2d(resampled_centerline.back());
984 prev_sampled_point_orientation =
986 prev_sampled_point = current_sampled_point;
994 if (route.current_route_element_idx >= route.route_elements.size() ||
995 route.starting_route_element_idx >= route.route_elements.size()) {
998 double to_current = route.route_elements[route.current_route_element_idx].s;
999 double ahead_of_starting_point = route.route_elements[route.starting_route_element_idx].s;
1000 double traveled = to_current - ahead_of_starting_point;
1005 if (route.current_route_element_idx >= route.route_elements.size() ||
1006 route.destination_route_element_idx >= route.route_elements.size()) {
1009 double to_current = route.route_elements[route.current_route_element_idx].s;
1010 double to_destination = route.route_elements[route.destination_route_element_idx].s;
1011 double remaining = to_destination - to_current;
1016 double remaining_time = 0.0;
1017 for (
size_t r = route.current_route_element_idx; r < route.route_elements.size() - 1; ++r) {
1018 const auto& route_element = route.route_elements[r];
1019 const auto& next_route_element = route.route_elements[r + 1];
1020 double speed_limit = route_planning_msgs::route_access::getSuggestedLaneElement(route_element).speed_limit;
1021 if (speed_limit == 0) {
1022 speed_limit = reference_speed;
1024 if (speed_limit > 0) {
1025 remaining_time += (next_route_element.s - route_element.s) / speed_limit;
1028 return remaining_time;
1032 route_planning_msgs::msg::Route& route_msg,
1033 std::vector<std::vector<int>>& suggested_turn_signal_distance_ahead_by_route_element_by_lane_element) {
1035 std::vector<route_planning_msgs::msg::RouteElement>& route_elements = route_msg.route_elements;
1036 for (
size_t r = 0; r < route_elements.size(); ++r) {
1038 auto& route_element = route_elements[r];
1039 auto& prev_route_element = (r > 0) ? route_elements[r - 1] : route_element;
1040 const auto& next_route_element = (r < route_elements.size() - 1) ? route_elements[r + 1] : route_element;
1044 if (!prev_route_element.is_enriched) {
1045 prev_route_element.lane_elements[0].has_following_lane_idx =
true;
1046 prev_route_element.lane_elements[0].following_lane_idx = route_element.suggested_lane_idx;
1051 for (
size_t l = 0; l < route_element.lane_elements.size(); ++l) {
1053 auto& lane_element = route_element.lane_elements[l];
1054 const auto prev_lane_element_opt = route_planning_msgs::route_access::getPrecedingLaneElement(l, prev_route_element);
1055 const auto next_lane_element_opt =
1056 route_planning_msgs::route_access::getFollowingLaneElement(lane_element, next_route_element);
1059 const auto point =
toEigen2d(lane_element.reference_pose.position);
1060 const bool changes_lane_from_prev_point = prev_route_element.will_change_suggested_lane;
1061 const bool changes_lane_to_next_point = next_route_element.will_change_suggested_lane;
1062 const auto prev_point_for_orientation = (changes_lane_from_prev_point || !prev_lane_element_opt)
1064 :
toEigen2d(prev_lane_element_opt->reference_pose.position);
1065 const auto next_point_for_orientation = (changes_lane_to_next_point || !next_lane_element_opt)
1067 :
toEigen2d(next_lane_element_opt->reference_pose.position);
1071 lane_element.reference_pose.orientation =
toRosQuaternion(orientation);
1076 for (
int r =
static_cast<int>(route_elements.size()) - 1; r >= 0; --r) {
1077 auto& route_element = route_elements[r];
1078 if (!route_element.is_enriched)
continue;
1081 for (
size_t l = 0; l < route_element.lane_elements.size(); ++l) {
1082 auto& lane_element = route_element.lane_elements[l];
1084 if (suggested_turn_signal_distance_ahead_by_route_element_by_lane_element[r].empty())
continue;
1085 int suggested_turn_signal_distance_ahead = suggested_turn_signal_distance_ahead_by_route_element_by_lane_element[r][l];
1090 auto* curr_lane_element = &lane_element;
1091 auto* prev_route_element = &route_elements[r - 1];
1092 auto prev_lane_element_idx_opt = route_planning_msgs::route_access::getPrecedingLaneElementIdx(l, *prev_route_element);
1095 while (suggested_turn_signal_distance_ahead > 0 && prev_lane_element_idx_opt) {
1096 auto& prev_lane_element = prev_route_element->lane_elements[*prev_lane_element_idx_opt];
1097 if (!prev_route_element->is_enriched)
break;
1100 if (!suggested_turn_signal_distance_ahead_by_route_element_by_lane_element[curr_r - 1].empty()) {
1101 int prev_suggested_turn_signal_distance_ahead =
1102 suggested_turn_signal_distance_ahead_by_route_element_by_lane_element[curr_r - 1][*prev_lane_element_idx_opt];
1103 if (prev_suggested_turn_signal_distance_ahead >= 0) {
1109 const auto point =
toEigen2d(curr_lane_element->reference_pose.position);
1110 const auto prev_point =
toEigen2d(prev_lane_element.reference_pose.position);
1111 const double distance_to_prev_point = (point - prev_point).norm();
1112 if (distance_to_prev_point > suggested_turn_signal_distance_ahead) {
1117 prev_lane_element.suggested_turn_signal = lane_element.suggested_turn_signal;
1120 suggested_turn_signal_distance_ahead -=
static_cast<uint8_t
>(std::round(distance_to_prev_point));
1122 if (curr_r <= 0)
break;
1123 curr_lane_element = &prev_lane_element;
1124 prev_route_element = &route_elements[curr_r - 1];
1125 prev_lane_element_idx_opt =
1126 route_planning_msgs::route_access::getPrecedingLaneElementIdx(*prev_lane_element_idx_opt, *prev_route_element);
1133 std::vector<std::pair<double, lanelet::ConstLanelet>>& lanelets_with_distances,
1134 const std::optional<lanelet::traffic_rules::TrafficRulesPtr>& traffic_rules) {
1135 struct LaneletMatchingCost {
1136 std::pair<double, lanelet::ConstLanelet> lanelet_with_distance;
1140 std::vector<LaneletMatchingCost> lanelet_matching_costs;
1141 lanelet_matching_costs.reserve(lanelets_with_distances.size());
1144 for (
const auto& lanelet_with_distance : lanelets_with_distances) {
1145 const lanelet::ConstLanelet& lanelet = lanelet_with_distance.second;
1146 const lanelet::ArcCoordinates arc_coordinates = lanelet::geometry::toArcCoordinates(lanelet.centerline2d(), point);
1147 const bool point_is_inside_lanelet = lanelet::geometry::inside(lanelet, point);
1150 double cost = (point_is_inside_lanelet ? 0.5 : 2.0) * arc_coordinates.distance * arc_coordinates.distance;
1153 if (traffic_rules && !traffic_rules.value()->canPass(lanelet)) {
1157 lanelet_matching_costs.push_back({lanelet_with_distance, cost});
1161 std::sort(lanelet_matching_costs.begin(), lanelet_matching_costs.end(),
1162 [](
const LaneletMatchingCost& lhs,
const LaneletMatchingCost& rhs) { return lhs.cost < rhs.cost; });
1164 for (
size_t i = 0; i < lanelet_matching_costs.size(); ++i) {
1165 lanelets_with_distances.at(i) = lanelet_matching_costs[i].lanelet_with_distance;
1170 const size_t current_global_idx,
1171 const double distance_behind,
1172 const double distance_ahead) {
1174 result.
route.header = full_route.header;
1175 result.
route.destination = full_route.destination;
1176 result.
route.intermediate_destinations = full_route.intermediate_destinations;
1177 const auto& full_route_elements = full_route.route_elements;
1178 if (current_global_idx >= full_route_elements.size()) {
1179 result.
route.route_elements.clear();
1184 const double current_s = full_route_elements[current_global_idx].s;
1185 const auto first_it = std::lower_bound(
1186 full_route_elements.begin(), full_route_elements.end(), current_s - distance_behind,
1187 [](
const route_planning_msgs::msg::RouteElement& route_element,
const double s) { return route_element.s < s; });
1188 const auto last_it = std::upper_bound(
1189 full_route_elements.begin(), full_route_elements.end(), current_s + distance_ahead,
1190 [](
const double s,
const route_planning_msgs::msg::RouteElement& route_element) { return s < route_element.s; });
1191 result.
first_global_idx = std::distance(full_route_elements.begin(), first_it);
1192 const size_t last_global_idx = std::distance(full_route_elements.begin(), last_it);
1193 result.
route.route_elements.assign(first_it, last_it);
1196 const auto remap_global_idx = [first_global_idx = result.
first_global_idx, last_global_idx](
const uint64_t global_idx) {
1197 return (global_idx >= first_global_idx && global_idx < last_global_idx)
1198 ? global_idx - first_global_idx
1199 : route_planning_msgs::msg::Route::INVALID_ROUTE_ELEMENT_IDX;
1201 result.
route.starting_route_element_idx = remap_global_idx(full_route.starting_route_element_idx);
1203 result.
route.destination_route_element_idx = remap_global_idx(full_route.destination_route_element_idx);
std::optional< ProjectPointToLineStringAlongAxisResult > projectPointToLineStringAlongNormal(const Eigen::Vector2d &point, const Eigen::Vector2d &prev_point, const Eigen::Vector2d &next_point, const std::vector< Eigen::Vector2d > &line_string)
Projects a point to the closest line segment of a line string along the normal to the tangent at the ...
uint8_t laneBoundaryType(const lanelet::ConstLineString2d &line)
Extracts the lane boundary type of a lanelet line.
lanelet::ConstLanelet followLaneletsAlongRoutingGraph(const lanelet::routing::RoutingGraphUPtr &routing_graph, const lanelet::ConstLanelet &lanelet, const Eigen::Vector2d &position, const double distance)
Follows a lanelet's and following lanelets' centerline for a given distance.
double distanceTraveled(const route_planning_msgs::msg::Route &route)
Computes the traveled distance along the route.
double angleBetweenVectors(const Eigen::Vector2d &v1, const Eigen::Vector2d &v2)
Computes the angle between two 2D vectors.
lanelet::traffic_rules::TrafficRulesPtr getTrafficRules()
Get traffic rules.
bool changesLaneFromPointToPoint(const Eigen::Vector2d &point, const Eigen::Vector2d &next_point, const double sampling_distance)
Identifies a lane change based on the distance between two reference line points.
std::optional< lanelet::routing::Route > getRoute(const lanelet::routing::RoutingGraphUPtr &routing_graph, const std::vector< lanelet::ConstLanelet > &route_lanelets)
Computes a route from start to destination along intermediate destinations.
std::optional< std::array< geometry_msgs::msg::Point, 2 > > regulatoryElementReferenceLine(const std::shared_ptr< const lanelet::RegulatoryElement > ®ulatory_element)
Extracts the reference/effect line of a regulatory element.
std::vector< geometry_msgs::msg::Point > regulatoryElementPositions(const std::shared_ptr< const lanelet::RegulatoryElement > ®ulatory_element)
Extracts the sign/signal positions of a regulatory element.
bool isLineStringDrivable(const lanelet::ConstLineString3d &line_string)
Checks if lanelet line string has a type that is considered drivable.
size_t matchPointToLineString(const std::vector< Eigen::Vector2d > &line_string, const Eigen::Vector2d &point, const size_t idx_indication, const bool consider_order=false, const bool behind=true)
Finds the index of a point in a line string that is locally closest to another point.
Eigen::Vector2d tangentOfPointAlongLineString(const Eigen::Vector2d &point, const Eigen::Vector2d &prev_point, const Eigen::Vector2d &next_point)
Computes a unit vector tangential to a point along a line string.
LocalRouteWindow extractLocalRouteWindow(const route_planning_msgs::msg::Route &full_route, size_t current_global_idx, double distance_behind, double distance_ahead)
Extracts a local route window while preserving absolute route data.
ExtractRegulatoryElementsResult extractRegulatoryElements(const lanelet::ConstLanelet &lanelet, const std::vector< lanelet::ConstLanelet > &adjacent_left_lanelets, const std::vector< lanelet::ConstLanelet > &adjacent_right_lanelets, const PointSequence &point_sequence)
Extracts regulatory element information for a route element.
double estimateRemainingTime(const route_planning_msgs::msg::Route &route, const double reference_speed=50.0/3.6)
Estimate remaining time for a route based on speed limits.
route_planning_msgs::msg::RouteElement createMinimalRouteElement(const geometry_msgs::msg::Point &position, const geometry_msgs::msg::Quaternion &orientation, double s=0.0, bool will_change_suggested_lane=false, uint8_t speed_limit=0)
Create a minimal route element message.
lanelet::BasicPoint2d toLanelet(const Eigen::Vector2d &point)
Converts a 2D Eigen point to a Lanelet point.
uint8_t speedLimit(const lanelet::ConstLanelet &lanelet, const bool consider_regulatory_elements=true)
Extracts the speed limit of a lanelet.
std::optional< std::array< geometry_msgs::msg::Point, 2 > > regulatoryElementCancelLine(const std::shared_ptr< const lanelet::RegulatoryElement > ®ulatory_element)
Extracts the cancel line of a regulatory element.
geometry_msgs::msg::Quaternion toRosQuaternion(const Eigen::Vector2d &vector)
Converts a 2D Eigen vector pointing in a specific direction to a ROS quaternion.
Eigen::Vector2d normalOfPointAlongLineString(const Eigen::Vector2d &point, const Eigen::Vector2d &prev_point, const Eigen::Vector2d &next_point)
Computes a unit vector normal to a point along a line string.
std::vector< Eigen::Vector3d > resampleLineString(const std::vector< Eigen::Vector3d > &line_string, const double delta, double &offset)
Resamples a 3D line string with a constant sampling distance.
std::optional< int > computeFollowingLaneIdxOffset(const lanelet::ConstLanelet &lanelet, const lanelet::ConstLanelet &lanelet_of_next_point, const lanelet::routing::RoutingGraphUPtr &routing_graph)
Computes the offset of lane element indices from current to next route element.
void sortLaneletsByMatchingCost(const lanelet::BasicPoint2d &point, std::vector< std::pair< double, lanelet::ConstLanelet > > &lanelets_with_distances, const std::optional< lanelet::traffic_rules::TrafficRulesPtr > &traffic_rules=std::nullopt)
Sorts lanelet candidates by their matching cost for a 2D point.
size_t indexOfLineStringPointClosestToPoint(const std::vector< Eigen::Vector2d > &line_string, const Eigen::Vector2d &point, const bool consider_order=false, const bool behind=true)
Finds the index of a point in a line string that is closest to another point.
Eigen::Vector2d to2d(const Eigen::Vector3d &point)
Converts a 3D Eigen point to a 2D Eigen point.
geometry_msgs::msg::Point toRos(const Eigen::Vector2d &point)
Converts a 2D Eigen point to a ROS point.
ResampleCenterlinesAlongPathResult resampleCenterlinesAlongPath(const lanelet::routing::LaneletPath &path, const double delta_s, bool monotonically)
Equidistantly resamples lanelet centerlines along a path to one joint centerline.
size_t considerOrderForPointMatchedToLineString(const std::vector< Eigen::Vector2d > &line_string, const Eigen::Vector2d &point, const size_t idx_closest, const bool behind)
Takes a closest point in a line string and guarantees that it is behind or ahead of the given point.
std::optional< IntersectionOfLinesResult > intersectionOfLines(const std::vector< Eigen::Vector2d > &line1, const std::vector< Eigen::Vector2d > &line2)
Computes the intersection of two 2D lines.
Eigen::Vector2d toEigen2d(const geometry_msgs::msg::Point &point)
Converts a ROS point to a 2D Eigen point.
void postprocessRouteMessage(route_planning_msgs::msg::Route &route_msg, std::vector< std::vector< int > > &suggested_turn_signal_distance_ahead_by_route_element_by_lane_element)
Postprocesses a route message, filling missing information that can be inferred from other message co...
std::pair< Eigen::Vector2d, Eigen::Vector2d > extractDrivableSpace(const lanelet::LineStringLayer &line_string_layer, const PointSequence &point_sequence, const double max_distance)
Extracts drivable space boundaries for a route element.
std::pair< uint8_t, uint8_t > regulatoryElementType(const std::shared_ptr< const lanelet::RegulatoryElement > ®ulatory_element)
Extracts the type and meta value of a regulatory element.
std::vector< lanelet::ConstLanelet > adjacentLeftOrRightLanelets(const lanelet::ConstLanelet &lanelet, const lanelet::routing::RoutingGraphUPtr &routing_graph, bool left, bool sort_from_left=true)
Finds lanelets adjacent to the left or right of a given lanelet.
std::optional< lanelet::ConstLanelet > laneletAtPoint(const Eigen::Vector2d &point, const lanelet::LaneletMapConstPtr &map, const std::optional< lanelet::traffic_rules::TrafficRulesPtr > traffic_rules=std::nullopt)
Find lanelet at arbitrary point.
std::vector< ProjectedLaneletPoints > projectPointToLaneletLines(const Eigen::Vector2d &point, const Eigen::Vector2d &prev_point, const Eigen::Vector2d &next_point, const std::vector< lanelet::ConstLanelet > &lanelets, const rclcpp::Logger &logger=rclcpp::get_logger("lanelet2_route_planning"))
Projects a point to the centerline and bounds of a set of lanelets.
uint8_t regulatoryElementSpeedLimit(const std::shared_ptr< const lanelet::RegulatoryElement > ®ulatory_element)
Extracts the speed limit of a regulatory element of subtype 'speed_limit'.
std::tuple< uint8_t, int > suggestedTurnSignal(const lanelet::ConstLanelet &lanelet, const rclcpp::Logger &logger)
Extracts the suggested turn signal of a lanelet.
Eigen::Vector3d toEigen(const geometry_msgs::msg::Point &point)
Converts a ROS point to a 3D Eigen point.
double distanceRemaining(const route_planning_msgs::msg::Route &route)
Computes the remaining distance along the route.
A local route window and its offset in the complete route.
route_planning_msgs::msg::Route route
Helper type for a sequence of three points.
Eigen::Vector2d next
next point
Eigen::Vector2d prev
previous point
Eigen::Vector2d current
current point
Projected lanelet points.
Eigen::Vector2d centerline_point
projected centerline point
Eigen::Vector2d right_bound_point
projected right bound point
Eigen::Vector2d left_bound_point
projected left bound point
Return type of resampleCenterlinesAlongPath.
std::vector< Eigen::Vector3d > centerline
resampled centerline
std::vector< size_t > lanelet_idx_by_point
lanelet index in path for each point