lanelet2_route_planning v2.0.0
Loading...
Searching...
No Matches
lanelet2_route_planning Namespace Reference

Classes

struct  ExtractRegulatoryElementsResult
 Return type of extractRegulatoryElements. More...
 
struct  IntersectionOfLinesResult
 Return type of intersectionOfLines. More...
 
struct  is_vector
 
struct  is_vector< std::vector< T, A > >
 
class  Lanelet2RoutePlanning
 Lanelet2 route planning node. More...
 
struct  LocalRouteWindow
 A local route window and its offset in the complete route. More...
 
struct  PointSequence
 Helper type for a sequence of three points. More...
 
struct  ProjectedLaneletPoints
 Projected lanelet points. More...
 
struct  ProjectPointToLineStringAlongAxisResult
 Return type of projectPointToLineStringAlongAxis. More...
 
struct  ResampleCenterlinesAlongPathResult
 Return type of resampleCenterlinesAlongPath. More...
 
struct  TopicDiagnosticConfig
 Configuration parameters for topic diagnostics. More...
 

Functions

Eigen::Vector2d to2d (const Eigen::Vector3d &point)
 Converts a 3D Eigen point to a 2D Eigen point.
 
Eigen::Vector3d to3d (const Eigen::Vector2d &point)
 Converts a 2D Eigen point to a 3D Eigen point.
 
Eigen::Vector3d to3d (const Eigen::Vector2d &point, double z)
 Converts a 2D Eigen point to a 3D Eigen point.
 
std::vector< Eigen::Vector2d > to2d (const std::vector< Eigen::Vector3d > &points)
 Converts a vector of 3D Eigen points to a vector of 2D Eigen points.
 
std::vector< Eigen::Vector3d > to3d (const std::vector< Eigen::Vector2d > &points)
 Converts a vector of 2D Eigen points to a vector of 3D Eigen points.
 
geometry_msgs::msg::Point toRos (const Eigen::Vector2d &point)
 Converts a 2D Eigen point to a ROS point.
 
geometry_msgs::msg::Point toRos (const Eigen::Vector3d &point)
 Converts a 3D Eigen point to a ROS point.
 
geometry_msgs::msg::Point toRos (const lanelet::BasicPoint2d &point)
 Converts a 2D Lanelet point to a ROS point.
 
lanelet::BasicPoint2d toLanelet (const Eigen::Vector2d &point)
 Converts a 2D Eigen point to a Lanelet point.
 
lanelet::BasicPoint3d toLanelet (const Eigen::Vector3d &point)
 Converts a 3D Eigen point to a Lanelet point.
 
Eigen::Vector2d toEigen2d (const geometry_msgs::msg::Point &point)
 Converts a ROS point to a 2D Eigen point.
 
Eigen::Vector3d toEigen (const geometry_msgs::msg::Point &point)
 Converts a ROS point to a 3D Eigen point.
 
geometry_msgs::msg::Point egoPosition (const perception_msgs::msg::EgoData &ego_data)
 Extracts an EgoData position as a ROS point.
 
std::vector< Eigen::Vector2d > toEigen (const lanelet::BasicLineString2d &line_string)
 Converts a 2D Lanelet line string to a vector of Eigen points.
 
std::vector< Eigen::Vector3d > toEigen (const lanelet::BasicLineString3d &line_string)
 Converts a 3D Lanelet line string to a vector of Eigen points.
 
lanelet::BasicLineString2d toLanelet (const std::vector< Eigen::Vector2d > &line_string)
 Converts a vector of 2D Eigen points to a Lanelet line string.
 
lanelet::BasicLineString3d toLanelet (const std::vector< Eigen::Vector3d > &line_string)
 Converts a vector of 3D Eigen points to a Lanelet line string.
 
geometry_msgs::msg::Quaternion toRosQuaternion (const Eigen::Vector2d &vector)
 Converts a 2D Eigen vector pointing in a specific direction to a ROS quaternion.
 
std::vector< Eigen::Vector3d > suggestedReferenceLineToEigen (const std::vector< route_planning_msgs::msg::RouteElement > &route_elements)
 Extracts the reference line along the suggested lane from a list of RouteElements.
 
double wrapAngle (const double angle)
 Wraps an angle to the range [-π, π].
 
double angleBetweenVectors (const Eigen::Vector2d &v1, const Eigen::Vector2d &v2)
 Computes the angle between two 2D vectors.
 
std::optional< IntersectionOfLinesResultintersectionOfLines (const std::vector< Eigen::Vector2d > &line1, const std::vector< Eigen::Vector2d > &line2)
 Computes the intersection of two 2D lines.
 
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.
 
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::vector< size_t > adaptivelySampleLineString (const std::vector< Eigen::Vector2d > &line_string, double max_lateral_error, const std::vector< size_t > &break_after_indices={})
 Simplifies a 2D line string within a maximum lateral error.
 
Eigen::Vector2d projectPointToLineString (const Eigen::Vector2d &point, const std::vector< Eigen::Vector2d > &line_string)
 Projects a point to the closest line segment of a line string.
 
Eigen::Vector3d projectPointToLineString (const Eigen::Vector3d &point, const std::vector< Eigen::Vector3d > &line_string)
 Projects a 3D point to the closest line segment of a 3D line string.
 
std::optional< ProjectPointToLineStringAlongAxisResultprojectPointToLineStringAlongAxis (const Eigen::Vector2d &point, const Eigen::Vector2d &axis, const std::vector< Eigen::Vector2d > &line_string)
 Projects a point along an axis to the closest line segment of a line string.
 
std::optional< ProjectPointToLineStringAlongAxisResultprojectPointToLineStringAlongNormal (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 point.
 
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.
 
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.
 
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.
 
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.
 
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.
 
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::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::vector< ProjectedLaneletPointsprojectPointToLaneletLines (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.
 
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.
 
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.
 
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.
 
bool isLineStringDrivable (const lanelet::ConstLineString3d &line_string)
 Checks if lanelet line string has a type that is considered drivable.
 
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.
 
std::optional< std::array< geometry_msgs::msg::Point, 2 > > regulatoryElementReferenceLine (const std::shared_ptr< const lanelet::RegulatoryElement > &regulatory_element)
 Extracts the reference/effect line of a regulatory element.
 
std::optional< std::array< geometry_msgs::msg::Point, 2 > > regulatoryElementCancelLine (const std::shared_ptr< const lanelet::RegulatoryElement > &regulatory_element)
 Extracts the cancel line of a regulatory element.
 
std::vector< geometry_msgs::msg::Point > regulatoryElementPositions (const std::shared_ptr< const lanelet::RegulatoryElement > &regulatory_element)
 Extracts the sign/signal positions of a regulatory element.
 
std::pair< uint8_t, uint8_t > regulatoryElementType (const std::shared_ptr< const lanelet::RegulatoryElement > &regulatory_element)
 Extracts the type and meta value of a regulatory element.
 
uint8_t regulatoryElementSpeedLimit (const std::shared_ptr< const lanelet::RegulatoryElement > &regulatory_element)
 Extracts the speed limit of a regulatory element of subtype 'speed_limit'.
 
uint8_t laneBoundaryType (const lanelet::ConstLineString2d &line)
 Extracts the lane boundary type of a lanelet line.
 
uint8_t speedLimit (const lanelet::ConstLanelet &lanelet, const bool consider_regulatory_elements=true)
 Extracts the speed limit of a lanelet.
 
uint8_t speedLimit (const lanelet::ConstLanelet &lanelet, const Eigen::Vector2d &point)
 Extracts the speed limit of a lanelet at a specific position on that lanelet.
 
std::tuple< uint8_t, int > suggestedTurnSignal (const lanelet::ConstLanelet &lanelet, const rclcpp::Logger &logger)
 Extracts the suggested turn signal of a lanelet.
 
lanelet::traffic_rules::TrafficRulesPtr getTrafficRules ()
 Get traffic rules.
 
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.
 
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.
 
ResampleCenterlinesAlongPathResult resampleCenterlinesAlongPath (const lanelet::routing::LaneletPath &path, const double delta_s, bool monotonically)
 Equidistantly resamples lanelet centerlines along a path to one joint centerline.
 
double distanceTraveled (const route_planning_msgs::msg::Route &route)
 Computes the traveled distance along the route.
 
double distanceRemaining (const route_planning_msgs::msg::Route &route)
 Computes the remaining distance along the route.
 
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.
 
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 contents.
 
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.
 

Variables

template<typename C >
constexpr bool is_vector_v = is_vector<C>::value
 

Function Documentation

◆ adaptivelySampleLineString()

std::vector< size_t > lanelet2_route_planning::adaptivelySampleLineString ( const std::vector< Eigen::Vector2d > & line_string,
double max_lateral_error,
const std::vector< size_t > & break_after_indices = {} )

Simplifies a 2D line string within a maximum lateral error.

Uses Ramer-Douglas-Peucker simplification and returns indices into the input. Breaks split the line after the given indices so discontinuities are retained. A maximum error of zero disables simplification.

Parameters
[in]line_stringline string
[in]max_lateral_errormaximum perpendicular deviation [m]
[in]break_after_indicesindices after which to split the line
Returns
retained input indices in ascending order

Definition at line 188 of file geometry.cpp.

190 {
191 std::vector<size_t> retained_indices;
192 if (line_string.empty()) {
193 return retained_indices;
194 }
195 if (max_lateral_error <= 0.0) {
196 retained_indices.resize(line_string.size());
197 std::iota(retained_indices.begin(), retained_indices.end(), 0);
198 return retained_indices;
199 }
200
201 // retain discontinuities, such as lane changes, as separate ranges
202 std::vector<size_t> valid_breaks;
203 for (const size_t index : break_after_indices) {
204 if (index < line_string.size() - 1) {
205 valid_breaks.push_back(index);
206 }
207 }
208 std::sort(valid_breaks.begin(), valid_breaks.end());
209 valid_breaks.erase(std::unique(valid_breaks.begin(), valid_breaks.end()), valid_breaks.end());
210
211 // sample each continuous range independently
212 std::vector<bool> keep(line_string.size(), false);
213 size_t segment_start = 0;
214 for (const size_t break_after : valid_breaks) {
215 if (break_after < segment_start) {
216 continue;
217 }
218 adaptivelySampleLineStringRange(line_string, segment_start, break_after, max_lateral_error, keep);
219 segment_start = break_after + 1;
220 }
221 adaptivelySampleLineStringRange(line_string, segment_start, line_string.size() - 1, max_lateral_error, keep);
222
223 for (size_t i = 0; i < keep.size(); ++i) {
224 if (keep[i]) {
225 retained_indices.push_back(i);
226 }
227 }
228 return retained_indices;
229}

◆ adjacentLeftOrRightLanelets()

std::vector< lanelet::ConstLanelet > lanelet2_route_planning::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.

RelationType::Left and RelationType::AdjacentLeft are used for left adjacent lanelets, right vice versa.

Parameters
[in]laneletlanelet
[in]routing_graphrouting graph
[in]leftwhether to find left or right adjacent lanelets
[in]sort_from_leftwhether to sort from left to right (true) or right to left (false)
Returns
adjacent lanelets

Definition at line 184 of file utils.cpp.

187 {
188 std::vector<lanelet::ConstLanelet> adjacent_lanelets;
189 const int routing_cost_id = 0; // RoutingCostDistance
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);
198 }
199 }
200
201 if ((left && sort_from_left) || (!left && !sort_from_left)) {
202 std::reverse(adjacent_lanelets.begin(), adjacent_lanelets.end());
203 }
204
205 return adjacent_lanelets;
206}

