CARLA
Loading...
Searching...
No Matches
GlobalRoutePlanner.cpp
Go to the documentation of this file.
1// Copyright (c) 2018-2020 CVC.
2//
3// This work is licensed under the terms of the MIT license.
4// For a copy, see <https://opensource.org/licenses/MIT>.
5
7
8#include "carla/client/Map.h"
11#include "carla/road/Lane.h"
13
14#include <algorithm>
15#include <cmath>
16#include <limits>
17#include <queue>
18#include <unordered_map>
19#include <unordered_set>
20
21namespace carla {
22namespace agents {
23namespace navigation {
24
25namespace {
26
27 // Mirrors agents.tools.misc.vector(): unit vector from a -> b with an
28 // epsilon added to the norm to avoid division by zero (matches numpy's
29 // `np.finfo(float).eps`).
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));
40 }
41
42 // Bitwise-AND test on the LaneChange enum class — Python uses
43 // `lane_change & carla.LaneChange.Right` and treats non-zero as truthy.
44 bool LaneChangeAllows(road::element::LaneMarking::LaneChange lc,
46 using U = std::underlying_type_t<road::element::LaneMarking::LaneChange>;
47 return (static_cast<U>(lc) & static_cast<U>(flag)) != 0;
48 }
49
50} // namespace
51
52// -----------------------------------------------------------------------------
53// ctor: build pipeline mirrors the Python __init__:
54// _build_topology -> _build_graph -> _find_loose_ends -> _lane_change_link.
55// -----------------------------------------------------------------------------
57 double sampling_resolution)
58 : _map(std::move(map)),
59 _sampling_resolution(sampling_resolution) {
61 BuildGraph();
64}
65
66// -----------------------------------------------------------------------------
67// graph mutators
68// -----------------------------------------------------------------------------
70 auto it = _id_map.find(key);
71 if (it != _id_map.end()) {
72 return it->second;
73 }
74 const NodeId new_id = static_cast<NodeId>(_id_map.size());
75 _id_map.emplace(key, new_id);
76 Node node;
77 node.vertex = {std::get<0>(key), std::get<1>(key), std::get<2>(key)};
78 _nodes.emplace(new_id, std::move(node));
79 return new_id;
80}
81
83 auto &edge = _edges[{n1, n2}];
84 edge.src = n1;
85 edge.dst = n2;
86 // Track the successor only on the first insert (matches DiGraph semantics).
87 auto &node = _nodes[n1];
88 if (std::find(node.successors.begin(), node.successors.end(), n2)
89 == node.successors.end()) {
90 node.successors.push_back(n2);
91 }
92 return edge;
93}
94
97 auto it = _edges.find({n1, n2});
98 return it == _edges.end() ? nullptr : &it->second;
99}
100
103 auto it = _edges.find({n1, n2});
104 return it == _edges.end() ? nullptr : &it->second;
105}
106
107// -----------------------------------------------------------------------------
108// _build_topology
109// -----------------------------------------------------------------------------
111 _topology.clear();
112
113 for (const auto &segment : _map->GetTopology()) {
114 SharedPtr<client::Waypoint> wp1 = segment.first;
115 SharedPtr<client::Waypoint> wp2 = segment.second;
116
117 const auto &l1 = wp1->GetTransform().location;
118 const auto &l2 = wp2->GetTransform().location;
119
120 // Round to integer coords to deduplicate near-identical endpoints — must
121 // match `np.round([...], 0)` exactly.
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));
128
129 TopologySegment seg;
130 seg.entry = wp1;
131 seg.exit = wp2;
132 seg.entry_xyz = std::make_tuple(x1, y1, z1);
133 seg.exit_xyz = std::make_tuple(x2, y2, z2);
134
135 const auto end_loc = wp2->GetTransform().location;
136 if (wp1->GetTransform().location.Distance(end_loc) > _sampling_resolution) {
137 auto next_wps = wp1->GetNext(_sampling_resolution);
138 if (next_wps.empty()) {
139 // Mirror Python: still record the (empty-path) segment.
140 _topology.push_back(std::move(seg));
141 continue;
142 }
143 auto w = next_wps[0];
144 while (w && w->GetTransform().location.Distance(end_loc) > _sampling_resolution) {
145 seg.path.push_back(w);
146 auto step = w->GetNext(_sampling_resolution);
147 if (step.empty()) {
148 break;
149 }
150 w = step[0];
151 }
152 } else {
153 auto next_wps = wp1->GetNext(_sampling_resolution);
154 if (next_wps.empty()) {
155 continue; // skip degenerate segment
156 }
157 seg.path.push_back(next_wps[0]);
158 }
159
160 _topology.push_back(std::move(seg));
161 }
162}
163
164// -----------------------------------------------------------------------------
165// _build_graph
166// -----------------------------------------------------------------------------
168 _nodes.clear();
169 _edges.clear();
170 _id_map.clear();
171 _road_id_to_edge.clear();
172
173 for (const auto &segment : _topology) {
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();
180
181 const NodeId n1 = GetOrCreateNode(segment.entry_xyz);
182 const NodeId n2 = GetOrCreateNode(segment.exit_xyz);
183
184 _road_id_to_edge[road_id][section_id][lane_id] = {n1, n2};
185
186 const auto entry_v = entry_wp->GetTransform().rotation.GetForwardVector();
187 const auto exit_v = exit_wp->GetTransform().rotation.GetForwardVector();
188
189 Edge &edge = AddEdge(n1, n2);
190 // Python: length = len(path) + 1.
191 edge.length = static_cast<double>(segment.path.size()) + 1.0;
192 edge.path = segment.path;
193 edge.entry_waypoint = entry_wp;
194 edge.exit_waypoint = exit_wp;
195 edge.entry_vector = entry_v;
196 edge.exit_vector = exit_v;
197 edge.net_vector = UnitVector(entry_wp->GetTransform().location,
198 exit_wp->GetTransform().location);
199 edge.intersection = intersection;
201 }
202}
203
204// -----------------------------------------------------------------------------
205// _find_loose_ends — synthesize terminal nodes with NEGATIVE ids for road
206// segments whose exit doesn't appear as anyone's entry.
207// -----------------------------------------------------------------------------
209 int count_loose_ends = 0;
210 const double hop = _sampling_resolution;
211
212 for (const auto &segment : _topology) {
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();
217
218 bool already_indexed = false;
219 auto road_it = _road_id_to_edge.find(road_id);
220 if (road_it != _road_id_to_edge.end()) {
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;
224 }
225 }
226 if (already_indexed) {
227 continue;
228 }
229
230 ++count_loose_ends;
231 const NodeId n1 = _id_map.at(segment.exit_xyz);
232 const NodeId n2 = -1 * count_loose_ends; // NEGATIVE id sentinel
233 _road_id_to_edge[road_id][section_id][lane_id] = {n1, n2};
234
235 std::vector<SharedPtr<client::Waypoint>> path;
236 auto next_wps = end_wp->GetNext(hop);
237 while (!next_wps.empty()
238 && next_wps[0]
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);
244 }
245
246 if (!path.empty()) {
247 const auto &tail_loc = path.back()->GetTransform().location;
248 Node terminal;
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));
253
254 Edge &edge = AddEdge(n1, n2);
255 edge.length = static_cast<double>(path.size()) + 1.0;
256 edge.path = path;
257 edge.entry_waypoint = end_wp;
258 edge.exit_waypoint = path.back();
259 edge.entry_vector = std::nullopt;
260 edge.exit_vector = std::nullopt;
261 edge.net_vector = std::nullopt;
262 edge.intersection = end_wp->IsJunction();
264 }
265 }
266}
267
268// -----------------------------------------------------------------------------
269// _lane_change_link — zero-length edges from segment entry to the localized
270// neighbor lane. Python only adds at most one Right and one Left per segment.
271// -----------------------------------------------------------------------------
274
275 for (const auto &segment : _topology) {
276 bool left_found = false;
277 bool right_found = false;
278 if (segment.entry->IsJunction()) {
279 // Python only checks `not segment['entry'].is_junction` inside the loop;
280 // skipping the loop when true is equivalent and saves work.
281 continue;
282 }
283
284 for (const auto &waypoint : segment.path) {
285 if (left_found && right_found) {
286 break;
287 }
288
289 // Right lane change.
290 if (!right_found) {
291 auto right_marking = waypoint->GetRightLaneMarking();
292 if (right_marking
293 && LaneChangeAllows(right_marking->lane_change, LaneChange::Right)) {
294 auto next_wp = waypoint->GetRight();
295 if (next_wp
296 && next_wp->GetType() == road::Lane::LaneType::Driving
297 && waypoint->GetRoadId() == next_wp->GetRoadId()) {
298 auto next_segment = Localize(next_wp->GetTransform().location);
299 if (next_segment.has_value()) {
300 const NodeId src = _id_map.at(segment.entry_xyz);
301 const NodeId dst = next_segment->first;
302 Edge &edge = AddEdge(src, dst);
303 edge.entry_waypoint = waypoint;
304 edge.exit_waypoint = next_wp;
305 edge.intersection = false;
306 edge.exit_vector = std::nullopt;
307 edge.path.clear();
308 edge.length = 0.0;
310 edge.change_waypoint = next_wp;
311 right_found = true;
312 }
313 }
314 }
315 }
316
317 // Left lane change.
318 if (!left_found) {
319 auto left_marking = waypoint->GetLeftLaneMarking();
320 if (left_marking
321 && LaneChangeAllows(left_marking->lane_change, LaneChange::Left)) {
322 auto next_wp = waypoint->GetLeft();
323 if (next_wp
324 && next_wp->GetType() == road::Lane::LaneType::Driving
325 && waypoint->GetRoadId() == next_wp->GetRoadId()) {
326 auto next_segment = Localize(next_wp->GetTransform().location);
327 if (next_segment.has_value()) {
328 const NodeId src = _id_map.at(segment.entry_xyz);
329 const NodeId dst = next_segment->first;
330 Edge &edge = AddEdge(src, dst);
331 edge.entry_waypoint = waypoint;
332 edge.exit_waypoint = next_wp;
333 edge.intersection = false;
334 edge.exit_vector = std::nullopt;
335 edge.path.clear();
336 edge.length = 0.0;
338 edge.change_waypoint = next_wp;
339 left_found = true;
340 }
341 }
342 }
343 }
344 }
345 }
346}
347
348// -----------------------------------------------------------------------------
349// _localize
350// -----------------------------------------------------------------------------
351std::optional<std::pair<GlobalRoutePlanner::NodeId, GlobalRoutePlanner::NodeId>>
353 auto wp = _map->GetWaypoint(location);
354 if (!wp) {
355 return std::nullopt;
356 }
357 auto road_it = _road_id_to_edge.find(wp->GetRoadId());
358 if (road_it == _road_id_to_edge.end()) return std::nullopt;
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;
364}
365
366// -----------------------------------------------------------------------------
367// _distance_heuristic
368// -----------------------------------------------------------------------------
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);
376}
377
378// -----------------------------------------------------------------------------
379// _path_search — A* with euclidean heuristic on rounded XYZ vertices.
380// -----------------------------------------------------------------------------
381std::vector<GlobalRoutePlanner::NodeId>
383 const geom::Location &destination) {
384 auto start = Localize(origin);
385 auto end = Localize(destination);
386 if (!start.has_value() || !end.has_value()) {
387 return {};
388 }
389 const NodeId source = start->first;
390 const NodeId target = end->first;
391
392 // Standard A*: priority queue keyed on f-score = g + h.
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;
398
399 g_score[source] = 0.0;
400 open.emplace(DistanceHeuristic(source, target), source);
401
402 while (!open.empty()) {
403 auto [f, current] = open.top();
404 open.pop();
405 if (current == target) {
406 // Reconstruct path source -> target.
407 std::vector<NodeId> path;
408 NodeId n = current;
409 path.push_back(n);
410 while (n != source) {
411 auto it = came_from.find(n);
412 if (it == came_from.end()) break;
413 n = it->second;
414 path.push_back(n);
415 }
416 std::reverse(path.begin(), path.end());
417 // Python appends end[1] (the second node id of the destination edge).
418 path.push_back(end->second);
419 return path;
420 }
421 if (!closed.insert(current).second) {
422 continue; // stale entry
423 }
424
425 auto node_it = _nodes.find(current);
426 if (node_it == _nodes.end()) continue;
427 const double g_current = g_score[current];
428
429 for (NodeId neighbor : node_it->second.successors) {
430 const Edge *edge = FindEdge(current, neighbor);
431 if (!edge) continue;
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;
437 const double f_score = tentative + DistanceHeuristic(neighbor, target);
438 open.emplace(f_score, neighbor);
439 }
440 }
441 }
442
443 return {}; // unreachable
444}
445
446// -----------------------------------------------------------------------------
447// _successive_last_intersection_edge
448// -----------------------------------------------------------------------------
449std::pair<std::optional<GlobalRoutePlanner::NodeId>, const GlobalRoutePlanner::Edge *>
451 std::size_t index, const std::vector<NodeId> &route) const {
452 const Edge *last_intersection_edge = nullptr;
453 std::optional<NodeId> last_node;
454
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];
458 const Edge *candidate = FindEdge(n1, n2);
459 if (!candidate) break;
460 if (n1 == route[index]) {
461 last_intersection_edge = candidate;
462 }
463 if (candidate->type == RoadOption::LaneFollow && candidate->intersection) {
464 last_intersection_edge = candidate;
465 last_node = n2;
466 } else {
467 break;
468 }
469 }
470 return {last_node, last_intersection_edge};
471}
472
473// -----------------------------------------------------------------------------
474// _turn_decision — uses 2-D cross-product Z (cv.x*nv.y - cv.y*nv.x).
475// -----------------------------------------------------------------------------
477 const std::vector<NodeId> &route) {
478 // math.radians(35) — hard-coded to avoid depending on the non-standard M_PI.
479 static constexpr double threshold = 35.0 * 3.14159265358979323846 / 180.0;
480 RoadOption decision = RoadOption::Void;
481
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);
485 if (!next_edge) {
487 return RoadOption::Void;
488 }
489
490 if (index > 0) {
491 const NodeId previous_node = route[index - 1];
494 && _intersection_end_node != previous_node
495 && next_edge->type == RoadOption::LaneFollow
496 && next_edge->intersection) {
497 decision = _previous_decision;
498 } else {
500 const Edge *current_edge = FindEdge(previous_node, current_node);
501 if (!current_edge) {
502 _previous_decision = next_edge->type;
503 return next_edge->type;
504 }
505 const bool calculate_turn = current_edge->type == RoadOption::LaneFollow
506 && !current_edge->intersection
507 && next_edge->type == RoadOption::LaneFollow
508 && next_edge->intersection;
509 if (calculate_turn) {
510 auto [last_node, tail_edge] = SuccessiveLastIntersectionEdge(index, route);
511 _intersection_end_node = last_node.value_or(-1);
512 if (tail_edge != nullptr) {
513 next_edge = tail_edge;
514 }
515 const auto &cv_opt = current_edge->exit_vector;
516 const auto &nv_opt = next_edge->exit_vector;
517 if (!cv_opt.has_value() || !nv_opt.has_value()) {
518 _previous_decision = next_edge->type;
519 return next_edge->type;
520 }
521 const auto cv = *cv_opt;
522 const auto nv = *nv_opt;
523
524 // 2-D cross product Z-component for siblings (only LANEFOLLOW
525 // successors that aren't the chosen next-node).
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;
532 if (select_edge->type == RoadOption::LaneFollow
533 && neighbor != route[index + 1]
534 && select_edge->net_vector.has_value()) {
535 const auto &sv = *select_edge->net_vector;
536 cross_list.push_back(
537 static_cast<double>(cv.x) * sv.y
538 - static_cast<double>(cv.y) * sv.x);
539 }
540 }
541 }
542 const double next_cross = static_cast<double>(cv.x) * nv.y
543 - static_cast<double>(cv.y) * nv.x;
544
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);
556 }
557 cos_val = std::clamp(cos_val, -1.0, 1.0);
558 const double deviation = std::acos(cos_val);
559
560 if (cross_list.empty()) {
561 cross_list.push_back(0.0);
562 }
563
564 if (deviation < threshold) {
565 decision = RoadOption::Straight;
566 } else if (next_cross < *std::min_element(cross_list.begin(), cross_list.end())) {
567 decision = RoadOption::Left;
568 } else if (next_cross > *std::max_element(cross_list.begin(), cross_list.end())) {
569 decision = RoadOption::Right;
570 } else if (next_cross < 0.0) {
571 decision = RoadOption::Left;
572 } else if (next_cross > 0.0) {
573 decision = RoadOption::Right;
574 }
575 } else {
576 decision = next_edge->type;
577 }
578 }
579 } else {
580 decision = next_edge->type;
581 }
582
583 _previous_decision = decision;
584 return decision;
585}
586
587// -----------------------------------------------------------------------------
588// _find_closest_in_list
589// -----------------------------------------------------------------------------
591 const SharedPtr<client::Waypoint> &current,
592 const std::vector<SharedPtr<client::Waypoint>> &list) {
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) {
599 min_distance = d;
600 closest = i;
601 }
602 }
603 return closest;
604}
605
606// -----------------------------------------------------------------------------
607// trace_route
608// -----------------------------------------------------------------------------
609std::vector<GlobalRoutePlanner::RouteItem>
611 const geom::Location &destination) {
612 std::vector<RouteItem> route_trace;
613 std::vector<NodeId> route = PathSearch(origin, destination);
614 if (route.size() < 2) {
615 return route_trace;
616 }
617
618 SharedPtr<client::Waypoint> current_waypoint = _map->GetWaypoint(origin);
619 SharedPtr<client::Waypoint> destination_waypoint = _map->GetWaypoint(destination);
620 if (!current_waypoint || !destination_waypoint) {
621 return route_trace;
622 }
623
624 for (std::size_t i = 0; i + 1 < route.size(); ++i) {
625 const RoadOption road_option = TurnDecision(i, route);
626 const Edge *edge = FindEdge(route[i], route[i + 1]);
627 if (!edge) continue;
628
629 if (edge->type != RoadOption::LaneFollow && edge->type != RoadOption::Void) {
630 route_trace.emplace_back(current_waypoint, road_option);
631 const auto &exit_wp = edge->exit_waypoint;
632 auto road_it = _road_id_to_edge.find(exit_wp->GetRoadId());
633 if (road_it == _road_id_to_edge.end()) continue;
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()) {
641 std::size_t closest_index = FindClosestInList(current_waypoint, next_edge->path);
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) {
645 current_waypoint = next_edge->exit_waypoint;
646 }
647 route_trace.emplace_back(current_waypoint, road_option);
648 } else {
649 // path = [entry] + path + [exit]
650 std::vector<SharedPtr<client::Waypoint>> path;
651 path.reserve(edge->path.size() + 2);
652 path.push_back(edge->entry_waypoint);
653 path.insert(path.end(), edge->path.begin(), edge->path.end());
654 path.push_back(edge->exit_waypoint);
655
656 const std::size_t closest_index = FindClosestInList(current_waypoint, path);
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;
662 if (remaining <= 2
663 && current_waypoint->GetTransform().location.Distance(destination)
664 < 2.0 * _sampling_resolution) {
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;
673 }
674 }
675 }
676 }
677 }
678
679 return route_trace;
680}
681
682} // namespace navigation
683} // namespace agents
684} // namespace carla
long long node
Definition LaneGraph.cpp:43
std::string road_id
Definition LaneGraph.cpp:39
std::tuple< double, double, double > XYZKey
double DistanceHeuristic(NodeId a, NodeId b) const
RoadOption TurnDecision(std::size_t index, const std::vector< NodeId > &route)
std::map< std::pair< NodeId, NodeId >, Edge > _edges
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 > &current, const std::vector< SharedPtr< client::Waypoint > > &list)
const Edge * FindEdge(NodeId n1, NodeId n2) const
std::map< uint32_t, std::map< uint32_t, std::map< int32_t, std::pair< NodeId, NodeId > > > > _road_id_to_edge
std::pair< std::optional< NodeId >, const Edge * > SuccessiveLastIntersectionEdge(std::size_t index, const std::vector< NodeId > &route) const
std::optional< std::pair< NodeId, NodeId > > Localize(const geom::Location &loc) const
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.
Definition Misc.cpp:139
This file contains definitions of common data structures used in traffic manager.
std::shared_ptr< T > SharedPtr
Definition Memory.h:15
std::vector< SharedPtr< client::Waypoint > > path
LaneChange
Can be used as flags.
Definition LaneMarking.h:50