18#include <unordered_map>
19#include <unordered_set>
30 geom::Vector3D
UnitVector(
const geom::Location &a,
const geom::Location &b) {
31 geom::Vector3D v(b.x - a.x, b.y - a.y, b.z - a.z);
32 const double norm = std::sqrt(
static_cast<double>(v.x) * v.x
33 +
static_cast<double>(v.y) * v.y
34 +
static_cast<double>(v.z) * v.z)
35 + std::numeric_limits<double>::epsilon();
36 return geom::Vector3D(
37 static_cast<float>(v.x / norm),
38 static_cast<float>(v.y / norm),
39 static_cast<float>(v.z / norm));
46 using U = std::underlying_type_t<road::element::LaneMarking::LaneChange>;
47 return (
static_cast<U
>(lc) &
static_cast<U
>(flag)) != 0;
57 double sampling_resolution)
58 : _map(
std::move(map)),
59 _sampling_resolution(sampling_resolution) {
77 node.
vertex = {std::get<0>(key), std::get<1>(key), std::get<2>(key)};
83 auto &edge =
_edges[{n1, n2}];
88 if (std::find(
node.successors.begin(),
node.successors.end(), n2)
89 ==
node.successors.end()) {
90 node.successors.push_back(n2);
97 auto it =
_edges.find({n1, n2});
98 return it ==
_edges.end() ? nullptr : &it->second;
103 auto it =
_edges.find({n1, n2});
104 return it ==
_edges.end() ? nullptr : &it->second;
113 for (
const auto &segment :
_map->GetTopology()) {
117 const auto &l1 = wp1->GetTransform().location;
118 const auto &l2 = wp2->GetTransform().location;
122 const double x1 = std::round(
static_cast<double>(l1.x));
123 const double y1 = std::round(
static_cast<double>(l1.y));
124 const double z1 = std::round(
static_cast<double>(l1.z));
125 const double x2 = std::round(
static_cast<double>(l2.x));
126 const double y2 = std::round(
static_cast<double>(l2.y));
127 const double z2 = std::round(
static_cast<double>(l2.z));
132 seg.
entry_xyz = std::make_tuple(x1, y1, z1);
133 seg.
exit_xyz = std::make_tuple(x2, y2, z2);
135 const auto end_loc = wp2->GetTransform().location;
138 if (next_wps.empty()) {
143 auto w = next_wps[0];
145 seg.
path.push_back(w);
154 if (next_wps.empty()) {
157 seg.
path.push_back(next_wps[0]);
174 const auto &entry_wp = segment.entry;
175 const auto &exit_wp = segment.exit;
176 const bool intersection = entry_wp->IsJunction();
177 const auto road_id = entry_wp->GetRoadId();
178 const auto section_id = entry_wp->GetSectionId();
179 const auto lane_id = entry_wp->GetLaneId();
186 const auto entry_v = entry_wp->GetTransform().rotation.GetForwardVector();
187 const auto exit_v = exit_wp->GetTransform().rotation.GetForwardVector();
191 edge.
length =
static_cast<double>(segment.path.size()) + 1.0;
192 edge.
path = segment.path;
198 exit_wp->GetTransform().location);
209 int count_loose_ends = 0;
213 const auto &end_wp = segment.exit;
214 const auto road_id = end_wp->GetRoadId();
215 const auto section_id = end_wp->GetSectionId();
216 const auto lane_id = end_wp->GetLaneId();
218 bool already_indexed =
false;
221 auto sec_it = road_it->second.find(section_id);
222 if (sec_it != road_it->second.end()) {
223 already_indexed = sec_it->second.count(lane_id) > 0;
226 if (already_indexed) {
232 const NodeId n2 = -1 * count_loose_ends;
235 std::vector<SharedPtr<client::Waypoint>> path;
236 auto next_wps = end_wp->GetNext(hop);
237 while (!next_wps.empty()
239 && next_wps[0]->GetRoadId() ==
road_id
240 && next_wps[0]->GetSectionId() == section_id
241 && next_wps[0]->GetLaneId() == lane_id) {
242 path.push_back(next_wps[0]);
243 next_wps = next_wps[0]->GetNext(hop);
247 const auto &tail_loc = path.back()->GetTransform().location;
249 terminal.
vertex = {
static_cast<double>(tail_loc.x),
250 static_cast<double>(tail_loc.y),
251 static_cast<double>(tail_loc.z)};
252 _nodes.emplace(n2, std::move(terminal));
255 edge.
length =
static_cast<double>(path.size()) + 1.0;
276 bool left_found =
false;
277 bool right_found =
false;
278 if (segment.entry->IsJunction()) {
284 for (
const auto &waypoint : segment.path) {
285 if (left_found && right_found) {
291 auto right_marking = waypoint->GetRightLaneMarking();
293 && LaneChangeAllows(right_marking->lane_change, LaneChange::Right)) {
294 auto next_wp = waypoint->GetRight();
297 && waypoint->GetRoadId() == next_wp->GetRoadId()) {
298 auto next_segment =
Localize(next_wp->GetTransform().location);
299 if (next_segment.has_value()) {
301 const NodeId dst = next_segment->first;
319 auto left_marking = waypoint->GetLeftLaneMarking();
321 && LaneChangeAllows(left_marking->lane_change, LaneChange::Left)) {
322 auto next_wp = waypoint->GetLeft();
325 && waypoint->GetRoadId() == next_wp->GetRoadId()) {
326 auto next_segment =
Localize(next_wp->GetTransform().location);
327 if (next_segment.has_value()) {
329 const NodeId dst = next_segment->first;
351std::optional<std::pair<GlobalRoutePlanner::NodeId, GlobalRoutePlanner::NodeId>>
353 auto wp =
_map->GetWaypoint(location);
359 auto sec_it = road_it->second.find(wp->GetSectionId());
360 if (sec_it == road_it->second.end())
return std::nullopt;
361 auto lane_it = sec_it->second.find(wp->GetLaneId());
362 if (lane_it == sec_it->second.end())
return std::nullopt;
363 return lane_it->second;
370 const auto &va =
_nodes.at(a).vertex;
371 const auto &vb =
_nodes.at(b).vertex;
372 const double dx = va[0] - vb[0];
373 const double dy = va[1] - vb[1];
374 const double dz = va[2] - vb[2];
375 return std::sqrt(dx * dx + dy * dy + dz * dz);
381std::vector<GlobalRoutePlanner::NodeId>
386 if (!start.has_value() || !end.has_value()) {
389 const NodeId source = start->first;
390 const NodeId target = end->first;
393 using Item = std::pair<double, NodeId>;
394 std::priority_queue<Item, std::vector<Item>, std::greater<Item>> open;
395 std::unordered_map<NodeId, double> g_score;
396 std::unordered_map<NodeId, NodeId> came_from;
397 std::unordered_set<NodeId> closed;
399 g_score[source] = 0.0;
402 while (!open.empty()) {
403 auto [f, current] = open.top();
405 if (current == target) {
407 std::vector<NodeId> path;
410 while (n != source) {
411 auto it = came_from.find(n);
412 if (it == came_from.end())
break;
416 std::reverse(path.begin(), path.end());
418 path.push_back(end->second);
421 if (!closed.insert(current).second) {
425 auto node_it =
_nodes.find(current);
426 if (node_it ==
_nodes.end())
continue;
427 const double g_current = g_score[current];
429 for (
NodeId neighbor : node_it->second.successors) {
432 const double tentative = g_current + edge->
length;
433 auto it = g_score.find(neighbor);
434 if (it == g_score.end() || tentative < it->second) {
435 g_score[neighbor] = tentative;
436 came_from[neighbor] = current;
438 open.emplace(f_score, neighbor);
451 std::size_t index,
const std::vector<NodeId> &route)
const {
452 const Edge *last_intersection_edge =
nullptr;
453 std::optional<NodeId> last_node;
455 for (std::size_t i = index; i + 1 < route.size(); ++i) {
456 const NodeId n1 = route[i];
457 const NodeId n2 = route[i + 1];
459 if (!candidate)
break;
460 if (n1 == route[index]) {
461 last_intersection_edge = candidate;
464 last_intersection_edge = candidate;
470 return {last_node, last_intersection_edge};
477 const std::vector<NodeId> &route) {
479 static constexpr double threshold = 35.0 * 3.14159265358979323846 / 180.0;
482 const NodeId current_node = route[index];
483 const NodeId next_node = route[index + 1];
484 const Edge *next_edge =
FindEdge(current_node, next_node);
491 const NodeId previous_node = route[index - 1];
500 const Edge *current_edge =
FindEdge(previous_node, current_node);
503 return next_edge->
type;
509 if (calculate_turn) {
512 if (tail_edge !=
nullptr) {
513 next_edge = tail_edge;
517 if (!cv_opt.has_value() || !nv_opt.has_value()) {
519 return next_edge->
type;
521 const auto cv = *cv_opt;
522 const auto nv = *nv_opt;
526 std::vector<double> cross_list;
527 auto succ_it =
_nodes.find(current_node);
528 if (succ_it !=
_nodes.end()) {
529 for (
NodeId neighbor : succ_it->second.successors) {
530 const Edge *select_edge =
FindEdge(current_node, neighbor);
531 if (!select_edge)
continue;
533 && neighbor != route[index + 1]
536 cross_list.push_back(
537 static_cast<double>(cv.x) * sv.y
538 -
static_cast<double>(cv.y) * sv.x);
542 const double next_cross =
static_cast<double>(cv.x) * nv.y
543 -
static_cast<double>(cv.y) * nv.x;
545 const double cv_len = std::sqrt(
static_cast<double>(cv.x) * cv.x
546 +
static_cast<double>(cv.y) * cv.y
547 +
static_cast<double>(cv.z) * cv.z);
548 const double nv_len = std::sqrt(
static_cast<double>(nv.x) * nv.x
549 +
static_cast<double>(nv.y) * nv.y
550 +
static_cast<double>(nv.z) * nv.z);
551 double cos_val = 0.0;
552 if (cv_len > 0.0 && nv_len > 0.0) {
553 cos_val = (
static_cast<double>(cv.x) * nv.x
554 +
static_cast<double>(cv.y) * nv.y
555 +
static_cast<double>(cv.z) * nv.z) / (cv_len * nv_len);
557 cos_val = std::clamp(cos_val, -1.0, 1.0);
558 const double deviation = std::acos(cos_val);
560 if (cross_list.empty()) {
561 cross_list.push_back(0.0);
564 if (deviation < threshold) {
566 }
else if (next_cross < *std::min_element(cross_list.begin(), cross_list.end())) {
568 }
else if (next_cross > *std::max_element(cross_list.begin(), cross_list.end())) {
570 }
else if (next_cross < 0.0) {
572 }
else if (next_cross > 0.0) {
576 decision = next_edge->
type;
580 decision = next_edge->
type;
593 double min_distance = std::numeric_limits<double>::infinity();
594 std::size_t closest = 0;
595 const auto &cur_loc = current->GetTransform().location;
596 for (std::size_t i = 0; i < list.size(); ++i) {
597 const double d = list[i]->GetTransform().location.Distance(cur_loc);
598 if (d < min_distance) {
609std::vector<GlobalRoutePlanner::RouteItem>
612 std::vector<RouteItem> route_trace;
613 std::vector<NodeId> route =
PathSearch(origin, destination);
614 if (route.size() < 2) {
620 if (!current_waypoint || !destination_waypoint) {
624 for (std::size_t i = 0; i + 1 < route.size(); ++i) {
630 route_trace.emplace_back(current_waypoint, road_option);
634 auto sec_it = road_it->second.find(exit_wp->GetSectionId());
635 if (sec_it == road_it->second.end())
continue;
636 auto lane_it = sec_it->second.find(exit_wp->GetLaneId());
637 if (lane_it == sec_it->second.end())
continue;
638 const auto &n_pair = lane_it->second;
639 const Edge *next_edge =
FindEdge(n_pair.first, n_pair.second);
640 if (next_edge && !next_edge->
path.empty()) {
642 closest_index = std::min(next_edge->
path.size() - 1, closest_index + 5);
643 current_waypoint = next_edge->
path[closest_index];
644 }
else if (next_edge) {
647 route_trace.emplace_back(current_waypoint, road_option);
650 std::vector<SharedPtr<client::Waypoint>> path;
651 path.reserve(edge->
path.size() + 2);
653 path.insert(path.end(), edge->
path.begin(), edge->
path.end());
657 bool emitted_break =
false;
658 for (std::size_t k = closest_index; k < path.size() && !emitted_break; ++k) {
659 current_waypoint = path[k];
660 route_trace.emplace_back(current_waypoint, road_option);
661 const std::size_t remaining = route.size() - i;
663 && current_waypoint->GetTransform().location.Distance(destination)
665 emitted_break =
true;
666 }
else if (remaining <= 2
667 && current_waypoint->GetRoadId() == destination_waypoint->GetRoadId()
668 && current_waypoint->GetSectionId() == destination_waypoint->GetSectionId()
669 && current_waypoint->GetLaneId() == destination_waypoint->GetLaneId()) {
670 const std::size_t destination_index =
FindClosestInList(destination_waypoint, path);
671 if (closest_index > destination_index) {
672 emitted_break =
true;
std::tuple< double, double, double > XYZKey
double DistanceHeuristic(NodeId a, NodeId b) const
NodeId _intersection_end_node
RoadOption TurnDecision(std::size_t index, const std::vector< NodeId > &route)
std::map< std::pair< NodeId, NodeId >, Edge > _edges
double _sampling_resolution
std::vector< RouteItem > TraceRoute(const geom::Location &origin, const geom::Location &destination)
Returns the list of (waypoint, RoadOption) pairs from origin to destination.
std::unordered_map< NodeId, Node > _nodes
static std::size_t FindClosestInList(const SharedPtr< client::Waypoint > ¤t, const std::vector< SharedPtr< client::Waypoint > > &list)
const Edge * FindEdge(NodeId n1, NodeId n2) const
std::map< XYZKey, NodeId > _id_map
std::map< uint32_t, std::map< uint32_t, std::map< int32_t, std::pair< NodeId, NodeId > > > > _road_id_to_edge
NodeId GetOrCreateNode(const XYZKey &key)
std::pair< std::optional< NodeId >, const Edge * > SuccessiveLastIntersectionEdge(std::size_t index, const std::vector< NodeId > &route) const
Edge & AddEdge(NodeId n1, NodeId n2)
RoadOption _previous_decision
std::optional< std::pair< NodeId, NodeId > > Localize(const geom::Location &loc) const
SharedPtr< client::Map > _map
std::vector< TopologySegment > _topology
GlobalRoutePlanner(SharedPtr< client::Map > map, double sampling_resolution)
std::vector< NodeId > PathSearch(const geom::Location &origin, const geom::Location &destination)
RoadOption
Topological direction emitted by the planners.
std::array< float, 3 > UnitVector(const geom::Location &a, const geom::Location &b)
Unit vector going from a to b, including the z component.
This file contains definitions of common data structures used in traffic manager.
std::shared_ptr< T > SharedPtr
SharedPtr< client::Waypoint > change_waypoint
std::optional< geom::Vector3D > net_vector
std::optional< geom::Vector3D > entry_vector
SharedPtr< client::Waypoint > entry_waypoint
std::vector< SharedPtr< client::Waypoint > > path
std::optional< geom::Vector3D > exit_vector
SharedPtr< client::Waypoint > exit_waypoint
std::array< double, 3 > vertex
SharedPtr< client::Waypoint > exit
std::vector< SharedPtr< client::Waypoint > > path
SharedPtr< client::Waypoint > entry
LaneChange
Can be used as flags.