◆ angleBetweenVectors()

double lanelet2_route_planning::angleBetweenVectors ( const Eigen::Vector2d & v1,
const Eigen::Vector2d & v2 )

Computes the angle between two 2D vectors.

Angle is in the range [-π, π].

Parameters
[in]v1vector 1
[in]v2vector 2
Returns
angle between vectors [radians]

Definition at line 80 of file geometry.cpp.

80 {
81 double dot_product = v1.dot(v2);
82 double determinant = v1.x() * v2.y() - v1.y() * v2.x();
83 double angle = std::atan2(determinant, dot_product);
84 return wrapAngle(angle);
85}
double wrapAngle(const double angle)
Wraps an angle to the range [-π, π].
Definition geometry.cpp:73

◆ changesLaneFromPointToPoint()

bool lanelet2_route_planning::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.

Assumes that the two points are part of an equidistant reference line. If the distance between the two points is greater than the sampling distance, a lane change is assumed.

Parameters
[in]pointpoint on reference line
[in]next_pointnext point on reference line
[in]sampling_distanceexpected distance between points
Returns
whether a lane change is identified

Definition at line 177 of file utils.cpp.

179 {
180 const double epsilon = 1e-6;
181 return ((next_point - point).norm() > (sampling_distance + epsilon));
182}

◆ computeFollowingLaneIdxOffset()

std::optional< int > lanelet2_route_planning::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.

The algorithm works as follows:

  • find adjacent lanelets of current lanelet
  • find adjacent lanelets of next lanelet (lanelet of next point)
  • try to match the ID of the lanelet following the current one to the next lanelet and its adjacent lanelets
  • if no match is found, try to match the ID of the lanelets following adjacent lanelets of the current lanelet to the next lanelet and its adjacent lanelets
  • keep following lanelets for up to 3 iterations to account for lanelets that are skipped during sampling

If lane element j of the next route element follows on lane element i of the current route element, the returned offset is (j-i).

Parameters
[in]laneletcurrent lanelet
[in]lanelet_of_next_pointlanelet of next point (on next route element)
[in]routing_graphrouting graph
Returns
following lane index offset

Definition at line 252 of file utils.cpp.

254 {
255 int following_lane_idx_offset = 0;
256 if (lanelet_of_next_point.id() != lanelet.id()) {
257 // get adjacent lanelets of current lanelet
258 std::vector<lanelet::ConstLanelet> adjacent_left_lanelets = adjacentLeftOrRightLanelets(lanelet, routing_graph, true);
259 std::vector<lanelet::ConstLanelet> adjacent_right_lanelets = adjacentLeftOrRightLanelets(lanelet, routing_graph, false);
260 const int suggested_lane_idx = static_cast<int>(adjacent_left_lanelets.size());
261
262 // get adjacent lanelets of next lanelet (lanelet of next point)
263 std::vector<lanelet::ConstLanelet> adjacent_left_lanelets_of_next_lanelet =
264 adjacentLeftOrRightLanelets(lanelet_of_next_point, routing_graph, true);
265 std::vector<lanelet::ConstLanelet> adjacent_right_lanelets_of_next_lanelet =
266 adjacentLeftOrRightLanelets(lanelet_of_next_point, routing_graph, false);
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());
272
273 // find following lanelet of current lanelet and adjacent lanelets in adjacent lanelets of next lanelet
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();
277
278 // first try to match following lanelet of current lanelet, then of adjacent left lanelets, then of adjacent right lanelets
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];
282
283 // loop over all lanelets in group
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()) {
287 continue;
288 }
289 auto following_lanelet = following_lanelets.front();
290 size_t following_lanelet_idx = 0;
291 size_t follow_further_idx =
292 0; // counter for following lanelets more than once (e.g., if sampling skipped short lanelets)
293 size_t max_follow_further_iterations = 3; // maximum number of following lanelets to check
294
295 // loop until following lanelet is found in adjacent lanelets of next lanelet
296 while (following_lane_idx_offset == std::numeric_limits<int>::max()) {
297 // check all adjacent lanelets of next lanelet
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);
302 break;
303 }
304 }
305
306 // check abort conditions
307 follow_further_idx++;
308 if (follow_further_idx >= max_follow_further_iterations) {
309 break;
310 }
311
312 // get next following lanelet
313 following_lanelet_idx++;
314 if (following_lanelet_idx < following_lanelets.size()) {
315 following_lanelet = following_lanelets[following_lanelet_idx];
316 } else {
317 following_lanelets = routing_graph->following(following_lanelet, false);
318 if (following_lanelets.empty()) {
319 continue;
320 }
321 following_lanelet = following_lanelets.front();
322 following_lanelet_idx = 0;
323 }
324 }
325
326 if (following_lane_idx_offset != std::numeric_limits<int>::max()) {
327 break;
328 }
329 }
330
331 if (following_lane_idx_offset != std::numeric_limits<int>::max()) {
332 break;
333 }
334 }
335
336 if (following_lane_idx_offset == std::numeric_limits<int>::max()) {
337 // could not match following lanelets to adjacent lanelets of lanelet of next point
338 return std::nullopt;
339 }
340 }
341
342 return following_lane_idx_offset;
343}
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.
Definition utils.cpp:184

◆ considerOrderForPointMatchedToLineString()

size_t lanelet2_route_planning::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.

Behind/ahead is meant physically, not in the order of the line string. The point behind a point at index i is at index i-1.

Parameters
[in]line_stringline string
[in]pointother point
[in]idx_closestindex of closest point in line string
[in]behindwhether to consider points behind (or ahead of) the given point
Returns

Definition at line 144 of file utils.cpp.

147 {
148 if (line_string.empty()) {
149 return 0;
150 }
151
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];
159 } else {
160 return idx_closest;
161 }
162
163 // use angle to check if closest point is behind or ahead of the given point
164 const double angle = angleBetweenVectors(closest_point_to_point, closest_point_to_next);
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;
169 } else {
170 new_idx_closest = idx_closest;
171 }
172 new_idx_closest = std::clamp(new_idx_closest, size_t{0}, line_string.size() - 1);
173
174 return new_idx_closest;
175}
double angleBetweenVectors(const Eigen::Vector2d &v1, const Eigen::Vector2d &v2)
Computes the angle between two 2D vectors.
Definition geometry.cpp:80

◆ createMinimalRouteElement()

route_planning_msgs::msg::RouteElement lanelet2_route_planning::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.

A minimal valid route element only has a single lane element with a reference pose.

Parameters
[in]positionposition
[in]orientationorientation
[in]saccumulated distance along route
[in]will_change_suggested_lanewhether the lane will change to the next route element
[in]speed_limitspeed limit
Returns
minimal route element

Definition at line 345 of file utils.cpp.

349 {
350 // create RouteElement
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;
356 // route_element_msg.left_boundary not set in global route
357 // route_element_msg.right_boundary not set in global route
358 // route_element_msg.regulatory_elements not set in global route
359
360 // create LaneElement
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;
364 // lane_element_msg.left_boundary not set in global route
365 // lane_element_msg.right_boundary not set in global route
366 lane_element_msg.speed_limit = speed_limit;
367 // lane_element_msg.regulatory_element_idcs not set in global route
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);
371
372 return route_element_msg;
373}

◆ distanceRemaining()

double lanelet2_route_planning::distanceRemaining ( const route_planning_msgs::msg::Route & route)

Computes the remaining distance along the route.

Accurate to the level of route elements. Ignores route overshoot.

Parameters
[in]routeroute
Returns
remaining distance [m]

Definition at line 1004 of file utils.cpp.

1004 {
1005 if (route.current_route_element_idx >= route.route_elements.size() ||
1006 route.destination_route_element_idx >= route.route_elements.size()) {
1007 return 0.0;
1008 }
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;
1012 return remaining;
1013}

◆ distanceTraveled()

double lanelet2_route_planning::distanceTraveled ( const route_planning_msgs::msg::Route & route)

Computes the traveled distance along the route.

Accurate to the level of route elements. Ignores route undershoot.

Parameters
[in]routeroute
Returns
traveled distance [m]

Definition at line 993 of file utils.cpp.

993 {
994 if (route.current_route_element_idx >= route.route_elements.size() ||
995 route.starting_route_element_idx >= route.route_elements.size()) {
996 return 0.0;
997 }
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;
1001 return traveled;
1002}

◆ egoPosition()

geometry_msgs::msg::Point lanelet2_route_planning::egoPosition ( const perception_msgs::msg::EgoData & ego_data)

Extracts an EgoData position as a ROS point.

Parameters
[in]ego_dataego data
Returns
ego data position

Definition at line 53 of file conversions.cpp.

53 {
54 geometry_msgs::msg::Point position;
55 position.x = perception_msgs::object_access::getX(ego_data);
56 position.y = perception_msgs::object_access::getY(ego_data);
57 position.z = perception_msgs::object_access::getZ(ego_data);
58 return position;
59}

◆ estimateRemainingTime()

double lanelet2_route_planning::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.

Parameters
[in]routeroute
[in]reference_speedreference speed if speed limit is not set [m/s]
Returns
estimated remaining time [s]

Definition at line 1015 of file utils.cpp.

