28#include <boost/geometry.hpp>
29#include <boost/geometry/geometries/point_xy.hpp>
30#include <boost/geometry/geometries/polygon.hpp>
42namespace bg = boost::geometry;
43using BgPoint = bg::model::d2::point_xy<double>;
51inline bool LaneChangeAllows(
LaneChange lc,
bool want_left) {
54 return lc == LaneChange::Left || lc == LaneChange::Both;
56 return lc == LaneChange::Right || lc == LaneChange::Both;
64 float target_speed_kmh,
68 : _vehicle(
std::move(vehicle)),
69 _last_traffic_light(nullptr),
70 _ignore_traffic_lights(options.ignore_traffic_lights),
71 _ignore_stop_signs(options.ignore_stop_signs),
72 _ignore_vehicles(options.ignore_vehicles),
73 _use_bbs_detection(options.use_bbs_detection),
74 _target_speed(target_speed_kmh),
75 _sampling_resolution(options.sampling_resolution),
76 _base_tlight_threshold(options.base_tlight_threshold),
77 _base_vehicle_threshold(options.base_vehicle_threshold),
78 _speed_ratio(options.detection_speed_ratio),
79 _max_brake(options.max_brake),
80 _offset(options.offset) {
133 std::optional<geom::Location> start) {
136 if (!start.has_value()) {
143 start_location = target_wpt->GetTransform().location;
145 start_location =
_vehicle->GetLocation();
149 start_location = *start;
153 auto start_wp =
_map->GetWaypoint(start_location);
154 auto end_wp =
_map->GetWaypoint(end);
161 bool stop_waypoint_creation,
163 _local_planner->SetGlobalPlan(plan, stop_waypoint_creation, clean_queue);
166std::vector<LocalPlanner::PlanItem>
169 if (!start || !end)
return {};
170 const auto &start_loc = start->GetTransform().location;
171 const auto &end_loc = end->GetTransform().location;
176 bool hazard_detected =
false;
179 auto vehicle_list =
_world->GetActors()->Filter(
"*vehicle*");
184 const float max_vehicle_distance =
187 if (v_obs.affected) {
188 hazard_detected =
true;
192 const float max_tlight_distance =
196 hazard_detected =
true;
200 if (hazard_detected) {
219 float same_lane_time,
220 float other_lane_time,
221 float lane_change_time) {
222 const float speed =
_vehicle->GetVelocity().Length();
226 same_lane_time * speed,
227 other_lane_time * speed,
228 lane_change_time * speed,
241std::pair<bool, SharedPtr<client::TrafficLight>>
243 std::optional<float> max_distance_opt) {
245 return {
false,
nullptr};
249 lights_list =
_world->GetActors()->Filter(
"*traffic_light*");
252 const float max_distance =
263 const auto ego_location =
_vehicle->GetLocation();
264 auto ego_wpt =
_map->GetWaypoint(ego_location);
268 return {
false,
nullptr};
271 for (
auto actor : *lights_list) {
273 std::dynamic_pointer_cast<client::TrafficLight>(actor);
274 if (!traffic_light) {
278 const uint32_t tl_id =
static_cast<uint32_t
>(traffic_light->GetId());
283 trigger_wp = it->second;
285 const auto trigger_location =
287 trigger_wp =
_map->GetWaypoint(trigger_location);
298 if (trigger_wp->GetTransform().location.Distance(ego_location) > max_distance) {
302 if (trigger_wp->GetRoadId() != ego_wpt->GetRoadId()) {
306 const auto ve_dir = ego_wpt->GetTransform().GetForwardVector();
307 const auto wp_dir = trigger_wp->GetTransform().GetForwardVector();
308 const float dot_ve_wp = ve_dir.x * wp_dir.x + ve_dir.y * wp_dir.y + ve_dir.z * wp_dir.z;
309 if (dot_ve_wp < 0.0f) {
320 std::make_pair(0.0f, 90.0f))) {
322 return {
true, traffic_light};
326 return {
false,
nullptr};
333 std::optional<float> max_distance_opt,
344 vehicle_list =
_world->GetActors()->Filter(
"*vehicle*");
347 const float max_distance =
350 const auto ego_transform =
_vehicle->GetTransform();
351 const auto ego_location = ego_transform.location;
352 auto ego_wpt =
_map->GetWaypoint(ego_location);
355 if (ego_wpt->GetLaneId() < 0 && lane_offset != 0) {
363 const float ext_x =
_vehicle->GetBoundingBox().extent.
x;
369 const float ego_extent_y =
_vehicle->GetBoundingBox().extent.y;
370 const bool opposite_invasion =
371 std::abs(
_offset) + ego_extent_y > ego_wpt->GetLaneWidth() / 2.0;
376 auto build_route_polygon = [&]() -> std::optional<BgPolygon> {
377 std::vector<std::array<double, 3>> route_bb;
378 const float r_ext = ego_extent_y +
_offset;
379 const float l_ext = -ego_extent_y +
_offset;
382 const auto rv = t.GetRightVector();
383 const auto loc = t.location;
384 const geom::Location p1(loc.x + r_ext * rv.x, loc.y + r_ext * rv.y, loc.z);
385 const geom::Location p2(loc.x + l_ext * rv.x, loc.y + l_ext * rv.y, loc.z);
386 route_bb.push_back({{p1.
x, p1.
y, p1.
z}});
387 route_bb.push_back({{p2.
x, p2.
y, p2.
z}});
390 append_pair(ego_transform);
393 const auto &wp = item.first;
394 if (ego_location.Distance(wp->GetTransform().location) > max_distance) {
397 append_pair(wp->GetTransform());
400 if (route_bb.size() < 3) {
405 for (
const auto &v : route_bb) {
406 bg::append(poly.outer(),
BgPoint(v[0], v[1]));
412 std::optional<BgPolygon> route_polygon = build_route_polygon();
414 for (
auto actor : *vehicle_list) {
415 if (!actor)
continue;
416 if (actor->GetId() ==
_vehicle->GetId()) {
420 const auto target_transform = actor->GetTransform();
421 if (target_transform.location.Distance(ego_location) > max_distance) {
425 auto target_wpt =
_map->GetWaypoint(target_transform.location,
427 static_cast<int32_t
>(LaneType::Any));
430 if ((use_bbs || target_wpt->IsJunction()) && route_polygon.has_value()) {
431 const auto &target_bb = actor->GetBoundingBox();
432 const auto vertices = target_bb.GetWorldVertices(actor->GetTransform());
435 for (
const auto &v : vertices) {
436 bg::append(target_poly.outer(),
BgPoint(v.x, v.y));
438 bg::correct(target_poly);
440 if (bg::intersects(*route_polygon, target_poly)) {
442 result.
actor = actor;
448 if (target_wpt->GetRoadId() != ego_wpt->GetRoadId() ||
449 target_wpt->GetLaneId() != ego_wpt->GetLaneId() + lane_offset) {
450 auto next_pair =
_local_planner->GetIncomingWaypointAndDirection(3);
451 auto next_wp = next_pair.first;
455 if (target_wpt->GetRoadId() != next_wp->GetRoadId() ||
456 target_wpt->GetLaneId() != next_wp->GetLaneId() + lane_offset) {
461 const auto target_forward = target_transform.GetForwardVector();
462 const float target_extent_x = actor->GetBoundingBox().extent.x;
465 target_extent_x * target_forward.x,
466 target_extent_x * target_forward.y,
472 std::make_pair(low_angle_th, up_angle_th))) {
474 result.
actor = actor;
476 ego_transform.location);
489 const std::string &direction,
490 float distance_same_lane,
491 float distance_other_lane,
492 float lane_change_distance,
495 float step_distance) {
497 distance_same_lane = std::max(distance_same_lane, 0.1f);
498 distance_other_lane = std::max(distance_other_lane, 0.1f);
499 lane_change_distance = std::max(lane_change_distance, 0.1f);
501 std::vector<LocalPlanner::PlanItem> plan;
509 while (
distance < distance_same_lane) {
510 auto next_wps = plan.back().first->GetNext(step_distance);
511 if (next_wps.empty())
return {};
512 auto next_wp = next_wps.front();
514 next_wp->GetTransform().location.Distance(
515 plan.back().first->GetTransform().location));
521 if (direction ==
"left") {
524 }
else if (direction ==
"right") {
531 int lane_changes_done = 0;
532 const float per_change_distance =
533 lane_change_distance /
static_cast<float>(std::max(lane_changes, 1));
536 while (lane_changes_done < lane_changes) {
537 auto next_wps = plan.back().first->GetNext(per_change_distance);
538 if (next_wps.empty())
return {};
539 auto next_wp = next_wps.front();
543 if (check && !LaneChangeAllows(next_wp->GetLaneChange(),
true)) {
546 side_wp = next_wp->GetLeft();
548 if (check && !LaneChangeAllows(next_wp->GetLaneChange(),
false)) {
551 side_wp = next_wp->GetRight();
554 if (!side_wp || side_wp->GetType() != LaneType::Driving) {
558 plan.emplace_back(side_wp, option);
565 while (
distance < distance_other_lane) {
566 auto next_wps = plan.back().first->GetNext(step_distance);
567 if (next_wps.empty())
return {};
568 auto next_wp = next_wps.front();
570 next_wp->GetTransform().location.Distance(
571 plan.back().first->GetTransform().location));
SharedPtr< client::Map > _map
bool _ignore_traffic_lights
std::pair< bool, SharedPtr< client::TrafficLight > > AffectedByTrafficLight(SharedPtr< client::ActorList > lights=nullptr, std::optional< float > max_distance=std::nullopt)
Returns (affected, light) similar to Python _affected_by_traffic_light.
void SetOffset(float offset)
VehicleObstacle VehicleObstacleDetected(SharedPtr< client::ActorList > vehicles=nullptr, std::optional< float > max_distance=std::nullopt, float up_angle_th=90.0f, float low_angle_th=0.0f, int lane_offset=0)
Mirrors Python _vehicle_obstacle_detected.
rpc::VehicleControl AddEmergencyStop(rpc::VehicleControl c) const
Overwrites throttle/brake to perform an emergency stop.
void IgnoreTrafficLights(bool active=true)
SharedPtr< client::World > _world
BasicAgent(SharedPtr< client::Vehicle > vehicle, float target_speed_kmh=20.0f, const Options &options=DefaultOptions(), SharedPtr< client::Map > map=nullptr, SharedPtr< GlobalRoutePlanner > grp=nullptr)
SharedPtr< client::ActorList > _lights_list
void IgnoreVehicles(bool active=true)
void SetTargetSpeed(float speed_kmh)
void SetGlobalPlan(const std::vector< LocalPlanner::PlanItem > &plan, bool stop_waypoint_creation=true, bool clean_queue=true)
void FollowSpeedLimits(bool value=true)
void LaneChange(const std::string &direction, float same_lane_time=0.0f, float other_lane_time=0.0f, float lane_change_time=2.0f)
Replaces the current plan with one that performs a lane change.
SharedPtr< client::TrafficLight > _last_traffic_light
std::vector< LocalPlanner::PlanItem > TraceRoute(SharedPtr< client::Waypoint > start, SharedPtr< client::Waypoint > end)
float _base_vehicle_threshold
SharedPtr< client::Vehicle > _vehicle
std::vector< LocalPlanner::PlanItem > GenerateLaneChangePath(SharedPtr< client::Waypoint > waypoint, const std::string &direction="left", float distance_same_lane=10.0f, float distance_other_lane=25.0f, float lane_change_distance=25.0f, bool check=true, int lane_changes=1, float step_distance=2.0f)
Mirrors Python _generate_lane_change_path.
virtual rpc::VehicleControl RunStep()
float _base_tlight_threshold
std::unordered_map< uint32_t, SharedPtr< client::Waypoint > > _lights_map
SharedPtr< GlobalRoutePlanner > _global_planner
float _sampling_resolution
std::unique_ptr< LocalPlanner > _local_planner
void SetDestination(const geom::Location &end, std::optional< geom::Location > start=std::nullopt)
Computes a route from start (or the current target waypoint) to end and forwards it to the local plan...
void IgnoreStopSigns(bool active=true)
GlobalRoutePlanner * GetGlobalPlanner()
LocalPlanner * GetLocalPlanner()
C++ port of agents.navigation.global_route_planner.GlobalRoutePlanner.
LocalPlanner reproduces agents.navigation.local_planner.LocalPlanner.
LaneType
Can be used as flags.
bool IsWithinDistance(const geom::Transform &target, const geom::Transform &reference, float max_distance, std::optional< std::pair< float, float > > angle_interval)
Returns true when target is within max_distance of reference.
RoadOption
Topological direction emitted by the planners.
float ComputeDistance(const geom::Location &a, const geom::Location &b)
Euclidean distance between two locations (matches numpy's regularised version that adds an epsilon to...
bg::model::d2::point_xy< double > BgPoint
geom::Location GetTrafficLightTriggerLocation(SharedPtr< client::TrafficLight > traffic_light)
Compute the world-space trigger location of a traffic light, mirroring the helper in agents....
float GetSpeed(SharedPtr< client::Actor > actor)
Compute speed of an actor in km/h.
bg::model::polygon< BgPoint > BgPolygon
This file contains definitions of common data structures used in traffic manager.
std::shared_ptr< T > SharedPtr
SharedPtr< client::Actor > actor
Aggregated configuration. Mirrors the opt_dict in local_planner.py.
LaneChange
Can be used as flags.