Debug drawing extension to allow drawing primitives on HUD layer (#7168)

* Extended debug draw functions to allow drawing primitives on HUD layer

* Added documentation for new drawing features

* Added debug draw changes to changelog

---------

Co-authored-by: Olli <olli.koskelainen@tuni.fi>
This commit is contained in:
Olli Koskelainen 2024-03-27 13:28:43 +02:00 committed by GitHub
parent b6b4b4f138
commit d5d3cf9edf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 811 additions and 410 deletions

View File

@ -10,6 +10,7 @@
* make PythonAPI Windows: Fixed incompatibility issue with Anaconda due `py` command.
* Added function to get actor' sockets names
* Fixed bug in python agents when vehicle list was empty causing a check on all vehicles (BasicAgent.py) and detected pedestrians as vehicles if no pedestrains are present (BehaviourAgent.py)
* Extended debug drawing functions to allow drawing primitives on HUD layer
* Added possibility to change gravity variable in imui sensor for the accelerometer
* Fixed ROS2 native extension build error when ROS2 is installed in the system.
* ROS2Native: Force fast-dds dependencies download to avoid build crash when boost_asio and tinyxml2 are not installed in Linux.

View File

@ -722,13 +722,45 @@ Draws an arrow from `begin` to `end` pointing in that direction.
- `color` (_[carla.Color](#carla.Color)_) - RGB code to color the object. Red by default.
- `life_time` (_float<small> - seconds</small>_) - Shape's lifespan. By default it only lasts one frame. Set this to <code>0</code> for permanent shapes.
- <a name="carla.DebugHelper.draw_box"></a>**<font color="#7fb800">draw_box</font>**(<font color="#00a6ed">**self**</font>, <font color="#00a6ed">**box**</font>, <font color="#00a6ed">**rotation**</font>, <font color="#00a6ed">**thickness**=0.1</font>, <font color="#00a6ed">**color**=(255,0,0)</font>, <font color="#00a6ed">**life_time**=-1.0</font>)<button class="SnipetButton" id="carla.DebugHelper.draw_box-snipet_button">snippet &rarr;</button>
Draws a box, ussually to act for object colliders.
Draws a box, usually to act for object colliders.
- **Parameters:**
- `box` (_[carla.BoundingBox](#carla.BoundingBox)_) - Object containing a location and the length of a box for every axis.
- `rotation` (_[carla.Rotation](#carla.Rotation)<small> - degrees (pitch,yaw,roll)</small>_) - Orientation of the box according to Unreal Engine's axis system.
- `thickness` (_float<small> - meters</small>_) - Density of the lines that define the box.
- `color` (_[carla.Color](#carla.Color)_) - RGB code to color the object. Red by default.
- `life_time` (_float<small> - seconds</small>_) - Shape's lifespan. By default it only lasts one frame. Set this to <code>0</code> for permanent shapes.
- <a name="carla.DebugHelper.draw_hud_arrow"></a>**<font color="#7fb800">draw_hud_arrow</font>**(<font color="#00a6ed">**self**</font>, <font color="#00a6ed">**begin**</font>, <font color="#00a6ed">**end**</font>, <font color="#00a6ed">**thickness**=0.1</font>, <font color="#00a6ed">**arrow_size**=0.1</font>, <font color="#00a6ed">**color**=(255,0,0)</font>, <font color="#00a6ed">**life_time**=-1.0</font>)
Draws an arrow on the HUD from `begin` to `end` which can only be seen server-side.
- **Parameters:**
- `begin` (_[carla.Location](#carla.Location)<small> - meters</small>_) - Point in the coordinate system where the arrow starts.
- `end` (_[carla.Location](#carla.Location)<small> - meters</small>_) - Point in the coordinate system where the arrow ends and points towards to.
- `thickness` (_float<small> - meters</small>_) - Density of the line.
- `arrow_size` (_float<small> - meters</small>_) - Size of the tip of the arrow.
- `color` (_[carla.Color](#carla.Color)_) - RGB code to color the object. Red by default.
- `life_time` (_float<small> - seconds</small>_) - Shape's lifespan. By default it only lasts one frame. Set this to <code>0</code> for permanent shapes.
- <a name="carla.DebugHelper.draw_hud_box"></a>**<font color="#7fb800">draw_hud_box</font>**(<font color="#00a6ed">**self**</font>, <font color="#00a6ed">**box**</font>, <font color="#00a6ed">**rotation**</font>, <font color="#00a6ed">**thickness**=0.1</font>, <font color="#00a6ed">**color**=(255,0,0)</font>, <font color="#00a6ed">**life_time**=-1.0</font>)
Draws a box on the HUD, usually to act for object colliders. The box can only be seen server-side.
- **Parameters:**
- `box` (_[carla.BoundingBox](#carla.BoundingBox)_) - Object containing a location and the length of a box for every axis.
- `rotation` (_[carla.Rotation](#carla.Rotation)<small> - degrees (pitch,yaw,roll)</small>_) - Orientation of the box according to Unreal Engine's axis system.
- `thickness` (_float<small> - meters</small>_) - Density of the lines that define the box.
- `color` (_[carla.Color](#carla.Color)_) - RGB code to color the object. Red by default.
- `life_time` (_float<small> - seconds</small>_) - Shape's lifespan. By default it only lasts one frame. Set this to <code>0</code> for permanent shapes.
- <a name="carla.DebugHelper.draw_hud_line"></a>**<font color="#7fb800">draw_hud_line</font>**(<font color="#00a6ed">**self**</font>, <font color="#00a6ed">**begin**</font>, <font color="#00a6ed">**end**</font>, <font color="#00a6ed">**thickness**=0.1</font>, <font color="#00a6ed">**color**=(255,0,0)</font>, <font color="#00a6ed">**life_time**=-1.0</font>)
Draws a line on the HUD in between `begin` and `end`. The line can only be seen server-side.
- **Parameters:**
- `begin` (_[carla.Location](#carla.Location)<small> - meters</small>_) - Point in the coordinate system where the line starts.
- `end` (_[carla.Location](#carla.Location)<small> - meters</small>_) - Spot in the coordinate system where the line ends.
- `thickness` (_float<small> - meters</small>_) - Density of the line.
- `color` (_[carla.Color](#carla.Color)_) - RGB code to color the object. Red by default.
- `life_time` (_float<small> - seconds</small>_) - Shape's lifespan. By default it only lasts one frame. Set this to <code>0</code> for permanent shapes.
- <a name="carla.DebugHelper.draw_hud_point"></a>**<font color="#7fb800">draw_hud_point</font>**(<font color="#00a6ed">**self**</font>, <font color="#00a6ed">**location**</font>, <font color="#00a6ed">**size**=0.1</font>, <font color="#00a6ed">**color**=(255,0,0)</font>, <font color="#00a6ed">**life_time**=-1.0</font>)
Draws a point on the HUD at `location`. The point can only be seen server-side.
- **Parameters:**
- `location` (_[carla.Location](#carla.Location)<small> - meters</small>_) - Spot in the coordinate system to center the object.
- `size` (_float<small> - meters</small>_) - Density of the point.
- `color` (_[carla.Color](#carla.Color)_) - RGB code to color the object. Red by default.
- `life_time` (_float<small> - seconds</small>_) - Shape's lifespan. By default it only lasts one frame. Set this to <code>0</code> for permanent shapes.
- <a name="carla.DebugHelper.draw_line"></a>**<font color="#7fb800">draw_line</font>**(<font color="#00a6ed">**self**</font>, <font color="#00a6ed">**begin**</font>, <font color="#00a6ed">**end**</font>, <font color="#00a6ed">**thickness**=0.1</font>, <font color="#00a6ed">**color**=(255,0,0)</font>, <font color="#00a6ed">**life_time**=-1.0</font>)
Draws a line in between `begin` and `end`.
- **Parameters:**
@ -4194,71 +4226,6 @@ document.getElementById("snipets-container").innerHTML = null;
}
</script>
<div id ="carla.World.unload_map_layer-snipet" style="display: none;">
<p class="SnipetFont">
Snippet for carla.World.unload_map_layer
</p>
<div id="carla.World.unload_map_layer-code" class="SnipetContent">
```py
# This recipe toggles off several layers in our "_Opt" maps
# Load town one with minimum layout (roads, sidewalks, traffic lights and traffic signs)
# as well as buildings and parked vehicles
world = client.load_world('Town01_Opt', carla.MapLayer.Buildings | carla.MapLayer.ParkedVehicles)
# Toggle all buildings off
world.unload_map_layer(carla.MapLayer.Buildings)
# Toggle all parked vehicles off
world.unload_map_layer(carla.MapLayer.ParkedVehicles)
```
<button id="button1" class="CopyScript" onclick="CopyToClipboard('carla.World.unload_map_layer-code')">Copy snippet</button>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<button id="button1" class="CloseSnipet" onclick="CloseSnipet()">Close snippet</button><br><br>
</div>
<div id ="carla.DebugHelper.draw_string-snipet" style="display: none;">
<p class="SnipetFont">
Snippet for carla.DebugHelper.draw_string
</p>
<div id="carla.DebugHelper.draw_string-code" class="SnipetContent">
```py
# This recipe is a modification of lane_explorer.py example.
# It draws the path of an actor through the world, printing information at each waypoint.
# ...
current_w = map.get_waypoint(vehicle.get_location())
while True:
next_w = map.get_waypoint(vehicle.get_location(), lane_type=carla.LaneType.Driving | carla.LaneType.Shoulder | carla.LaneType.Sidewalk )
# Check if the vehicle is moving
if next_w.id != current_w.id:
vector = vehicle.get_velocity()
# Check if the vehicle is on a sidewalk
if current_w.lane_type == carla.LaneType.Sidewalk:
draw_waypoint_union(debug, current_w, next_w, cyan if current_w.is_junction else red, 60)
else:
draw_waypoint_union(debug, current_w, next_w, cyan if current_w.is_junction else green, 60)
debug.draw_string(current_w.transform.location, str('%15.0f km/h' % (3.6 * math.sqrt(vector.x**2 + vector.y**2 + vector.z**2))), False, orange, 60)
draw_transform(debug, current_w.transform, white, 60)
# Update the current waypoint and sleep for some time
current_w = next_w
time.sleep(args.tick_time)
# ...
```
<button id="button1" class="CopyScript" onclick="CopyToClipboard('carla.DebugHelper.draw_string-code')">Copy snippet</button>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<button id="button1" class="CloseSnipet" onclick="CloseSnipet()">Close snippet</button><br><br>
</div>
<div id ="carla.ActorBlueprint.set_attribute-snipet" style="display: none;">
<p class="SnipetFont">
Snippet for carla.ActorBlueprint.set_attribute
@ -4293,247 +4260,6 @@ camera_bp.set_attribute('image_size_y', 600)
</div>
<div id ="carla.World.get_spectator-snipet" style="display: none;">
<p class="SnipetFont">
Snippet for carla.World.get_spectator
</p>
<div id="carla.World.get_spectator-code" class="SnipetContent">
```py
# This recipe spawns an actor and the spectator camera at the actor's location.
# ...
world = client.get_world()
spectator = world.get_spectator()
vehicle_bp = random.choice(world.get_blueprint_library().filter('vehicle.bmw.*'))
transform = random.choice(world.get_map().get_spawn_points())
vehicle = world.try_spawn_actor(vehicle_bp, transform)
# Wait for world to get the vehicle actor
world.tick()
world_snapshot = world.wait_for_tick()
actor_snapshot = world_snapshot.find(vehicle.id)
# Set spectator at given transform (vehicle transform)
spectator.set_transform(actor_snapshot.get_transform())
# ...
```
<button id="button1" class="CopyScript" onclick="CopyToClipboard('carla.World.get_spectator-code')">Copy snippet</button>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<button id="button1" class="CloseSnipet" onclick="CloseSnipet()">Close snippet</button><br><br>
</div>
<div id ="carla.Sensor.listen-snipet" style="display: none;">
<p class="SnipetFont">
Snippet for carla.Sensor.listen
</p>
<div id="carla.Sensor.listen-code" class="SnipetContent">
```py
# This recipe applies a color conversion to the image taken by a camera sensor,
# so it is converted to a semantic segmentation image.
# ...
camera_bp = world.get_blueprint_library().filter('sensor.camera.semantic_segmentation')
# ...
cc = carla.ColorConverter.CityScapesPalette
camera.listen(lambda image: image.save_to_disk('output/%06d.png' % image.frame, cc))
# ...
```
<button id="button1" class="CopyScript" onclick="CopyToClipboard('carla.Sensor.listen-code')">Copy snippet</button>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<button id="button1" class="CloseSnipet" onclick="CloseSnipet()">Close snippet</button><br><br>
</div>
<div id ="carla.World.load_map_layer-snipet" style="display: none;">
<p class="SnipetFont">
Snippet for carla.World.load_map_layer
</p>
<div id="carla.World.load_map_layer-code" class="SnipetContent">
```py
# This recipe toggles on several layers in our "_Opt" maps
# Load town one with only minimum layout (roads, sidewalks, traffic lights and traffic signs)
world = client.load_world('Town01_Opt', carla.MapLayer.None)
# Toggle all buildings on
world.load_map_layer(carla.MapLayer.Buildings)
# Toggle all foliage on
world.load_map_layer(carla.MapLayer.Foliage)
# Toggle all parked vehicles on
world.load_map_layer(carla.MapLayer.ParkedVehicles)
```
<button id="button1" class="CopyScript" onclick="CopyToClipboard('carla.World.load_map_layer-code')">Copy snippet</button>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<button id="button1" class="CloseSnipet" onclick="CloseSnipet()">Close snippet</button><br><br>
</div>
<div id ="carla.Map.get_waypoint-snipet" style="display: none;">
<p class="SnipetFont">
Snippet for carla.Map.get_waypoint
</p>
<div id="carla.Map.get_waypoint-code" class="SnipetContent">
```py
# This recipe shows the current traffic rules affecting the vehicle.
# Shows the current lane type and if a lane change can be done in the actual lane or the surrounding ones.
# ...
waypoint = world.get_map().get_waypoint(vehicle.get_location(),project_to_road=True, lane_type=(carla.LaneType.Driving | carla.LaneType.Shoulder | carla.LaneType.Sidewalk))
print("Current lane type: " + str(waypoint.lane_type))
# Check current lane change allowed
print("Current Lane change: " + str(waypoint.lane_change))
# Left and Right lane markings
print("L lane marking type: " + str(waypoint.left_lane_marking.type))
print("L lane marking change: " + str(waypoint.left_lane_marking.lane_change))
print("R lane marking type: " + str(waypoint.right_lane_marking.type))
print("R lane marking change: " + str(waypoint.right_lane_marking.lane_change))
# ...
```
<button id="button1" class="CopyScript" onclick="CopyToClipboard('carla.Map.get_waypoint-code')">Copy snippet</button>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<button id="button1" class="CloseSnipet" onclick="CloseSnipet()">Close snippet</button><br><br>
<img src="/img/snipets_images/carla.Map.get_waypoint.jpg">
</div>
<div id ="carla.TrafficLight.set_state-snipet" style="display: none;">
<p class="SnipetFont">
Snippet for carla.TrafficLight.set_state
</p>
<div id="carla.TrafficLight.set_state-code" class="SnipetContent">
```py
# This recipe changes from red to green the traffic light that affects the vehicle.
# This is done by detecting if the vehicle actor is at a traffic light.
# ...
world = client.get_world()
spectator = world.get_spectator()
vehicle_bp = random.choice(world.get_blueprint_library().filter('vehicle.bmw.*'))
transform = random.choice(world.get_map().get_spawn_points())
vehicle = world.try_spawn_actor(vehicle_bp, transform)
# Wait for world to get the vehicle actor
world.tick()
world_snapshot = world.wait_for_tick()
actor_snapshot = world_snapshot.find(vehicle.id)
# Set spectator at given transform (vehicle transform)
spectator.set_transform(actor_snapshot.get_transform())
# ...# ...
if vehicle_actor.is_at_traffic_light():
traffic_light = vehicle_actor.get_traffic_light()
if traffic_light.get_state() == carla.TrafficLightState.Red:
# world.hud.notification("Traffic light changed! Good to go!")
traffic_light.set_state(carla.TrafficLightState.Green)
# ...
```
<button id="button1" class="CopyScript" onclick="CopyToClipboard('carla.TrafficLight.set_state-code')">Copy snippet</button>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<button id="button1" class="CloseSnipet" onclick="CloseSnipet()">Close snippet</button><br><br>
<img src="/img/snipets_images/carla.TrafficLight.set_state.gif">
</div>
<div id ="carla.Vehicle.set_wheel_steer_direction-snipet" style="display: none;">
<p class="SnipetFont">
Snippet for carla.Vehicle.set_wheel_steer_direction
</p>
<div id="carla.Vehicle.set_wheel_steer_direction-code" class="SnipetContent">
```py
# Sets the appearance of the vehicles front wheels to 40°. Vehicle physics will not be affected.
vehicle.set_wheel_steer_direction(carla.VehicleWheelLocation.FR_Wheel, 40.0)
vehicle.set_wheel_steer_direction(carla.VehicleWheelLocation.FL_Wheel, 40.0)
```
<button id="button1" class="CopyScript" onclick="CopyToClipboard('carla.Vehicle.set_wheel_steer_direction-code')">Copy snippet</button>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<button id="button1" class="CloseSnipet" onclick="CloseSnipet()">Close snippet</button><br><br>
</div>
<div id ="carla.DebugHelper.draw_box-snipet" style="display: none;">
<p class="SnipetFont">
Snippet for carla.DebugHelper.draw_box
</p>
<div id="carla.DebugHelper.draw_box-code" class="SnipetContent">
```py
# This recipe shows how to draw traffic light actor bounding boxes from a world snapshot.
# ....
debug = world.debug
world_snapshot = world.get_snapshot()
for actor_snapshot in world_snapshot:
actual_actor = world.get_actor(actor_snapshot.id)
if actual_actor.type_id == 'traffic.traffic_light':
debug.draw_box(carla.BoundingBox(actor_snapshot.get_transform().location,carla.Vector3D(0.5,0.5,2)),actor_snapshot.get_transform().rotation, 0.05, carla.Color(255,0,0,0),0)
# ...
```
<button id="button1" class="CopyScript" onclick="CopyToClipboard('carla.DebugHelper.draw_box-code')">Copy snippet</button>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<button id="button1" class="CloseSnipet" onclick="CloseSnipet()">Close snippet</button><br><br>
<img src="/img/snipets_images/carla.DebugHelper.draw_box.jpg">
</div>
<div id ="carla.WalkerAIController.stop-snipet" style="display: none;">
<p class="SnipetFont">
Snippet for carla.WalkerAIController.stop
</p>
<div id="carla.WalkerAIController.stop-code" class="SnipetContent">
```py
#To destroy the pedestrians, stop them from the navigation, and then destroy the objects (actor and controller).
# stop pedestrians (list is [controller, actor, controller, actor ...])
for i in range(0, len(all_id), 2):
all_actors[i].stop()
# destroy pedestrian (actor and controller)
client.apply_batch([carla.command.DestroyActor(x) for x in all_id])
```
<button id="button1" class="CopyScript" onclick="CopyToClipboard('carla.WalkerAIController.stop-code')">Copy snippet</button>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<button id="button1" class="CloseSnipet" onclick="CloseSnipet()">Close snippet</button><br><br>
</div>
<div id ="carla.Client.apply_batch_sync-snipet" style="display: none;">
<p class="SnipetFont">
Snippet for carla.Client.apply_batch_sync
@ -4607,36 +4333,6 @@ for i in range(0, len(all_actors), 2):
</div>
<div id ="carla.World.enable_environment_objects-snipet" style="display: none;">
<p class="SnipetFont">
Snippet for carla.World.enable_environment_objects
</p>
<div id="carla.World.enable_environment_objects-code" class="SnipetContent">
```py
# This recipe turn visibility off and on for two specifc buildings on the map
# Get the buildings in the world
world = client.get_world()
env_objs = world.get_environment_objects(carla.CityObjectLabel.Buildings)
# Access individual building IDs and save in a set
building_01 = env_objs[0]
building_02 = env_objs[1]
objects_to_toggle = {building_01.id, building_02.id}
# Toggle buildings off
world.enable_environment_objects(objects_to_toggle, False)
# Toggle buildings on
world.enable_environment_objects(objects_to_toggle, True)
```
<button id="button1" class="CopyScript" onclick="CopyToClipboard('carla.World.enable_environment_objects-code')">Copy snippet</button>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<button id="button1" class="CloseSnipet" onclick="CloseSnipet()">Close snippet</button><br><br>
</div>
<div id ="carla.Client.__init__-snipet" style="display: none;">
<p class="SnipetFont">
Snippet for carla.Client.__init__
@ -4682,6 +4378,316 @@ Snippet for carla.Client.__init__
</div>
<div id ="carla.DebugHelper.draw_box-snipet" style="display: none;">
<p class="SnipetFont">
Snippet for carla.DebugHelper.draw_box
</p>
<div id="carla.DebugHelper.draw_box-code" class="SnipetContent">
```py
# This recipe shows how to draw traffic light actor bounding boxes from a world snapshot.
# ....
debug = world.debug
world_snapshot = world.get_snapshot()
for actor_snapshot in world_snapshot:
actual_actor = world.get_actor(actor_snapshot.id)
if actual_actor.type_id == 'traffic.traffic_light':
debug.draw_box(carla.BoundingBox(actor_snapshot.get_transform().location,carla.Vector3D(0.5,0.5,2)),actor_snapshot.get_transform().rotation, 0.05, carla.Color(255,0,0,0),0)
# ...
```
<button id="button1" class="CopyScript" onclick="CopyToClipboard('carla.DebugHelper.draw_box-code')">Copy snippet</button>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<button id="button1" class="CloseSnipet" onclick="CloseSnipet()">Close snippet</button><br><br>
<img src="/img/snipets_images/carla.DebugHelper.draw_box.jpg">
</div>
<div id ="carla.DebugHelper.draw_string-snipet" style="display: none;">
<p class="SnipetFont">
Snippet for carla.DebugHelper.draw_string
</p>
<div id="carla.DebugHelper.draw_string-code" class="SnipetContent">
```py
# This recipe is a modification of lane_explorer.py example.
# It draws the path of an actor through the world, printing information at each waypoint.
# ...
current_w = map.get_waypoint(vehicle.get_location())
while True:
next_w = map.get_waypoint(vehicle.get_location(), lane_type=carla.LaneType.Driving | carla.LaneType.Shoulder | carla.LaneType.Sidewalk )
# Check if the vehicle is moving
if next_w.id != current_w.id:
vector = vehicle.get_velocity()
# Check if the vehicle is on a sidewalk
if current_w.lane_type == carla.LaneType.Sidewalk:
draw_waypoint_union(debug, current_w, next_w, cyan if current_w.is_junction else red, 60)
else:
draw_waypoint_union(debug, current_w, next_w, cyan if current_w.is_junction else green, 60)
debug.draw_string(current_w.transform.location, str('%15.0f km/h' % (3.6 * math.sqrt(vector.x**2 + vector.y**2 + vector.z**2))), False, orange, 60)
draw_transform(debug, current_w.transform, white, 60)
# Update the current waypoint and sleep for some time
current_w = next_w
time.sleep(args.tick_time)
# ...
```
<button id="button1" class="CopyScript" onclick="CopyToClipboard('carla.DebugHelper.draw_string-code')">Copy snippet</button>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<button id="button1" class="CloseSnipet" onclick="CloseSnipet()">Close snippet</button><br><br>
</div>
<div id ="carla.Map.get_waypoint-snipet" style="display: none;">
<p class="SnipetFont">
Snippet for carla.Map.get_waypoint
</p>
<div id="carla.Map.get_waypoint-code" class="SnipetContent">
```py
# This recipe shows the current traffic rules affecting the vehicle.
# Shows the current lane type and if a lane change can be done in the actual lane or the surrounding ones.
# ...
waypoint = world.get_map().get_waypoint(vehicle.get_location(),project_to_road=True, lane_type=(carla.LaneType.Driving | carla.LaneType.Shoulder | carla.LaneType.Sidewalk))
print("Current lane type: " + str(waypoint.lane_type))
# Check current lane change allowed
print("Current Lane change: " + str(waypoint.lane_change))
# Left and Right lane markings
print("L lane marking type: " + str(waypoint.left_lane_marking.type))
print("L lane marking change: " + str(waypoint.left_lane_marking.lane_change))
print("R lane marking type: " + str(waypoint.right_lane_marking.type))
print("R lane marking change: " + str(waypoint.right_lane_marking.lane_change))
# ...
```
<button id="button1" class="CopyScript" onclick="CopyToClipboard('carla.Map.get_waypoint-code')">Copy snippet</button>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<button id="button1" class="CloseSnipet" onclick="CloseSnipet()">Close snippet</button><br><br>
<img src="/img/snipets_images/carla.Map.get_waypoint.jpg">
</div>
<div id ="carla.Sensor.listen-snipet" style="display: none;">
<p class="SnipetFont">
Snippet for carla.Sensor.listen
</p>
<div id="carla.Sensor.listen-code" class="SnipetContent">
```py
# This recipe applies a color conversion to the image taken by a camera sensor,
# so it is converted to a semantic segmentation image.
# ...
camera_bp = world.get_blueprint_library().filter('sensor.camera.semantic_segmentation')
# ...
cc = carla.ColorConverter.CityScapesPalette
camera.listen(lambda image: image.save_to_disk('output/%06d.png' % image.frame, cc))
# ...
```
<button id="button1" class="CopyScript" onclick="CopyToClipboard('carla.Sensor.listen-code')">Copy snippet</button>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<button id="button1" class="CloseSnipet" onclick="CloseSnipet()">Close snippet</button><br><br>
</div>
<div id ="carla.TrafficLight.set_state-snipet" style="display: none;">
<p class="SnipetFont">
Snippet for carla.TrafficLight.set_state
</p>
<div id="carla.TrafficLight.set_state-code" class="SnipetContent">
```py
# This recipe changes from red to green the traffic light that affects the vehicle.
# This is done by detecting if the vehicle actor is at a traffic light.
# ...
world = client.get_world()
spectator = world.get_spectator()
vehicle_bp = random.choice(world.get_blueprint_library().filter('vehicle.bmw.*'))
transform = random.choice(world.get_map().get_spawn_points())
vehicle = world.try_spawn_actor(vehicle_bp, transform)
# Wait for world to get the vehicle actor
world.tick()
world_snapshot = world.wait_for_tick()
actor_snapshot = world_snapshot.find(vehicle.id)
# Set spectator at given transform (vehicle transform)
spectator.set_transform(actor_snapshot.get_transform())
# ...# ...
if vehicle_actor.is_at_traffic_light():
traffic_light = vehicle_actor.get_traffic_light()
if traffic_light.get_state() == carla.TrafficLightState.Red:
# world.hud.notification("Traffic light changed! Good to go!")
traffic_light.set_state(carla.TrafficLightState.Green)
# ...
```
<button id="button1" class="CopyScript" onclick="CopyToClipboard('carla.TrafficLight.set_state-code')">Copy snippet</button>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<button id="button1" class="CloseSnipet" onclick="CloseSnipet()">Close snippet</button><br><br>
<img src="/img/snipets_images/carla.TrafficLight.set_state.gif">
</div>
<div id ="carla.Vehicle.set_wheel_steer_direction-snipet" style="display: none;">
<p class="SnipetFont">
Snippet for carla.Vehicle.set_wheel_steer_direction
</p>
<div id="carla.Vehicle.set_wheel_steer_direction-code" class="SnipetContent">
```py
# Sets the appearance of the vehicles front wheels to 40°. Vehicle physics will not be affected.
vehicle.set_wheel_steer_direction(carla.VehicleWheelLocation.FR_Wheel, 40.0)
vehicle.set_wheel_steer_direction(carla.VehicleWheelLocation.FL_Wheel, 40.0)
```
<button id="button1" class="CopyScript" onclick="CopyToClipboard('carla.Vehicle.set_wheel_steer_direction-code')">Copy snippet</button>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<button id="button1" class="CloseSnipet" onclick="CloseSnipet()">Close snippet</button><br><br>
</div>
<div id ="carla.WalkerAIController.stop-snipet" style="display: none;">
<p class="SnipetFont">
Snippet for carla.WalkerAIController.stop
</p>
<div id="carla.WalkerAIController.stop-code" class="SnipetContent">
```py
#To destroy the pedestrians, stop them from the navigation, and then destroy the objects (actor and controller).
# stop pedestrians (list is [controller, actor, controller, actor ...])
for i in range(0, len(all_id), 2):
all_actors[i].stop()
# destroy pedestrian (actor and controller)
client.apply_batch([carla.command.DestroyActor(x) for x in all_id])
```
<button id="button1" class="CopyScript" onclick="CopyToClipboard('carla.WalkerAIController.stop-code')">Copy snippet</button>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<button id="button1" class="CloseSnipet" onclick="CloseSnipet()">Close snippet</button><br><br>
</div>
<div id ="carla.World.enable_environment_objects-snipet" style="display: none;">
<p class="SnipetFont">
Snippet for carla.World.enable_environment_objects
</p>
<div id="carla.World.enable_environment_objects-code" class="SnipetContent">
```py
# This recipe turn visibility off and on for two specifc buildings on the map
# Get the buildings in the world
world = client.get_world()
env_objs = world.get_environment_objects(carla.CityObjectLabel.Buildings)
# Access individual building IDs and save in a set
building_01 = env_objs[0]
building_02 = env_objs[1]
objects_to_toggle = {building_01.id, building_02.id}
# Toggle buildings off
world.enable_environment_objects(objects_to_toggle, False)
# Toggle buildings on
world.enable_environment_objects(objects_to_toggle, True)
```
<button id="button1" class="CopyScript" onclick="CopyToClipboard('carla.World.enable_environment_objects-code')">Copy snippet</button>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<button id="button1" class="CloseSnipet" onclick="CloseSnipet()">Close snippet</button><br><br>
</div>
<div id ="carla.World.get_spectator-snipet" style="display: none;">
<p class="SnipetFont">
Snippet for carla.World.get_spectator
</p>
<div id="carla.World.get_spectator-code" class="SnipetContent">
```py
# This recipe spawns an actor and the spectator camera at the actor's location.
# ...
world = client.get_world()
spectator = world.get_spectator()
vehicle_bp = random.choice(world.get_blueprint_library().filter('vehicle.bmw.*'))
transform = random.choice(world.get_map().get_spawn_points())
vehicle = world.try_spawn_actor(vehicle_bp, transform)
# Wait for world to get the vehicle actor
world.tick()
world_snapshot = world.wait_for_tick()
actor_snapshot = world_snapshot.find(vehicle.id)
# Set spectator at given transform (vehicle transform)
spectator.set_transform(actor_snapshot.get_transform())
# ...
```
<button id="button1" class="CopyScript" onclick="CopyToClipboard('carla.World.get_spectator-code')">Copy snippet</button>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<button id="button1" class="CloseSnipet" onclick="CloseSnipet()">Close snippet</button><br><br>
</div>
<div id ="carla.World.load_map_layer-snipet" style="display: none;">
<p class="SnipetFont">
Snippet for carla.World.load_map_layer
</p>
<div id="carla.World.load_map_layer-code" class="SnipetContent">
```py
# This recipe toggles on several layers in our "_Opt" maps
# Load town one with only minimum layout (roads, sidewalks, traffic lights and traffic signs)
world = client.load_world('Town01_Opt', carla.MapLayer.None)
# Toggle all buildings on
world.load_map_layer(carla.MapLayer.Buildings)
# Toggle all foliage on
world.load_map_layer(carla.MapLayer.Foliage)
# Toggle all parked vehicles on
world.load_map_layer(carla.MapLayer.ParkedVehicles)
```
<button id="button1" class="CopyScript" onclick="CopyToClipboard('carla.World.load_map_layer-code')">Copy snippet</button>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<button id="button1" class="CloseSnipet" onclick="CloseSnipet()">Close snippet</button><br><br>
</div>
<div id ="carla.World.spawn_actor-snipet" style="display: none;">
<p class="SnipetFont">
Snippet for carla.World.spawn_actor
@ -4707,6 +4713,32 @@ lane_invasion_sensor = world.spawn_actor(sensor_lane_invasion_bp, transform, att
</div>
<div id ="carla.World.unload_map_layer-snipet" style="display: none;">
<p class="SnipetFont">
Snippet for carla.World.unload_map_layer
</p>
<div id="carla.World.unload_map_layer-code" class="SnipetContent">
```py
# This recipe toggles off several layers in our "_Opt" maps
# Load town one with minimum layout (roads, sidewalks, traffic lights and traffic signs)
# as well as buildings and parked vehicles
world = client.load_world('Town01_Opt', carla.MapLayer.Buildings | carla.MapLayer.ParkedVehicles)
# Toggle all buildings off
world.unload_map_layer(carla.MapLayer.Buildings)
# Toggle all parked vehicles off
world.unload_map_layer(carla.MapLayer.ParkedVehicles)
```
<button id="button1" class="CopyScript" onclick="CopyToClipboard('carla.World.unload_map_layer-code')">Copy snippet</button>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<button id="button1" class="CloseSnipet" onclick="CloseSnipet()">Close snippet</button><br><br>
</div>
</div>

View File

@ -35,6 +35,16 @@ namespace client {
DrawShape(_episode, point, color, life_time, persistent_lines);
}
void DebugHelper::DrawHUDPoint(
const geom::Location &location,
float size,
sensor::data::Color color,
float life_time,
bool persistent_lines) {
Shape::HUDPoint point{location, size};
DrawShape(_episode, point, color, life_time, persistent_lines);
}
void DebugHelper::DrawLine(
const geom::Location &begin,
const geom::Location &end,
@ -46,6 +56,17 @@ namespace client {
DrawShape(_episode, line, color, life_time, persistent_lines);
}
void DebugHelper::DrawHUDLine(
const geom::Location &begin,
const geom::Location &end,
float thickness,
Color color,
float life_time,
bool persistent_lines) {
Shape::HUDLine line{begin, end, thickness};
DrawShape(_episode, line, color, life_time, persistent_lines);
}
void DebugHelper::DrawArrow(
const geom::Location &begin,
const geom::Location &end,
@ -59,6 +80,19 @@ namespace client {
DrawShape(_episode, arrow, color, life_time, persistent_lines);
}
void DebugHelper::DrawHUDArrow(
const geom::Location &begin,
const geom::Location &end,
float thickness,
float arrow_size,
sensor::data::Color color,
float life_time,
bool persistent_lines) {
Shape::HUDLine line{begin, end, thickness};
Shape::HUDArrow arrow{line, arrow_size};
DrawShape(_episode, arrow, color, life_time, persistent_lines);
}
void DebugHelper::DrawBox(
const geom::BoundingBox &box,
const geom::Rotation &rotation,
@ -70,6 +104,17 @@ namespace client {
DrawShape(_episode, the_box, color, life_time, persistent_lines);
}
void DebugHelper::DrawHUDBox(
const geom::BoundingBox &box,
const geom::Rotation &rotation,
float thickness,
sensor::data::Color color,
float life_time,
bool persistent_lines) {
Shape::HUDBox the_box{box, rotation, thickness};
DrawShape(_episode, the_box, color, life_time, persistent_lines);
}
void DebugHelper::DrawString(
const geom::Location &location,
const std::string &text,

View File

@ -30,6 +30,13 @@ namespace client {
float life_time = -1.0f,
bool persistent_lines = true);
void DrawHUDPoint(
const geom::Location &location,
float size = 0.1f,
Color color = Color{255u, 0u, 0u},
float life_time = -1.0f,
bool persistent_lines = true);
void DrawLine(
const geom::Location &begin,
const geom::Location &end,
@ -38,6 +45,14 @@ namespace client {
float life_time = -1.0f,
bool persistent_lines = true);
void DrawHUDLine(
const geom::Location &begin,
const geom::Location &end,
float thickness = 1.0f,
Color color = Color{225u, 0u, 0u},
float life_time = -1.0f,
bool presistent_lines = true);
void DrawArrow(
const geom::Location &begin,
const geom::Location &end,
@ -47,6 +62,15 @@ namespace client {
float life_time = -1.0f,
bool persistent_lines = true);
void DrawHUDArrow(
const geom::Location &begin,
const geom::Location &end,
float thickness = 0.1f,
float arrow_size = 0.1f,
Color color = Color{255u, 0u, 0u},
float life_time = -1.0f,
bool persistent_lines = true);
void DrawBox(
const geom::BoundingBox &box,
const geom::Rotation &rotation,
@ -55,6 +79,14 @@ namespace client {
float life_time = -1.0f,
bool persistent_lines = true);
void DrawHUDBox(
const geom::BoundingBox &box,
const geom::Rotation &rotation,
float thickness = 0.1f,
Color color = Color{255u, 0u, 0u},
float life_time = -1.0f,
bool persistent_lines = true);
void DrawString(
const geom::Location &location,
const std::string &text,

View File

@ -35,6 +35,12 @@ namespace rpc {
MSGPACK_DEFINE_ARRAY(location, size);
};
struct HUDPoint {
geom::Location location;
float size;
MSGPACK_DEFINE_ARRAY(location, size);
};
struct Line {
geom::Location begin;
geom::Location end;
@ -42,12 +48,25 @@ namespace rpc {
MSGPACK_DEFINE_ARRAY(begin, end, thickness);
};
struct HUDLine {
geom::Location begin;
geom::Location end;
float thickness;
MSGPACK_DEFINE_ARRAY(begin, end, thickness);
};
struct Arrow {
Line line;
float arrow_size;
MSGPACK_DEFINE_ARRAY(line, arrow_size);
};
struct HUDArrow {
HUDLine line;
float arrow_size;
MSGPACK_DEFINE_ARRAY(line, arrow_size);
};
struct Box {
geom::BoundingBox box;
geom::Rotation rotation;
@ -55,6 +74,13 @@ namespace rpc {
MSGPACK_DEFINE_ARRAY(box, rotation, thickness);
};
struct HUDBox {
geom::BoundingBox box;
geom::Rotation rotation;
float thickness;
MSGPACK_DEFINE_ARRAY(box, rotation, thickness);
};
struct String {
geom::Location location;
std::string text;
@ -62,7 +88,7 @@ namespace rpc {
MSGPACK_DEFINE_ARRAY(location, text, draw_shadow);
};
boost::variant2::variant<Point, Line, Arrow, Box, String> primitive;
boost::variant2::variant<Point, Line, Arrow, Box, String, HUDPoint, HUDLine, HUDArrow, HUDBox> primitive;
Color color = {255u, 0u, 0u};

View File

@ -374,6 +374,12 @@ void export_world() {
arg("color")=cc::DebugHelper::Color(255u, 0u, 0u),
arg("life_time")=-1.0f,
arg("persistent_lines")=true))
.def("draw_hud_point", &cc::DebugHelper::DrawHUDPoint,
(arg("location"),
arg("size")=0.1f,
arg("color")=cc::DebugHelper::Color(255u, 0u, 0u),
arg("life_time")=-1.0f,
arg("persistent_lines")=true))
.def("draw_line", &cc::DebugHelper::DrawLine,
(arg("begin"),
arg("end"),
@ -381,6 +387,13 @@ void export_world() {
arg("color")=cc::DebugHelper::Color(255u, 0u, 0u),
arg("life_time")=-1.0f,
arg("persistent_lines")=true))
.def("draw_hud_line", &cc::DebugHelper::DrawHUDLine,
(arg("begin"),
arg("end"),
arg("thickness")=0.1f,
arg("color")=cc::DebugHelper::Color(255u, 0u, 0u),
arg("life_time")=-1.0f,
arg("persistent_lines")=true))
.def("draw_arrow", &cc::DebugHelper::DrawArrow,
(arg("begin"),
arg("end"),
@ -389,6 +402,14 @@ void export_world() {
arg("color")=cc::DebugHelper::Color(255u, 0u, 0u),
arg("life_time")=-1.0f,
arg("persistent_lines")=true))
.def("draw_hud_arrow", &cc::DebugHelper::DrawHUDArrow,
(arg("begin"),
arg("end"),
arg("thickness")=0.1f,
arg("arrow_size")=0.1f,
arg("color")=cc::DebugHelper::Color(255u, 0u, 0u),
arg("life_time")=-1.0f,
arg("persistent_lines")=true))
.def("draw_box", &cc::DebugHelper::DrawBox,
(arg("box"),
arg("rotation"),
@ -396,6 +417,13 @@ void export_world() {
arg("color")=cc::DebugHelper::Color(255u, 0u, 0u),
arg("life_time")=-1.0f,
arg("persistent_lines")=true))
.def("draw_hud_box", &cc::DebugHelper::DrawHUDBox,
(arg("box"),
arg("rotation"),
arg("thickness")=0.1f,
arg("color")=cc::DebugHelper::Color(255u, 0u, 0u),
arg("life_time")=-1.0f,
arg("persistent_lines")=true))
.def("draw_string", &cc::DebugHelper::DrawString,
(arg("location"),
arg("text"),
@ -404,4 +432,6 @@ void export_world() {
arg("life_time")=-1.0f,
arg("persistent_lines")=true))
;
// scope HUD = class_<cc::DebugHelper>(
}

View File

@ -993,7 +993,139 @@
doc: >
Shape's lifespan. By default it only lasts one frame. Set this to <code>0</code> for permanent shapes.
doc: >
Draws a box, ussually to act for object colliders.
Draws a box, usually to act for object colliders.
# --------------------------------------
- def_name: draw_hud_arrow
params:
- param_name: begin
type: carla.Location
param_units: meters
doc: >
Point in the coordinate system where the arrow starts.
- param_name: end
type: carla.Location
param_units: meters
doc: >
Point in the coordinate system where the arrow ends and points towards to.
- param_name: thickness
type: float
default: 0.1
param_units: meters
doc: >
Density of the line.
- param_name: arrow_size
type: float
default: 0.1
param_units: meters
doc: >
Size of the tip of the arrow.
- param_name: color
type: carla.Color
default: (255,0,0)
doc: >
RGB code to color the object. Red by default.
- param_name: life_time
type: float
default: -1.0
param_units: seconds
doc: >
Shape's lifespan. By default it only lasts one frame. Set this to <code>0</code> for permanent shapes.
doc: >
Draws an arrow on the HUD from `begin` to `end` which can only be seen server-side.
# --------------------------------------
- def_name: draw_hud_box
params:
- param_name: box
type: carla.BoundingBox
doc: >
Object containing a location and the length of a box for every axis.
- param_name: rotation
type: carla.Rotation
param_units: degrees (pitch,yaw,roll)
doc: >
Orientation of the box according to Unreal Engine's axis system.
- param_name: thickness
type: float
default: 0.1
param_units: meters
doc: >
Density of the lines that define the box.
- param_name: color
type: carla.Color
default: (255,0,0)
doc: >
RGB code to color the object. Red by default.
- param_name: life_time
type: float
default: -1.0
param_units: seconds
doc: >
Shape's lifespan. By default it only lasts one frame. Set this to <code>0</code> for permanent shapes.
doc: >
Draws a box on the HUD, usually to act for object colliders. The box can only be seen server-side.
# --------------------------------------
- def_name: draw_hud_line
params:
- param_name: begin
type: carla.Location
param_units: meters
doc: >
Point in the coordinate system where the line starts.
- param_name: end
type: carla.Location
param_units: meters
doc: >
Spot in the coordinate system where the line ends.
- param_name: thickness
type: float
default: 0.1
param_units: meters
doc: >
Density of the line.
- param_name: color
type: carla.Color
default: (255,0,0)
doc: >
RGB code to color the object. Red by default.
- param_name: life_time
type: float
default: -1.0
param_units: seconds
doc: >
Shape's lifespan. By default it only lasts one frame. Set this to <code>0</code> for permanent shapes.
doc: >
Draws a line on the HUD in between `begin` and `end`. The line can only be seen server-side.
# --------------------------------------
- def_name: draw_hud_point
params:
- param_name: location
type: carla.Location
param_units: meters
doc: >
Spot in the coordinate system to center the object.
- param_name: size
type: float
default: 0.1
param_units: meters
doc: >
Density of the point.
- param_name: color
type: carla.Color
default: (255,0,0)
doc: >
RGB code to color the object. Red by default.
- param_name: life_time
type: float
default: -1.0
param_units: seconds
doc: >
Shape's lifespan. By default it only lasts one frame. Set this to <code>0</code> for permanent shapes.
doc: >
Draws a point on the HUD at `location`. The point can only be seen server-side.
# --------------------------------------
- def_name: draw_line

View File

@ -33,7 +33,6 @@ void ACarlaHUD::DrawHUD()
FVector2D Screen;
if (Player->ProjectWorldLocationToScreen(StringList[i].Location, Screen, true))
{
// draw text
DrawText(StringList[i].Str, StringList[i].Color, Screen.X, Screen.Y);
}
@ -45,6 +44,25 @@ void ACarlaHUD::DrawHUD()
else
++i;
}
while (i < LineList.Num())
{
// project position from camera
FVector2D Begin, End;
if (Player->ProjectWorldLocationToScreen(LineList[i].Begin, Begin, true) &&
Player->ProjectWorldLocationToScreen(LineList[i].End, End, true))
{
DrawLine(Begin.X, Begin.Y, End.X, End.Y, LineList[i].Color, LineList[i].Thickness);
}
// check to remove the string
if (Now >= LineList[i].TimeToDie)
{
LineList.RemoveAt(i);
}
else
++i;
}
}
void ACarlaHUD::AddHUDString(const FString Str, const FVector Location, const FColor Color, double LifeTime)
@ -53,3 +71,10 @@ void ACarlaHUD::AddHUDString(const FString Str, const FVector Location, const FC
HUDString Obj { Str, Location, Color, Now + LifeTime };
StringList.Add(std::move(Obj));
}
void ACarlaHUD::AddHUDLine(const FVector Begin, const FVector End, const float Thickness, const FColor Color, double LifeTime)
{
double Now = FPlatformTime::Seconds();
HUDLine Obj { Begin, End, Thickness, Color, Now + LifeTime };
LineList.Add(std::move(Obj));
}

View File

@ -35,6 +35,15 @@ struct HUDString
double TimeToDie;
};
struct HUDLine
{
FVector Begin;
FVector End;
float Thickness;
FColor Color;
double TimeToDie;
};
/// Class to draw on HUD
UCLASS()
class CARLA_API ACarlaHUD : public AHUD
@ -55,7 +64,9 @@ public:
void AddDebugVehicleForTelemetry(UWheeledVehicleMovementComponent* Veh) { DebugVehicle = Veh; }
void AddHUDString(const FString Str, const FVector Location, const FColor Color, double LifeTime);
void AddHUDLine(const FVector Begin, const FVector End, const float Thickness, const FColor Color, double LifeTime);
private:
TArray<HUDString> StringList;
TArray<HUDLine> LineList;
};

View File

@ -33,6 +33,17 @@ struct FShapeVisitor
World->PersistentLineBatcher->SetCollisionEnabled(ECollisionEnabled::NoCollision);
}
ACarlaHUD * GetHUD() const {
auto PlayerController = UGameplayStatics::GetPlayerController(World, 0);
if (PlayerController == nullptr)
{
UE_LOG(LogCarla, Error, TEXT("Can't find player controller!"));
return nullptr;
}
ACarlaHUD *Hud = Cast<ACarlaHUD>(PlayerController->GetHUD());
return Hud;
}
void operator()(const Shape::Point &Point) const
{
FVector Location = FVector(Point.location);
@ -49,6 +60,20 @@ struct FShapeVisitor
LifeTime);
}
void operator()(const Shape::HUDPoint &Point) const
{
auto Hud = GetHUD();
if (!Hud) return; // Don't draw if HUD is not available.
FVector Location = FVector(Point.location);
ALargeMapManager* LargeMap = UCarlaStatics::GetLargeMapManager(World);
if (LargeMap)
{
Location = LargeMap->GlobalToLocalLocation(Location);
}
Hud->AddHUDLine(Location, Location, Point.size, Color.Quantize(), LifeTime);
}
void operator()(const Shape::Line &Line) const
{
FVector Begin = FVector(Line.begin);
@ -68,6 +93,20 @@ struct FShapeVisitor
LifeTime);
}
void operator()(const Shape::HUDLine &Line) const {
auto Hud = GetHUD();
if (!Hud) return; // Don't draw if HUD is not available.
FVector Begin = FVector(Line.begin);
FVector End = FVector(Line.end);
ALargeMapManager* LargeMap = UCarlaStatics::GetLargeMapManager(World);
if (LargeMap)
{
Begin = LargeMap->GlobalToLocalLocation(Begin);
End = LargeMap->GlobalToLocalLocation(End);
}
Hud->AddHUDLine(Begin, End, Line.thickness, Color.Quantize(), LifeTime);
}
void operator()(const Shape::Arrow &Arrow) const
{
FVector Begin = FVector(Arrow.line.begin);
@ -90,40 +129,55 @@ struct FShapeVisitor
World->PersistentLineBatcher->DrawLines(TArray<FBatchedLine>({
FBatchedLine(
Begin,
End,
Color,
LifeTime,
Thickness,
DepthPriority),
Begin, End, Color, LifeTime, Thickness, DepthPriority),
FBatchedLine(
Transform.TransformPosition(FVector(ArrowTipDist, +ArrowSize, +ArrowSize)),
End,
Color,
LifeTime,
Thickness,
DepthPriority),
End, Color, LifeTime, Thickness, DepthPriority),
FBatchedLine(
Transform.TransformPosition(FVector(ArrowTipDist, +ArrowSize, -ArrowSize)),
End,
Color,
LifeTime,
Thickness,
DepthPriority),
End, Color, LifeTime, Thickness, DepthPriority),
FBatchedLine(
Transform.TransformPosition(FVector(ArrowTipDist, -ArrowSize, +ArrowSize)),
End,
Color,
LifeTime,
Thickness,
DepthPriority),
End, Color, LifeTime, Thickness, DepthPriority),
FBatchedLine(
Transform.TransformPosition(FVector(ArrowTipDist, -ArrowSize, -ArrowSize)),
End,
Color,
LifeTime,
Thickness,
DepthPriority)}));
End, Color, LifeTime, Thickness, DepthPriority)}));
}
void operator()(const Shape::HUDArrow &Arrow) const {
auto Hud = GetHUD();
if (!Hud) return; // Don't draw if HUD is not available.
FVector Begin = FVector(Arrow.line.begin);
FVector End = FVector(Arrow.line.end);
ALargeMapManager* LargeMap = UCarlaStatics::GetLargeMapManager(World);
if (LargeMap)
{
Begin = LargeMap->GlobalToLocalLocation(Begin);
End = LargeMap->GlobalToLocalLocation(End);
}
const auto Diff = End - Begin;
const FRotator LookAt = FRotationMatrix::MakeFromX(Diff).Rotator();
const FTransform Transform = {LookAt, Begin};
// Everything in centimeters
const auto Dist = Diff.Size();
const auto ArrowSize = Arrow.arrow_size;
const auto ArrowTipDist = Dist - ArrowSize;
const auto Thickness = Arrow.line.thickness;
Hud->AddHUDLine(Begin, End, Thickness, Color.Quantize(), LifeTime);
Hud->AddHUDLine(
Transform.TransformPosition(FVector(ArrowTipDist, +ArrowSize, +ArrowSize)),
End, Thickness, Color.Quantize(), LifeTime);
Hud->AddHUDLine(
Transform.TransformPosition(FVector(ArrowTipDist, +ArrowSize, -ArrowSize)),
End, Thickness, Color.Quantize(), LifeTime);
Hud->AddHUDLine(
Transform.TransformPosition(FVector(ArrowTipDist, -ArrowSize, +ArrowSize)),
End, Thickness, Color.Quantize(), LifeTime);
Hud->AddHUDLine(
Transform.TransformPosition(FVector(ArrowTipDist, -ArrowSize, -ArrowSize)),
End, Thickness, Color.Quantize(), LifeTime);
}
void operator()(const Shape::Box &Box) const
@ -146,66 +200,79 @@ struct FShapeVisitor
{
for(int32 j = 0; j < 2; ++j)
{
P.X=B[i].X;
Q.X=B[i].X;
P.Y=B[j].Y;
Q.Y=B[j].Y;
P.Z=B[0].Z;
Q.Z=B[1].Z;
P.X=B[i].X; Q.X=B[i].X; P.Y=B[j].Y;
Q.Y=B[j].Y; P.Z=B[0].Z; Q.Z=B[1].Z;
World->PersistentLineBatcher->DrawLine(
Transform.TransformPosition(P),
Transform.TransformPosition(Q),
Color,
DepthPriority,
Thickness,
LifeTime);
Transform.TransformPosition(P), Transform.TransformPosition(Q),
Color, DepthPriority, Thickness, LifeTime);
P.Y=B[i].Y;
Q.Y=B[i].Y;
P.Z=B[j].Z;
Q.Z=B[j].Z;
P.X=B[0].X;
Q.X=B[1].X;
P.Y=B[i].Y; Q.Y=B[i].Y; P.Z=B[j].Z;
Q.Z=B[j].Z; P.X=B[0].X; Q.X=B[1].X;
World->PersistentLineBatcher->DrawLine(
Transform.TransformPosition(P),
Transform.TransformPosition(Q),
Color,
DepthPriority,
Thickness,
LifeTime);
Transform.TransformPosition(P), Transform.TransformPosition(Q),
Color, DepthPriority, Thickness, LifeTime);
P.Z=B[i].Z;
Q.Z=B[i].Z;
P.X=B[j].X;
Q.X=B[j].X;
P.Y=B[0].Y;
Q.Y=B[1].Y;
P.Z=B[i].Z; Q.Z=B[i].Z; P.X=B[j].X;
Q.X=B[j].X; P.Y=B[0].Y; Q.Y=B[1].Y;
World->PersistentLineBatcher->DrawLine(
Transform.TransformPosition(P),
Transform.TransformPosition(Q),
Color,
DepthPriority,
Thickness,
LifeTime);
Transform.TransformPosition(P), Transform.TransformPosition(Q),
Color, DepthPriority, Thickness, LifeTime);
}
}
}
void operator()(const Shape::HUDBox &Box) const {
auto Hud = GetHUD();
if (!Hud) return; // Don't draw if HUD is not available.
const FVector Extent = 1e2f * FVector{Box.box.extent.x, Box.box.extent.y, Box.box.extent.z};
FTransform Transform = {FRotator(Box.rotation), Box.box.location};
const auto Thickness = Box.thickness;
ALargeMapManager* LargeMap = UCarlaStatics::GetLargeMapManager(World);
if (LargeMap)
{
Transform = LargeMap->GlobalToLocalTransform(Transform);
}
FVector B[2], P, Q;
B[0] = -Extent;
B[1] = Extent;
for(int32 i = 0; i < 2; ++i)
{
for(int32 j = 0; j < 2; ++j)
{
P.X=B[i].X; Q.X=B[i].X; P.Y=B[j].Y;
Q.Y=B[j].Y; P.Z=B[0].Z; Q.Z=B[1].Z;
Hud->AddHUDLine(
Transform.TransformPosition(P), Transform.TransformPosition(Q),
Thickness, Color.Quantize(), LifeTime);
P.Y=B[i].Y; Q.Y=B[i].Y; P.Z=B[j].Z;
Q.Z=B[j].Z; P.X=B[0].X; Q.X=B[1].X;
Hud->AddHUDLine(
Transform.TransformPosition(P), Transform.TransformPosition(Q),
Thickness, Color.Quantize(), LifeTime);
P.Z=B[i].Z; Q.Z=B[i].Z; P.X=B[j].X;
Q.X=B[j].X; P.Y=B[0].Y; Q.Y=B[1].Y;
Hud->AddHUDLine(
Transform.TransformPosition(P), Transform.TransformPosition(Q),
Thickness, Color.Quantize(), LifeTime);
}
}
}
void operator()(const Shape::String &Str) const
{
auto PlayerController = UGameplayStatics::GetPlayerController(World, 0);
if (PlayerController == nullptr)
{
UE_LOG(LogCarla, Error, TEXT("Can't find player controller!"));
return;
}
auto Hud = GetHUD();
if (!Hud) return;
FVector Location = FVector(Str.location);
ALargeMapManager* LargeMap = UCarlaStatics::GetLargeMapManager(World);
if (LargeMap)
{
Location = LargeMap->GlobalToLocalLocation(Location);
}
ACarlaHUD *Hud = Cast<ACarlaHUD>(PlayerController->GetHUD());
Hud->AddHUDString(carla::rpc::ToFString(Str.text), Location, Color.Quantize(), LifeTime);
}