1015 {
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;
1023 }
1024 if (speed_limit > 0) {
1025 remaining_time += (next_route_element.s - route_element.s) / speed_limit;
1026 }
1027 }
1028 return remaining_time;
1029}

◆ extractDrivableSpace()

std::pair< Eigen::Vector2d, Eigen::Vector2d > lanelet2_route_planning::extractDrivableSpace ( const lanelet::LineStringLayer & line_string_layer,
const PointSequence & point_sequence,
const double max_distance )

Extracts drivable space boundaries for a route element.

Drivable space is defined as the area around the current point that is physically drivable. To extract it, the intersection of the normal to the current point with all existing map line strings is computed. The outermost intersection point that is not drivable anymore is considered the boundary. If no such point is found, the maximum distance is used.

Parameters
[in]line_string_layermap line string layer
[in]point_sequencepoint sequence (should be centerline of main lanelet)
[in]max_distancemaximum distance to left/right drivable space bounds, if not otherwise restricted
Returns
left and right drivable space bounds

Definition at line 375 of file utils.cpp.

377 {
378 // find all line strings within 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);
382
383 // collect all intersections of the normal through the current point with nearby line strings
384 const std::vector<Eigen::Vector2d> normal_line = {
385 point_sequence.current,
386 point_sequence.current + normalOfPointAlongLineString(point_sequence.current, point_sequence.prev, point_sequence.next)};
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]};
393 auto intersection = intersectionOfLines(normal_line, line_segment);
394 if (!intersection || !intersection->intersects_line2) {
395 continue;
396 }
397
398 const Eigen::Vector2d& projected_point = intersection->intersection;
399 if ((projected_point - point_sequence.current).norm() > max_distance) {
400 continue;
401 }
402
403 projected_points_and_line_string_idcs.emplace_back(projected_point, l);
404 }
405 }
406
407 // sort projected points by distance to current point
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();
411 });
412
413 // split projected points into those left and those right of current point
414 const Eigen::Vector2d tangent = tangentOfPointAlongLineString(point_sequence.current, point_sequence.prev, point_sequence.next);
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) {
418 // determine left/right based on angle between tangent and vector to projected point
419 const Eigen::Vector2d point_to_projected_point = projected_point_and_line_string_idx.first - point_sequence.current;
420 const double angle = angleBetweenVectors(tangent, point_to_projected_point);
421 if (angle > 0) {
422 left_projected_points_and_line_string_idcs.emplace_back(projected_point_and_line_string_idx);
423 } else {
424 right_projected_points_and_line_string_idcs.emplace_back(projected_point_and_line_string_idx);
425 }
426 }
427
428 // find drivable space bounds by following projected points until corresponding line string is not passable anymore
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;
434 if (!isLineStringDrivable(line_string)) {
435 drivable_space_left = projected_point_and_line_string_idx.first;
436 is_drivable_space_left_limited_by_line_strings = true;
437 break;
438 }
439 }
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;
442 if (!isLineStringDrivable(line_string)) {
443 drivable_space_right = projected_point_and_line_string_idx.first;
444 is_drivable_space_right_limited_by_line_strings = true;
445 break;
446 }
447 }
448
449 // if drivable space is not limited by line strings, use maximum distance
450 const Eigen::Vector2d normal = normalOfPointAlongLineString(point_sequence.current, point_sequence.prev, point_sequence.next);
451 if (!is_drivable_space_left_limited_by_line_strings) {
452 drivable_space_left = point_sequence.current - normal * max_distance;
453 }
454 if (!is_drivable_space_right_limited_by_line_strings) {
455 drivable_space_right = point_sequence.current + normal * max_distance;
456 }
457
458 return {drivable_space_left, drivable_space_right};
459}
bool isLineStringDrivable(const lanelet::ConstLineString3d &line_string)
Checks if lanelet line string has a type that is considered drivable.
Definition utils.cpp:461
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.
Definition geometry.cpp:123
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.
Definition geometry.cpp:143
Eigen::Vector2d to2d(const Eigen::Vector3d &point)
Converts a 3D Eigen point to a 2D Eigen point.
std::optional< IntersectionOfLinesResult > intersectionOfLines(const std::vector< Eigen::Vector2d > &line1, const std::vector< Eigen::Vector2d > &line2)
Computes the intersection of two 2D lines.
Definition geometry.cpp:87
Eigen::Vector3d toEigen(const geometry_msgs::msg::Point &point)
Converts a ROS point to a 3D Eigen point.
Eigen::Vector2d next
next point
Definition utils.hpp:220
Eigen::Vector2d prev
previous point
Definition utils.hpp:218
Eigen::Vector2d current
current point
Definition utils.hpp:219

◆ extractLocalRouteWindow()

LocalRouteWindow lanelet2_route_planning::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.

Parameters
[in]full_routecomplete route
[in]current_global_idxcurrent element index in full_route
[in]distance_behinddistance to include behind the current element [m]
[in]distance_aheaddistance to include ahead of the current element [m]
Returns
extracted local route and its global offset

Definition at line 1169 of file utils.cpp.

1172 {
1173 LocalRouteWindow result;
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();
1180 return result;
1181 }
1182
1183 // find the route-element bounds by their absolute distances
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);
1194
1195 // remap route indices from the complete route to the local window
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;
1200 };
1201 result.route.starting_route_element_idx = remap_global_idx(full_route.starting_route_element_idx);
1202 result.route.current_route_element_idx = current_global_idx - result.first_global_idx;
1203 result.route.destination_route_element_idx = remap_global_idx(full_route.destination_route_element_idx);
1204 return result;
1205}
A local route window and its offset in the complete route.
Definition utils.hpp:29
route_planning_msgs::msg::Route route
Definition utils.hpp:30

◆ extractRegulatoryElements()

ExtractRegulatoryElementsResult lanelet2_route_planning::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.

Regulatory elements are queried from a lanelet and its adjacent lanelets. They are only considered if their reference line intersects with the given point sequence, which should be the centerline of the main lanelet. This way, regulatory elements are assignable to the closest route element. Note that the assignment to adjacent lanes is also based on the intersection with the single given point sequence.

Parameters
[in]laneletlanelet
[in]adjacent_left_laneletsleft adjacent lanelets
[in]adjacent_right_laneletsright adjacent lanelets
[in]point_sequencepoint sequence (should be centerline of main lanelet)
Returns
regulatory element information

Definition at line 481 of file utils.cpp.

484 {
485 // init result
487 result.adjacent_left_regulatory_element_idcs.resize(adjacent_left_lanelets.size());
488 result.adjacent_right_regulatory_element_idcs.resize(adjacent_right_lanelets.size());
489
490 // gather lanelets in single vector (left adjacent, current, right adjacent)
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());
494
495 // loop over lanelets
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];
499
500 // loop over regulatory elements of lanelet
501 const auto regulatory_elements = current_lanelet.regulatoryElements();
502 for (const auto& regulatory_element : regulatory_elements) {
503 // create RegulatoryElement
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();
507
508 // extract reference line
509 if (auto reference_line = regulatoryElementReferenceLine(regulatory_element)) {
510 regulatory_element_msg.reference_line = *reference_line;
511
512 // only consider regulatory element if reference line intersects with point sequence
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};
516 if (auto result = intersectionOfLines(reference_line_2d, line_to_next_point)) {
517 if (!result->intersects_line2) {
518 if (auto inner_result = intersectionOfLines(reference_line_2d, line_to_prev_point)) {
519 if (!inner_result->intersects_line2) {
520 continue;
521 }
522 }
523 }
524 }
525 } else {
526 continue;
527 }
528
529 // extract sign positions and type
530 regulatory_element_msg.positions = regulatoryElementPositions(regulatory_element);
531 std::tie(regulatory_element_msg.type, regulatory_element_msg.meta_value) = regulatoryElementType(regulatory_element);
532
533 // check if regulatory element has already been extracted (by another lanelet)
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()];
537 } else {
538 // add regulatory element to result
539 regulatory_element_msg_idx = result.regulatory_element_msgs.size();
540 regulatory_element_msg_idx_by_id[regulatory_element->id()] = regulatory_element_msg_idx;
541 result.regulatory_element_msgs.push_back(regulatory_element_msg);
542 }
543
544 // assign regulatory element to respective lanelet in result
545 if (l < adjacent_left_lanelets.size()) {
546 result.adjacent_left_regulatory_element_idcs[l].push_back(regulatory_element_msg_idx);
547 } else if (l < adjacent_left_lanelets.size() + 1) {
548 result.regulatory_element_idcs.push_back(regulatory_element_msg_idx);
549 } else {
550 size_t l_right = l - adjacent_left_lanelets.size() - 1;
551 result.adjacent_right_regulatory_element_idcs[l_right].push_back(regulatory_element_msg_idx);
552 }
553 }
554 }
555
556 return result;
557}
std::optional< std::array< geometry_msgs::msg::Point, 2 > > regulatoryElementReferenceLine(const std::shared_ptr< const lanelet::RegulatoryElement > &regulatory_element)
Extracts the reference/effect line of a regulatory element.
Definition utils.cpp:559
std::vector< geometry_msgs::msg::Point > regulatoryElementPositions(const std::shared_ptr< const lanelet::RegulatoryElement > &regulatory_element)
Extracts the sign/signal positions of a regulatory element.
Definition utils.cpp:589
Eigen::Vector2d toEigen2d(const geometry_msgs::msg::Point &point)
Converts a ROS point to a 2D Eigen point.
std::pair< uint8_t, uint8_t > regulatoryElementType(const std::shared_ptr< const lanelet::RegulatoryElement > &regulatory_element)
Extracts the type and meta value of a regulatory element.
Definition utils.cpp:603
Return type of extractRegulatoryElements.
Definition utils.hpp:280
std::vector< std::vector< uint8_t > > adjacent_right_regulatory_element_idcs
indices of regulatory elements belonging to right adjacent lanes
Definition utils.hpp:287
std::vector< uint8_t > regulatory_element_idcs
indices of regulatory elements belonging to main lane
Definition utils.hpp:283
std::vector< std::vector< uint8_t > > adjacent_left_regulatory_element_idcs
indices of regulatory elements belonging to left adjacent lanes
Definition utils.hpp:285
std::vector< route_planning_msgs::msg::RegulatoryElement > regulatory_element_msgs
regulatory element messages for route element
Definition utils.hpp:282

◆ followLaneletsAlongRoutingGraph()

lanelet::ConstLanelet lanelet2_route_planning::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.

If lanelets cannot be followed anymore, returns the last lanelet.

Parameters
[in]routing_graphrouting graph
[in]laneletcurrent lanelet
[in]positionposition on current lanelet
[in]distancedistance to follow lanelets (may be negative to follow in opposite direction)
Returns
followed lanelet

Definition at line 914 of file utils.cpp.

917 {
918 lanelet::ConstLanelet followed_lanelet = lanelet;
919 double remaining_length = 0.0;
920 if (distance > 0) {
921 remaining_length = static_cast<double>(lanelet::geometry::length(lanelet.centerline2d())) -
922 lanelet::geometry::toArcCoordinates(lanelet.centerline2d(), position).length;
923 } else {
924 remaining_length = lanelet::geometry::toArcCoordinates(lanelet.centerline2d(), position).length;
925 }
926 double remaining_distance = std::abs(distance);
927
928 while (remaining_distance > remaining_length) {
929 lanelet::ConstLanelets next_lanelets;
930 if (distance > 0) {
931 next_lanelets = routing_graph->following(followed_lanelet, false);
932 } else {
933 next_lanelets = routing_graph->previous(followed_lanelet);
934 }
935 if (next_lanelets.empty()) {
936 break;
937 }
938 followed_lanelet = next_lanelets.front();
939 remaining_distance -= remaining_length;
940 remaining_length = static_cast<double>(lanelet::geometry::length(followed_lanelet.centerline2d()));
941 }
942
943 return followed_lanelet;
944}

◆ getRoute()

std::optional< lanelet::routing::Route > lanelet2_route_planning::getRoute ( const lanelet::routing::RoutingGraphUPtr & routing_graph,
const std::vector< lanelet::ConstLanelet > & route_lanelets )

Computes a route from start to destination along intermediate destinations.

Parameters
[in]routing_graphrouting graph
[in]route_laneletslanelets to plan along, starting with start lanelet, ending with destination lanelet
Returns
route if found, otherwise std::nullopt

Definition at line 26 of file utils.cpp.

27 {
28 if (route_lanelets.empty()) {
29 return std::nullopt;
30 }
31
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();
35
36 // compute default route
37 const int routing_cost_id = 0; // RoutingCostDistance
38 const bool with_lane_changes = true;
39 auto route =
40 routing_graph->getRouteVia(start_lanelet, intermediate_lanelets, destination_lanelet, routing_cost_id, with_lane_changes);
41
42 // compute route alternatives with inverted start/destination lanelets (useful, if they are bidirectional)
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));
54
55 // select shortest route
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(); });
59
60 if (shortest_route_ptr == route_alternatives.end()) {
61 return std::nullopt;
62 }
63 auto shortest_route = std::optional<lanelet::routing::Route>(std::move(*shortest_route_ptr));
64 return shortest_route;
65}

◆ getTrafficRules()

lanelet::traffic_rules::TrafficRulesPtr lanelet2_route_planning::getTrafficRules ( )

Get traffic rules.

Returns
traffic rules

Definition at line 879 of file utils.cpp.

879 {
880 auto location = lanelet::Locations::Germany; // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
881 auto vehicle_type = std::string(lanelet::Participants::Vehicle); // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
882 return lanelet::traffic_rules::TrafficRulesFactory::create(location, vehicle_type);
883}

◆ indexOfLineStringPointClosestToPoint()

size_t lanelet2_route_planning::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.

If consider_order, then only the points behind or ahead of the projection of the given point are considered.

Parameters
[in]line_stringline string
[in]pointother point
[in]consider_orderwhether to consider the order of points in the line string
[in]behindwhether to consider points behind (or ahead of) the given point
Returns
index of closest point

Definition at line 67 of file utils.cpp.

70 {
71 if (line_string.empty()) {
72 return 0;
73 }
74
75 // loop over all points in line string to find closest one to given point
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;
82 idx_closest = i;
83 }
84 }
85
86 // if considering order, make sure to return the point behind or ahead of the given point
87 if (consider_order) {
88 idx_closest = considerOrderForPointMatchedToLineString(line_string, point, idx_closest, behind);
89 }
90
91 return idx_closest;
92}
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.
Definition utils.cpp:144

◆ intersectionOfLines()

std::optional< IntersectionOfLinesResult > lanelet2_route_planning::intersectionOfLines ( const std::vector< Eigen::Vector2d > & line1,
const std::vector< Eigen::Vector2d > & line2 )

Computes the intersection of two 2D lines.

Parameters
[in]line1first line defined by two points
[in]line2second line defined by two points
Returns
intersection point and whether intersection is on line segments

Definition at line 87 of file geometry.cpp.

88 {
90
91 // check if lines are valid
92 if (line1.size() < 2 || line2.size() < 2) {
93 return std::nullopt;
94 }
95
96 // define straight lines (a1 x + b1 y = c1) and (a2 x + b2 y = c2) through line points
97 const double a1 = line1[1].y() - line1[0].y();
98 const double b1 = line1[0].x() - line1[1].x();
99 const double c1 = line1[0].x() * line1[1].y() - line1[1].x() * line1[0].y();
100 const double a2 = line2[1].y() - line2[0].y();
101 const double b2 = line2[0].x() - line2[1].x();
102 const double c2 = line2[0].x() * line2[1].y() - line2[1].x() * line2[0].y();
103
104 // find intersection of both lines by solving for x and y
105 const double det = a1 * b2 - a2 * b1;
106 if (det != 0) {
107 const double x = (b2 * c1 - b1 * c2) / det;
108 const double y = (a1 * c2 - a2 * c1) / det;
109 result.intersection = Eigen::Vector2d(x, y);
110
111 // check if intersection point is within line segments
112 result.intersects_line1 = (x >= std::min(line1[0].x(), line1[1].x()) && x <= std::max(line1[0].x(), line1[1].x()) &&
113 y >= std::min(line1[0].y(), line1[1].y()) && y <= std::max(line1[0].y(), line1[1].y()));
114 result.intersects_line2 = (x >= std::min(line2[0].x(), line2[1].x()) && x <= std::max(line2[0].x(), line2[1].x()) &&
115 y >= std::min(line2[0].y(), line2[1].y()) && y <= std::max(line2[0].y(), line2[1].y()));
116 } else {
117 return std::nullopt;
118 }
119
120 return result;
121}
Return type of intersectionOfLines.
Definition geometry.hpp:35
bool intersects_line2
whether intersection is on second line segment
Definition geometry.hpp:38
bool intersects_line1
whether intersection is on first line segment
Definition geometry.hpp:37
Eigen::Vector2d intersection
intersection point
Definition geometry.hpp:36

◆ isLineStringDrivable()

bool lanelet2_route_planning::isLineStringDrivable ( const lanelet::ConstLineString3d & line_string)

Checks if lanelet line string has a type that is considered drivable.

Drivable in the sense of being able to physically cross it, not whether it is allowed to cross it.

The following types are considered drivable:

  • arrow
  • bike_marking
  • centerline
  • curbstone (only if subtype is 'low')
  • lane_center
  • line_thick
  • line_thin
  • pedestrian_marking
  • roadpainting
  • stop_line
  • traffic_light
  • virtual
  • zebra_marking

Additionally, the extra attribute 'HoldingLine' is considered drivable.

Parameters
[in]line_stringline string
Returns
whether line string is drivable

Definition at line 461 of file utils.cpp.

461 {
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",
465 "zebra_marking"};
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") {
471 return false;
472 }
473 }
474 return true;
475 }
476 return line_string.hasAttribute("HoldingLine");
477 }
478 return false;
479}

◆ laneBoundaryType()

uint8_t lanelet2_route_planning::laneBoundaryType ( const lanelet::ConstLineString2d & line)

Extracts the lane boundary type of a lanelet line.

Lane boundary type as in route_planning_msgs::msg::LaneBoundary.

Parameters
[in]linelanelet line
Returns
lane boundary type

Definition at line 666 of file utils.cpp.

666 {
667 uint8_t lane_boundary_type = route_planning_msgs::msg::LaneBoundary::TYPE_UNKNOWN;
668
669 // get type attribute
670 lanelet::Attribute type;
671 if (line.hasAttribute("type")) {
672 type = line.attribute("type");
673 } else {
674 lane_boundary_type = route_planning_msgs::msg::LaneBoundary::TYPE_UNKNOWN;
675 return lane_boundary_type;
676 }
677
678 // map lanelet type to 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;
693 }
694 }
695 } else if (type == "virtual") {
696 lane_boundary_type = route_planning_msgs::msg::LaneBoundary::TYPE_UNKNOWN;
697 } else {
698 lane_boundary_type = route_planning_msgs::msg::LaneBoundary::TYPE_UNKNOWN;
699 }
700
701 return lane_boundary_type;
702}

◆ laneletAtPoint()

std::optional< lanelet::ConstLanelet > lanelet2_route_planning::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.

Finds closest passable lanelet within 10m of the given point. Only considers the 5 closest lanelets.

Parameters
[in]pointpoint
[in]mapmap
[in]traffic_rulestraffic rules
Returns
matching lanelet

Definition at line 885 of file utils.cpp.

887 {
888 // parameters for lanelet matching
889 const unsigned int number_of_nearest_lanelets = 5;
890 const double max_lanelet_matching_distance = 5.0;
891
892 // find nearest lanelets
893 std::vector<std::pair<double, lanelet::ConstLanelet>> nearest_lanelets =
894 lanelet::geometry::findNearest(map->laneletLayer, point, number_of_nearest_lanelets);
895
896 // find best matching lanelet
897 if (traffic_rules) {
898 sortLaneletsByMatchingCost(point, nearest_lanelets, traffic_rules);
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;
902 }
903 }
904 } else if (!nearest_lanelets.empty()) {
905 sortLaneletsByMatchingCost(point, nearest_lanelets);
906 if (nearest_lanelets[0].first <= max_lanelet_matching_distance) {
907 return nearest_lanelets[0].second;
908 }
909 }
910
911 return std::nullopt;
912}
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.
Definition utils.cpp:1132

◆ matchPointToLineString()

size_t lanelet2_route_planning::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.

The purpose of this function is not to find the globally closest point, but the locally closest one. By locally, what is meant is that points closer in order to idx_indication are preferred over points that may actually be closer in distance.

The range of points 10m before and after idx_indication is considered. A maximum distance of 10m is used to match to this range of points, otherwise globally closer ones are preferred.

If consider_order, then only the points behind or ahead of the projection of the given point are considered.

Parameters
[in]line_stringline string
[in]pointother point
[in]idx_indicationindex of point in line string to indicate the range of points to be considered
[in]consider_orderwhether to consider the order of points in the line string
[in]behindwhether to consider points behind (or ahead of) the given point
Returns
index of locally closest point

Definition at line 94 of file utils.cpp.

98 {
99 if (line_string.empty()) {
100 return 0;
101 }
102
103 // constants
104 const double max_delta_s = 10.0;
105 const double max_local_distance = 10.0;
106
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);
110
111 // loop over points in front of and behind the given index
112 for (int direction : {1, -1}) {
113 double delta_s = 0.0;
114 size_t idx = start_idx;
115 // only check points within the local range of max_delta_s
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;
120 idx_closest = idx;
121 }
122 if (direction == 1) {
123 if (idx + 1 >= line_string.size()) break;
124 delta_s += (line_string[idx + 1] - line_string[idx]).norm();
125 } else {
126 if (idx == 0) break;
127 delta_s += (line_string[idx] - line_string[idx - 1]).norm();
128 }
129 idx += direction;
130 }
131 }
132
133 // check if closest local point is within max distance, else find globally closest point
134 if (min_distance > max_local_distance) {
135 idx_closest = indexOfLineStringPointClosestToPoint(line_string, point, consider_order, behind);
136 } else if (consider_order) {
137 // if considering order, make sure to return the point behind or ahead of the given point
138 idx_closest = considerOrderForPointMatchedToLineString(line_string, point, idx_closest, behind);
139 }
140
141 return idx_closest;
142}
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.
Definition utils.cpp:67

◆ normalOfPointAlongLineString()

Eigen::Vector2d lanelet2_route_planning::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.

The normal is normal to the tangent, see tangentOfPointAlongLineString.

Parameters
[in]pointpoint along line string
[in]prev_pointprevious point along line string
[in]next_pointnext point along line string
Returns
unit normal vector

Definition at line 143 of file geometry.cpp.

145 {
146 Eigen::Vector2d tangent = tangentOfPointAlongLineString(point, prev_point, next_point);
147 Eigen::Vector2d normal = Eigen::Vector2d(tangent.y(), -tangent.x());
148
149 return normal;
150}

◆ postprocessRouteMessage()

void lanelet2_route_planning::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 contents.

This includes:

  • orientation of each lane element's reference pose based on preceding and following points
  • propagation of suggested turn signals backwards along the route based on distance ahead information
Parameters
[in,out]route_msgroute message to postprocess
[in]suggested_turn_signal_distance_ahead_by_route_element_by_lane_elementsuggested turn signal distances ahead by route element and lane element indices

Definition at line 1031 of file utils.cpp.

1033 {
1034 // loop over route elements to set orientations and following lane indices
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) {
1037 // get current, previous and next route element
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;
1041
1042 // fix following lane index at the last non-enriched route element before route elements are enriched
1043 if (r > 0) {
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;
1047 }
1048 }
1049
1050 // loop over lane elements of current route element
1051 for (size_t l = 0; l < route_element.lane_elements.size(); ++l) {
1052 // get current, previous and next lane element
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);
1057
1058 // find current, previous and next points to compute orientation
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)
1063 ? point
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)
1066 ? point
1067 : toEigen2d(next_lane_element_opt->reference_pose.position);
1068
1069 // compute orientation of current point
1070 const auto orientation = tangentOfPointAlongLineString(point, prev_point_for_orientation, next_point_for_orientation);
1071 lane_element.reference_pose.orientation = toRosQuaternion(orientation);
1072 }
1073 }
1074
1075 // loop over route elements in reverse to propagate suggested turn signals backwards
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; // only handle turn signal information for enriched route elements
1079
1080 // loop over lane elements of current route element
1081 for (size_t l = 0; l < route_element.lane_elements.size(); ++l) {
1082 auto& lane_element = route_element.lane_elements[l];
1083
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];
1086
1087 // get preceding lane element
1088 if (r <= 0) break;
1089 int curr_r = r;
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);
1093
1094 // iterate over preceding lane elements within suggested distance to set suggested turn signal
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; // only propagate through enriched route elements
1098
1099 // stop if preceding lane element has its own suggested turn signal information
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) {
1104 break;
1105 }
1106 }
1107
1108 // check distance to preceding lane element
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) {
1113 break; // stop if distance to preceding point exceeds remaining distance ahead
1114 }
1115
1116 // set suggested turn signal of preceding lane element
1117 prev_lane_element.suggested_turn_signal = lane_element.suggested_turn_signal;
1118
1119 // update remaining distance and move to next preceding lane element
1120 suggested_turn_signal_distance_ahead -= static_cast<uint8_t>(std::round(distance_to_prev_point));
1121 curr_r -= 1;
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);
1127 }
1128 }
1129 }
1130}
geometry_msgs::msg::Quaternion toRosQuaternion(const Eigen::Vector2d &vector)
Converts a 2D Eigen vector pointing in a specific direction to a ROS quaternion.

◆ projectPointToLaneletLines()

std::vector< ProjectedLaneletPoints > lanelet2_route_planning::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.

For projection, projectPointToLineStringAlongNormal is used.

Parameters
[in]pointpoint
[in]prev_pointprevious point
[in]next_pointnext point
[in]laneletslanelets
[in]loggerlogger (for error logging)
Returns
projected points

Definition at line 208 of file utils.cpp.

212 {
213 std::vector<ProjectedLaneletPoints> projected_points_per_lanelet;
214
215 // loop over lanelets
216 for (const auto& lanelet : lanelets) {
217 ProjectedLaneletPoints projected_points;
218
219 // project point to left bounds
220 if (auto result = projectPointToLineStringAlongNormal(point, prev_point, next_point,
221 toEigen(lanelet.leftBound2d().basicLineString()))) {
222 projected_points.left_bound_point = result->projected_point;
223 } else {
224 RCLCPP_WARN(logger, "Failed to project point (%.3f, %.3f) to left bounds of lanelet %ld", point.x(), point.y(),
225 lanelet.id());
226 }
227
228 // project point to centerline
229 if (auto result = projectPointToLineStringAlongNormal(point, prev_point, next_point,
230 toEigen(lanelet.centerline2d().basicLineString()))) {
231 projected_points.centerline_point = result->projected_point;
232 } else {
233 RCLCPP_WARN(logger, "Failed to project point (%.3f, %.3f) to centerline of lanelet %ld", point.x(), point.y(),
234 lanelet.id());
235 }
236
237 // project point to right bounds
238 if (auto result = projectPointToLineStringAlongNormal(point, prev_point, next_point,
239 toEigen(lanelet.rightBound2d().basicLineString()))) {
240 projected_points.right_bound_point = result->projected_point;
241 } else {
242 RCLCPP_WARN(logger, "Failed to project point (%.3f, %.3f) to right bounds of lanelet %ld", point.x(), point.y(),
243 lanelet.id());
244 }
245
246 projected_points_per_lanelet.push_back(projected_points);
247 }
248
249 return projected_points_per_lanelet;
250}
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 ...
Definition geometry.cpp:279
Eigen::Vector2d centerline_point
projected centerline point
Definition utils.hpp:150
Eigen::Vector2d right_bound_point
projected right bound point
Definition utils.hpp:151
Eigen::Vector2d left_bound_point
projected left bound point
Definition utils.hpp:149

◆ projectPointToLineString() [1/2]

Eigen::Vector2d lanelet2_route_planning::projectPointToLineString ( const Eigen::Vector2d & point,
const std::vector< Eigen::Vector2d > & line_string )

Projects a point to the closest line segment of a line string.

Parameters
[in]pointpoint
[in]line_stringline string
Returns
projected point

Definition at line 231 of file geometry.cpp.

231 {
232 return lanelet::geometry::project(toLanelet(line_string), toLanelet(point));
233}
lanelet::BasicPoint2d toLanelet(const Eigen::Vector2d &point)
Converts a 2D Eigen point to a Lanelet point.

◆ projectPointToLineString() [2/2]

Eigen::Vector3d lanelet2_route_planning::projectPointToLineString ( const Eigen::Vector3d & point,
const std::vector< Eigen::Vector3d > & line_string )

Projects a 3D point to the closest line segment of a 3D line string.

Parameters
[in]pointpoint
[in]line_stringline string
Returns
projected point

Definition at line 235 of file geometry.cpp.

235 {
236 return lanelet::geometry::project(toLanelet(line_string), toLanelet(point));
237}

◆ projectPointToLineStringAlongAxis()

std::optional< ProjectPointToLineStringAlongAxisResult > lanelet2_route_planning::projectPointToLineStringAlongAxis ( const Eigen::Vector2d & point,
const Eigen::Vector2d & axis,
const std::vector< Eigen::Vector2d > & line_string )

Projects a point along an axis to the closest line segment of a line string.

Parameters
[in]pointpoint
[in]axisaxis direction
[in]line_stringline string
Returns
projected point and whether intersection is on line segment

Definition at line 239 of file geometry.cpp.

240 {
243 double closest_distance_to_line_segment = std::numeric_limits<double>::max();
244 bool found_at_least_one_intersection = false;
245
246 // define straight line along axis at point
247 std::vector<Eigen::Vector2d> axis_line = {point, point + axis};
248
249 // loop over line segments
250 for (size_t i = 0; i < line_string.size() - 1; ++i) {
251 std::vector<Eigen::Vector2d> line_segment = {line_string[i], line_string[i + 1]};
252
253 // find intersection of axis line and line segment
254 if (auto inner_result = intersectionOfLines(axis_line, line_segment)) {
255 const Eigen::Vector2d& intersection = inner_result->intersection;
256 const bool intersects_line_segment = inner_result->intersects_line2;
257 found_at_least_one_intersection = true;
258 if (intersects_line_segment) {
260 result.projected_point = intersection;
261 break;
262 }
263 double distance_to_line_segment =
264 std::min((intersection - line_string[i]).norm(), (intersection - line_string[i + 1]).norm());
265 if (distance_to_line_segment < closest_distance_to_line_segment) {
266 closest_distance_to_line_segment = distance_to_line_segment;
267 result.projected_point = intersection;
268 }
269 }
270 }
271
272 if (!found_at_least_one_intersection) {
273 return std::nullopt;
274 }
275
276 return result;
277}
Return type of projectPointToLineStringAlongAxis.
Definition geometry.hpp:133
bool found_intersection_with_line_segment
whether intersection is on line segment
Definition geometry.hpp:135

◆ projectPointToLineStringAlongNormal()

std::optional< ProjectPointToLineStringAlongAxisResult > lanelet2_route_planning::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 point.

Parameters
[in]pointpoint along line string
[in]prev_pointprevious point along line string
[in]next_pointnext point along line string
[in]line_stringother line string to project to
Returns
projected point and whether intersection is on line segment

Definition at line 279 of file geometry.cpp.

283 {
284 // find normal to tangent at point
285 Eigen::Vector2d normal = normalOfPointAlongLineString(point, prev_point, next_point);
286 if (normal == Eigen::Vector2d(0.0, 0.0)) {
287 return std::nullopt;
288 }
289
290 // project current point to other line along normal to tangent
291 if (auto result = projectPointToLineStringAlongAxis(point, normal, line_string)) {
292 return result;
293 }
294 return std::nullopt;
295}

◆ regulatoryElementCancelLine()

std::optional< std::array< geometry_msgs::msg::Point, 2 > > lanelet2_route_planning::regulatoryElementCancelLine ( const std::shared_ptr< const lanelet::RegulatoryElement > & regulatory_element)

Extracts the cancel line of a regulatory element.

Only the first cancel line of the regulatory element is considered. Only the end points of that cancel line are considered.

Parameters
[in]regulatory_elementregulatory element
Returns
cancel line

Definition at line 574 of file utils.cpp.

575 {
576 const std::vector<lanelet::ConstLineString3d> cancel_lines =
577 regulatory_element->getParameters<lanelet::ConstLineString3d>(lanelet::RoleName::CancelLine);
578 if (cancel_lines.empty()) {
579 return std::nullopt;
580 }
581 const std::vector<Eigen::Vector3d> cancel_line = cancel_lines.front().basicLineString();
582 if (cancel_line.size() < 2) {
583 return std::nullopt;
584 }
585 std::array<geometry_msgs::msg::Point, 2> cancel_line_ros = {toRos(cancel_line.front()), toRos(cancel_line.back())};
586 return cancel_line_ros;
587}
geometry_msgs::msg::Point toRos(const Eigen::Vector2d &point)
Converts a 2D Eigen point to a ROS point.

◆ regulatoryElementPositions()

std::vector< geometry_msgs::msg::Point > lanelet2_route_planning::regulatoryElementPositions ( const std::shared_ptr< const lanelet::RegulatoryElement > & regulatory_element)

Extracts the sign/signal positions of a regulatory element.

Only the first point of referenced line strings is considered.

Parameters
[in]regulatory_elementregulatory element
Returns
positions

Definition at line 589 of file utils.cpp.

590 {
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()));
598 }
599 }
600 return positions;
601}

◆ regulatoryElementReferenceLine()

std::optional< std::array< geometry_msgs::msg::Point, 2 > > lanelet2_route_planning::regulatoryElementReferenceLine ( const std::shared_ptr< const lanelet::RegulatoryElement > & regulatory_element)

Extracts the reference/effect line of a regulatory element.

Only the first reference line of the regulatory element is considered. Only the end points of that reference line are considered.

Parameters
[in]regulatory_elementregulatory element
Returns
reference line

Definition at line 559 of file utils.cpp.

560 {
561 const std::vector<lanelet::ConstLineString3d> reference_lines =
562 regulatory_element->getParameters<lanelet::ConstLineString3d>(lanelet::RoleName::RefLine);
563 if (reference_lines.empty()) {
564 return std::nullopt;
565 }
566 const std::vector<Eigen::Vector3d> reference_line = reference_lines.front().basicLineString();
567 if (reference_line.size() < 2) {
568 return std::nullopt;
569 }
570 std::array<geometry_msgs::msg::Point, 2> reference_line_ros = {toRos(reference_line.front()), toRos(reference_line.back())};
571 return reference_line_ros;
572}

◆ regulatoryElementSpeedLimit()

uint8_t lanelet2_route_planning::regulatoryElementSpeedLimit ( const std::shared_ptr< const lanelet::RegulatoryElement > & regulatory_element)

Extracts the speed limit of a regulatory element of subtype 'speed_limit'.

As defined in route_planning_msgs::msg::RegulatoryElement.

Parameters
[in]regulatory_elementregulatory element
Returns
speed limit [km/h]

Definition at line 631 of file utils.cpp.

631 {
632 uint8_t speed_limit = route_planning_msgs::msg::RegulatoryElement::META_VALUE_SPEED_UNKNOWN;
633
634 // https://github.com/fzi-forschungszentrum-informatik/Lanelet2/blob/master/lanelet2_core/doc/RegulatoryElementTagging.md#speed-limit
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();
640 std::smatch match;
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); // mph to km/h
646 } else if (match.str(2) == "mps") {
647 speed = static_cast<int>(speed * 3.6); // mps to km/h
648 }
649 speed_limit = static_cast<uint8_t>(speed);
650 } else {
651 std::regex regex("(\\d+)"); // assume km/h if no unit is specified
652 if (std::regex_search(sign_type, match, regex)) {
653 speed_limit = static_cast<uint8_t>(std::stoi(match.str(1)));
654 }
655 }
656 }
657 }
658 }
659
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);
662
663 return speed_limit;
664}

◆ regulatoryElementType()

std::pair< uint8_t, uint8_t > lanelet2_route_planning::regulatoryElementType ( const std::shared_ptr< const lanelet::RegulatoryElement > & regulatory_element)

Extracts the type and meta value of a regulatory element.

https://github.com/fzi-forschungszentrum-informatik/Lanelet2/blob/master/lanelet2_core/doc/RegulatoryElementTagging.md

Type and meta value as in route_planning_msgs::msg::RegulatoryElement.

Parameters
[in]regulatory_elementregulatory element
Returns
type and meta value

Definition at line 603 of file utils.cpp.

603 {
604 uint8_t type = route_planning_msgs::msg::RegulatoryElement::TYPE_UNKNOWN;
605 uint8_t meta_value = 0;
606
607 // https://github.com/fzi-forschungszentrum-informatik/Lanelet2/blob/master/lanelet2_core/doc/RegulatoryElementTagging.md
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;
614 meta_value = regulatoryElementSpeedLimit(regulatory_element);
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";
620 });
621 if (has_stop_sign) {
622 type = route_planning_msgs::msg::RegulatoryElement::TYPE_STOP;
623 }
624 } else if (subtype == "all_way_stop") {
625 type = route_planning_msgs::msg::RegulatoryElement::TYPE_STOP;
626 }
627 }
628 return {type, meta_value};
629}

◆ resampleCenterlinesAlongPath()

ResampleCenterlinesAlongPathResult lanelet2_route_planning::resampleCenterlinesAlongPath ( const lanelet::routing::LaneletPath & path,
const double delta_s,
bool monotonically )

Equidistantly resamples lanelet centerlines along a path to one joint centerline.

Parameters
[in]pathpath
[in]delta_ssampling distance
[in]monotonicallywhether to ensure that the centerline cannot make turns greater than 90 degrees
Returns
resampled centerline and lanelet index by point

Definition at line 946 of file utils.cpp.

948 {
949 // init variables
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);
954
955 // loop over lanelets in path
956 for (size_t l = 0; l < path.size(); ++l) {
957 // get centerline
958 const lanelet::ConstLanelet& lanelet = path[l];
959 lanelet::BasicLineString3d centerline = lanelet.centerline().basicLineString();
960
961 // skip point if behind previous sampled point, e.g., if on adjacent lanelet in shortest path due to lane change
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) { // angle > 90deg
966 cit = centerline.erase(cit);
967 } else {
968 break;
969 }
970 }
971 }
972
973 // resample lanelet centerline
974 std::vector<Eigen::Vector3d> resampled_centerline = resampleLineString(toEigen(centerline), delta_s, resampling_offset);
975 result.centerline.insert(result.centerline.end(), resampled_centerline.begin(), resampled_centerline.end());
976 result.lanelet_idx_by_point.insert(result.lanelet_idx_by_point.end(), resampled_centerline.size(), l);
977
978 // update information for monotonicity check
979 if (monotonically && !resampled_centerline.empty()) {
980 if (resampled_centerline.size() > 1) {
981 prev_sampled_point = to2d(resampled_centerline[resampled_centerline.size() - 2]);
982 }
983 const Eigen::Vector2d current_sampled_point = to2d(resampled_centerline.back());
984 prev_sampled_point_orientation =
985 tangentOfPointAlongLineString(current_sampled_point, prev_sampled_point, current_sampled_point);
986 prev_sampled_point = current_sampled_point;
987 }
988 }
989
990 return result;
991}
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.
Definition geometry.cpp:152
Return type of resampleCenterlinesAlongPath.
Definition utils.hpp:469
std::vector< Eigen::Vector3d > centerline
resampled centerline
Definition utils.hpp:470
std::vector< size_t > lanelet_idx_by_point
lanelet index in path for each point
Definition utils.hpp:471

◆ resampleLineString()

std::vector< Eigen::Vector3d > lanelet2_route_planning::resampleLineString ( const std::vector< Eigen::Vector3d > & line_string,
const double delta,
double & offset )

Resamples a 3D line string with a constant sampling distance.

Sampling distance is measured in the xy-plane; z is interpolated.

Parameters
[in]lineline string
[in]deltasampling distance
[in,out]offsetstarts sampling at offset distance, returns overshoot distance
Returns
resampled line string

Definition at line 152 of file geometry.cpp.

154 {
155 std::vector<Eigen::Vector3d> resampled_line_string;
156
157 // set initial sampling distance
158 double sampling_distance = delta;
159 if (offset == 0.0) { // if no offset, start with first line point
160 resampled_line_string.push_back(line_string.front());
161 } else { // else sample first point with offset != delta
162 sampling_distance = offset;
163 }
164
165 // loop over all line segments
166 for (size_t i = 1; i < line_string.size(); ++i) {
167 // determine 2D segment length and 3D direction
168 double segment_length = (to2d(line_string[i]) - to2d(line_string[i - 1])).norm();
169 const Eigen::Vector3d segment_direction = (line_string[i] - line_string[i - 1]) / segment_length;
170
171 // sample points along segment, increasing sampling_distance by delta
172 while (segment_length >= sampling_distance) {
173 const Eigen::Vector3d resampled_point = line_string[i - 1] + sampling_distance * segment_direction;
174 resampled_line_string.push_back(resampled_point);
175 sampling_distance += delta;
176 }
177
178 // reset sampling_distance for next segment, including overshoot
179 sampling_distance = sampling_distance - segment_length;
180 }
181
182 // save overshoot in outgoing offset parameter
183 offset = sampling_distance;
184
185 return resampled_line_string;
186}

◆ sortLaneletsByMatchingCost()

void lanelet2_route_planning::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.

Points inside a lanelet are favored, lateral distance is penalized quadratically, and non-passable lanelets receive an additional penalty if traffic rules are available.

Derived simplified implementation from deprecated lanelet2_utilties package.

Parameters
[in]pointpoint to match
[in,out]lanelets_with_distancescandidate lanelets from lanelet::geometry::findNearest
[in]traffic_rulesoptional traffic rules used to penalize non-passable lanelets

Definition at line 1132 of file utils.cpp.

1134 {
1135 struct LaneletMatchingCost {
1136 std::pair<double, lanelet::ConstLanelet> lanelet_with_distance;
1137 double cost;
1138 };
1139
1140 std::vector<LaneletMatchingCost> lanelet_matching_costs;
1141 lanelet_matching_costs.reserve(lanelets_with_distances.size());
1142
1143 // compute the matching cost for each candidate lanelet
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);
1148
1149 // favor lanelets containing the point and penalize lateral distance quadratically
1150 double cost = (point_is_inside_lanelet ? 0.5 : 2.0) * arc_coordinates.distance * arc_coordinates.distance;
1151
1152 // keep non-passable lanelets as fallback candidates, but rank them lower
1153 if (traffic_rules && !traffic_rules.value()->canPass(lanelet)) {
1154 cost *= 2.0;
1155 }
1156
1157 lanelet_matching_costs.push_back({lanelet_with_distance, cost});
1158 }
1159
1160 // apply the sorted order to the original lanelet-distance pairs
1161 std::sort(lanelet_matching_costs.begin(), lanelet_matching_costs.end(),
1162 [](const LaneletMatchingCost& lhs, const LaneletMatchingCost& rhs) { return lhs.cost < rhs.cost; });
1163
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;
1166 }
1167}

◆ speedLimit() [1/2]

uint8_t lanelet2_route_planning::speedLimit ( const lanelet::ConstLanelet & lanelet,
const bool consider_regulatory_elements = true )

Extracts the speed limit of a lanelet.

Uses lanelet traffic rules to determine the speed limit for the whole lanelet.

If consider_regulatory_elements is true, speed-limit regulatory elements attached to the lanelet may override the lanelet-wide speed limit according to lanelet traffic rules. If consider_regulatory_elements is false, only the lanelet's own speed_limit and speed_limit_mandatory attributes are considered.

As defined in route_planning_msgs::msg::RegulatoryElement.

Parameters
[in]laneletlanelet
[in]consider_regulatory_elementswhether to consider regulatory elements related to the lanelet
Returns
speed limit [km/h]

Definition at line 704 of file utils.cpp.

704 {
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);
709 } else {
710 uint8_t unlimited = route_planning_msgs::msg::RegulatoryElement::META_VALUE_SPEED_UNLIMITED;
711 if (!lanelet.hasAttribute(lanelet::AttributeName::SpeedLimit)) {
712 return unlimited;
713 }
714 auto speed_limit = lanelet.attribute(lanelet::AttributeName::SpeedLimit).asVelocity();
715 if (!speed_limit) {
716 return unlimited;
717 }
718 bool is_mandatory = true;
719 const std::string speed_limit_mandatory_attribute =
720 lanelet::AttributeNamesString::SpeedLimitMandatory; // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
721 if (lanelet.hasAttribute(speed_limit_mandatory_attribute)) {
722 is_mandatory = lanelet.attribute(speed_limit_mandatory_attribute).value() != std::string("no");
723 }
724 speed_limit_info = lanelet::traffic_rules::SpeedLimitInformation{*speed_limit, is_mandatory};
725 }
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);
731 }
732 return unlimited;
733}
lanelet::traffic_rules::TrafficRulesPtr getTrafficRules()
Get traffic rules.
Definition utils.cpp:879

◆ speedLimit() [2/2]

uint8_t lanelet2_route_planning::speedLimit ( const lanelet::ConstLanelet & lanelet,
const Eigen::Vector2d & point )

Extracts the speed limit of a lanelet at a specific position on that lanelet.

Speed-limit regulatory elements take precedence over the lanelet-wide speed limit, but only once the given point is behind the regulatory element's reference line and, if present, still before its cancel line.

If no applicable speed-limit regulatory element is active at the given point, this falls back to the lanelet-wide speed limit. If the point is still before an intersecting reference line, the fallback ignores regulatory elements and uses only the lanelet's own speed-limit attributes.

This implementation considers only the first reference line and first cancel line of a speed-limit regulatory element, using their end points.

As defined in route_planning_msgs::msg::RegulatoryElement.

Parameters
[in]laneletlanelet
[in]pointpoint on or near the lanelet
Returns
speed limit [km/h]

Definition at line 735 of file utils.cpp.

735 {
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;
742
743 // loop over regulatory elements of lanelet
744 const auto regulatory_elements = lanelet.regulatoryElements();
745 for (const auto& regulatory_element : regulatory_elements) {
746 // extract type and meta value, skip non-speed-limit 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) {
751 continue;
752 }
753
754 // extract reference line
755 if (auto reference_line = regulatoryElementReferenceLine(regulatory_element)) {
756 std::vector<Eigen::Vector2d> reference_line_2d = {toEigen2d(reference_line->at(0)), toEigen2d(reference_line->at(1))};
757
758 // check if reference line intersects lanelet centerline
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]};
763 if (auto result = intersectionOfLines(reference_line_2d, centerline_segment)) {
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;
768 break;
769 }
770 }
771 }
772
773 // check if cancel line intersects lanelet centerline
774 bool cancel_line_intersects_centerline = false;
775 double cancel_arc_length = 0.0;
776 if (auto cancel_line = regulatoryElementCancelLine(regulatory_element)) {
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]};
780 if (auto result = intersectionOfLines(cancel_line_2d, centerline_segment)) {
781 if (result->intersects_line1 && result->intersects_line2) {
782 cancel_arc_length =
783 lanelet::geometry::toArcCoordinates(lanelet.centerline2d(), toLanelet(result->intersection)).length;
784 cancel_line_intersects_centerline = true;
785 break;
786 }
787 }
788 }
789 }
790
791 // if given point is behind reference line and before cancel line, use speed limit of regulatory element
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;
797 }
798 if (!point_is_before_cancel_line) {
799 found_past_cancel_line = true;
800 }
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) {
803 // only update speed limit if regulatory element is ahead of previously found regulatory element
804 // (in case of multiple speed limit regulatory elements on lanelet)
805 speed_limit = regulatory_element_meta_value;
806 best_reference_arc_length = reference_arc_length;
807 found_valid_regulatory_element_speed_limit = true;
808 }
809 }
810
811 } else {
812 continue;
813 }
814 }
815
816 // if no valid regulatory element speed limit is found, fall back to lanelet speed limit;
817 // that function will still yield regulatory-element-based speed limits, if related to the lanelet
818 // even though there are no intersecting reference lines
819 if (!found_valid_regulatory_element_speed_limit) {
820 if (found_future_reference_line || found_past_cancel_line) {
821 speed_limit = speedLimit(lanelet, false);
822 } else {
823 speed_limit = speedLimit(lanelet, true);
824 }
825 }
826
827 speed_limit =
828 std::clamp(speed_limit, static_cast<uint8_t>(0), route_planning_msgs::msg::RegulatoryElement::META_VALUE_SPEED_UNLIMITED);
829
830 return speed_limit;
831}
uint8_t speedLimit(const lanelet::ConstLanelet &lanelet, const bool consider_regulatory_elements=true)
Extracts the speed limit of a lanelet.
Definition utils.cpp:704
std::optional< std::array< geometry_msgs::msg::Point, 2 > > regulatoryElementCancelLine(const std::shared_ptr< const lanelet::RegulatoryElement > &regulatory_element)
Extracts the cancel line of a regulatory element.
Definition utils.cpp:574

◆ suggestedReferenceLineToEigen()

std::vector< Eigen::Vector3d > lanelet2_route_planning::suggestedReferenceLineToEigen ( const std::vector< route_planning_msgs::msg::RouteElement > & route_elements)

Extracts the reference line along the suggested lane from a list of RouteElements.

Parameters
[in]route_elementslist of RouteElements
Returns
reference line

Definition at line 97 of file conversions.cpp.

98 {
99 std::vector<Eigen::Vector3d> reference_line;
100 for (const auto& route_element : route_elements) {
101 const auto& lane_element = route_planning_msgs::route_access::getSuggestedLaneElement(route_element);
102 reference_line.push_back(toEigen(lane_element.reference_pose.position));
103 }
104 return reference_line;
105}

◆ suggestedTurnSignal()

std::tuple< uint8_t, int > lanelet2_route_planning::suggestedTurnSignal ( const lanelet::ConstLanelet & lanelet,
const rclcpp::Logger & logger )

Extracts the suggested turn signal of a lanelet.

Checks for the attribute suggested_turn_signal with values left, right, or hazard. Checks for the attribute suggested_turn_signal_distance_ahead to get the suggested distance ahead for the turn signal.

Parameters
[in]laneletlanelet
[in]loggerlogger (for error logging)
Returns
suggested turn signal and distance ahead

Definition at line 833 of file utils.cpp.

833 {
834 uint8_t suggested_turn_signal = route_planning_msgs::msg::LaneElement::SUGGESTED_TURN_SIGNAL_NONE;
835 int suggested_turn_signal_distance_ahead = -1;
836
837 // parse suggested turn signal attribute
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;
846 } else {
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);
851 }
852
853 // parse suggested turn signal distance ahead attribute
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();
856 try {
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);
862 }
863 if (suggested_turn_signal_distance_ahead < 0) {
864 RCLCPP_ERROR(logger,
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;
868 }
869 } else {
870 RCLCPP_ERROR(logger,
871 "Lanelet '%ld' has 'suggested_turn_signal' attribute but no 'suggested_turn_signal_distance_ahead', ignoring "
872 "suggested turn signal",
873 lanelet.id());
874 }
875 }
876 return std::make_tuple(suggested_turn_signal, suggested_turn_signal_distance_ahead);
877}

◆ tangentOfPointAlongLineString()

Eigen::Vector2d lanelet2_route_planning::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.

The tangent is pointing in the average direction of previous to current and current to next point directions.

If two points are equal, the tangent is pointing in the direction from/to the third. If three points are equal, the tangent is undefined and returns (0,0).

Parameters
[in]pointpoint along line string
[in]prev_pointprevious point along line string
[in]next_pointnext point along line string
Returns
unit tangential vector

Definition at line 123 of file geometry.cpp.

125 {
126 Eigen::Vector2d tangent;
127
128 if (point == prev_point && point != next_point) { // single line segment
129 tangent = (next_point - point).normalized();
130 } else if (point != prev_point && point == next_point) { // single line segment
131 tangent = (point - prev_point).normalized();
132 } else if (point == prev_point && point == next_point) { // single point
133 tangent = Eigen::Vector2d(0.0, 0.0);
134 } else { // proper two line segments with previous and next point
135 const Eigen::Vector2d prev_to_point_unit = (point - prev_point).normalized();
136 const Eigen::Vector2d point_to_next_unit = (next_point - point).normalized();
137 tangent = (prev_to_point_unit + point_to_next_unit).normalized();
138 }
139
140 return tangent;
141}

◆ to2d() [1/2]

Eigen::Vector2d lanelet2_route_planning::to2d ( const Eigen::Vector3d & point)

Converts a 3D Eigen point to a 2D Eigen point.

Removes the z-coordinate.

Parameters
[in]pointpoint
Returns
converted point

Definition at line 11 of file conversions.cpp.

11{ return point.head<2>(); }

◆ to2d() [2/2]

std::vector< Eigen::Vector2d > lanelet2_route_planning::to2d ( const std::vector< Eigen::Vector3d > & points)

Converts a vector of 3D Eigen points to a vector of 2D Eigen points.

Removes the z-coordinate.

Parameters
[in]pointspoints
Returns
converted points

Definition at line 17 of file conversions.cpp.

17 {
18 std::vector<Eigen::Vector2d> points_2d;
19 for (const auto& point : points) {
20 points_2d.push_back(to2d(point));
21 }
22 return points_2d;
23}

◆ to3d() [1/3]

Eigen::Vector3d lanelet2_route_planning::to3d ( const Eigen::Vector2d & point)

Converts a 2D Eigen point to a 3D Eigen point.

Adds a z-coordinate of 0.

Parameters
[in]pointpoint
Returns
converted point

Definition at line 13 of file conversions.cpp.

13{ return Eigen::Vector3d(point.x(), point.y(), 0.0); }

◆ to3d() [2/3]

Eigen::Vector3d lanelet2_route_planning::to3d ( const Eigen::Vector2d & point,
double z )

Converts a 2D Eigen point to a 3D Eigen point.

Adds the given z-coordinate.

Parameters
[in]pointpoint
[in]zz-coordinate
Returns
converted point

Definition at line 15 of file conversions.cpp.

15{ return Eigen::Vector3d(point.x(), point.y(), z); }

◆ to3d() [3/3]

std::vector< Eigen::Vector3d > lanelet2_route_planning::to3d ( const std::vector< Eigen::Vector2d > & points)

Converts a vector of 2D Eigen points to a vector of 3D Eigen points.

Adds a z-coordinate of 0.

Parameters
[in]pointspoints
Returns
converted points

Definition at line 25 of file conversions.cpp.

25 {
26 std::vector<Eigen::Vector3d> points_3d;
27 for (const auto& point : points) {
28 points_3d.push_back(to3d(point));
29 }
30 return points_3d;
31}
Eigen::Vector3d to3d(const Eigen::Vector2d &point)
Converts a 2D Eigen point to a 3D Eigen point.

◆ toEigen() [1/3]

Eigen::Vector3d lanelet2_route_planning::toEigen ( const geometry_msgs::msg::Point & point)

Converts a ROS point to a 3D Eigen point.

Parameters
[in]pointpoint
Returns
converted point

Definition at line 51 of file conversions.cpp.

51{ return Eigen::Vector3d(point.x, point.y, point.z); }

◆ toEigen() [2/3]

std::vector< Eigen::Vector2d > lanelet2_route_planning::toEigen ( const lanelet::BasicLineString2d & line_string)

Converts a 2D Lanelet line string to a vector of Eigen points.

Parameters
[in]line_stringline string
Returns
converted line string

Definition at line 61 of file conversions.cpp.

61 {
62 return std::vector<Eigen::Vector2d>(line_string.begin(), line_string.end());
63}

◆ toEigen() [3/3]

std::vector< Eigen::Vector3d > lanelet2_route_planning::toEigen ( const lanelet::BasicLineString3d & line_string)

Converts a 3D Lanelet line string to a vector of Eigen points.

Parameters
[in]line_stringline string
Returns
converted line string

Definition at line 65 of file conversions.cpp.

65 {
66 return std::vector<Eigen::Vector3d>(line_string.begin(), line_string.end());
67}

◆ toEigen2d()

Eigen::Vector2d lanelet2_route_planning::toEigen2d ( const geometry_msgs::msg::Point & point)

Converts a ROS point to a 2D Eigen point.

Parameters
[in]pointpoint
Returns
converted point

Definition at line 49 of file conversions.cpp.

49{ return Eigen::Vector2d(point.x, point.y); }

◆ toLanelet() [1/4]

lanelet::BasicPoint2d lanelet2_route_planning::toLanelet ( const Eigen::Vector2d & point)

Converts a 2D Eigen point to a Lanelet point.

Parameters
[in]pointpoint
Returns
converted point

Definition at line 45 of file conversions.cpp.

45{ return lanelet::BasicPoint2d(point.x(), point.y()); }

◆ toLanelet() [2/4]

lanelet::BasicPoint3d lanelet2_route_planning::toLanelet ( const Eigen::Vector3d & point)

Converts a 3D Eigen point to a Lanelet point.

Parameters
[in]pointpoint
Returns
converted point

Definition at line 47 of file conversions.cpp.

47{ return point; }

◆ toLanelet() [3/4]

lanelet::BasicLineString2d lanelet2_route_planning::toLanelet ( const std::vector< Eigen::Vector2d > & line_string)

Converts a vector of 2D Eigen points to a Lanelet line string.

Parameters
[in]line_stringline string
Returns
converted line string

Definition at line 69 of file conversions.cpp.

69 {
70 lanelet::BasicLineString2d lanelet_line_string;
71 for (const auto& point : line_string) {
72 lanelet_line_string.push_back(toLanelet(point));
73 }
74 return lanelet_line_string;
75}

◆ toLanelet() [4/4]

lanelet::BasicLineString3d lanelet2_route_planning::toLanelet ( const std::vector< Eigen::Vector3d > & line_string)

Converts a vector of 3D Eigen points to a Lanelet line string.

Parameters
[in]line_stringline string
Returns
converted line string

Definition at line 77 of file conversions.cpp.

77 {
78 lanelet::BasicLineString3d lanelet_line_string;
79 for (const auto& point : line_string) {
80 lanelet_line_string.push_back(toLanelet(point));
81 }
82 return lanelet_line_string;
83}

◆ toRos() [1/3]

geometry_msgs::msg::Point lanelet2_route_planning::toRos ( const Eigen::Vector2d & point)

Converts a 2D Eigen point to a ROS point.

Parameters
[in]pointpoint
Returns
converted point

Definition at line 33 of file conversions.cpp.

33{ return toRos(to3d(point)); }

◆ toRos() [2/3]

geometry_msgs::msg::Point lanelet2_route_planning::toRos ( const Eigen::Vector3d & point)

Converts a 3D Eigen point to a ROS point.

Parameters
[in]pointpoint
Returns
converted point

Definition at line 35 of file conversions.cpp.

35 {
36 geometry_msgs::msg::Point ros_point;
37 ros_point.x = point.x();
38 ros_point.y = point.y();
39 ros_point.z = point.z();
40 return ros_point;
41}

◆ toRos() [3/3]

geometry_msgs::msg::Point lanelet2_route_planning::toRos ( const lanelet::BasicPoint2d & point)

Converts a 2D Lanelet point to a ROS point.

Parameters
[in]pointpoint
Returns
converted point

Definition at line 43 of file conversions.cpp.

43{ return toRos(Eigen::Vector2d(point.x(), point.y())); }

◆ toRosQuaternion()

geometry_msgs::msg::Quaternion lanelet2_route_planning::toRosQuaternion ( const Eigen::Vector2d & vector)

Converts a 2D Eigen vector pointing in a specific direction to a ROS quaternion.

The vector is assumed to lie in the xy-plane.

Parameters
[in]vectorvector
Returns
converted quaternion

Definition at line 85 of file conversions.cpp.

85 {
86 Eigen::Vector2d unit_vector = vector.normalized();
87 double angle = std::atan2(unit_vector.y(), unit_vector.x());
88 Eigen::Quaterniond quaternion(Eigen::AngleAxisd(angle, Eigen::Vector3d::UnitZ()));
89 geometry_msgs::msg::Quaternion ros_quaternion;
90 ros_quaternion.x = quaternion.x();
91 ros_quaternion.y = quaternion.y();
92 ros_quaternion.z = quaternion.z();
93 ros_quaternion.w = quaternion.w();
94 return ros_quaternion;
95}

◆ wrapAngle()

double lanelet2_route_planning::wrapAngle ( const double angle)

Wraps an angle to the range [-π, π].

Parameters
[in]angleangle to wrap
Returns
wrapped angle [radians]

Definition at line 73 of file geometry.cpp.

73 {
74 double wrapped_angle = angle;
75 while (wrapped_angle > M_PI) wrapped_angle -= 2 * M_PI;
76 while (wrapped_angle < -M_PI) wrapped_angle += 2 * M_PI;
77 return wrapped_angle;
78}

Variable Documentation

◆ is_vector_v

template<typename C >
bool lanelet2_route_planning::is_vector_v = is_vector<C>::value
inlineconstexpr

Definition at line 34 of file lanelet2_route_planning.hpp.