diff --git a/roadscore/tests/test_native_hud_layout.py b/roadscore/tests/test_native_hud_layout.py new file mode 100644 index 0000000000..431ae1b038 --- /dev/null +++ b/roadscore/tests/test_native_hud_layout.py @@ -0,0 +1,20 @@ +"""Verify safety-icon spacing without opening native UI or device libraries.""" +import math +import sys +import unittest +from pathlib import Path +sys.path.insert(0, str(Path(__file__).resolve().parents[2] / 'selfdrive/ui/mici/onroad')) +from hud_layout import steering_warning_rect + + +class SafetyIconLayoutTests(unittest.TestCase): + def test_warning_follows_wheel_edge_instead_of_overlapping_it(self): + self.assertEqual(steering_warning_rect(46, 201, 50, 50, 0, 44, 44), (81, 179, 44, 44)) + + def test_warning_clears_rotated_wheel_at_every_steering_angle(self): + for angle in range(-180, 181, 5): + x, y, w, h = steering_warning_rect(46, 201, 50, 50, angle, 44, 44) + corners = [46 + dx * math.cos(math.radians(angle)) - dy * math.sin(math.radians(angle)) + for dx in (-25, 25) for dy in (-25, 25)] + self.assertGreaterEqual(x - max(corners), 9.999) + self.assertEqual((y, w, h), (179, 44, 44)) diff --git a/selfdrive/ui/mici/onroad/hud_layout.py b/selfdrive/ui/mici/onroad/hud_layout.py new file mode 100644 index 0000000000..a2e029f558 --- /dev/null +++ b/selfdrive/ui/mici/onroad/hud_layout.py @@ -0,0 +1,9 @@ +"""Pure geometry for native HUD icon groups.""" +import math + + +def steering_warning_rect(center_x, center_y, wheel_width, wheel_height, rotation, warning_width, warning_height, gap=10): + """Keep the unrotated warning clear of the steering wheel at any angle.""" + angle = math.radians(rotation) + rotated_half_width = (wheel_width * abs(math.cos(angle)) + wheel_height * abs(math.sin(angle))) / 2 + return (center_x + rotated_half_width + gap, center_y - warning_height / 2, warning_width, warning_height) diff --git a/selfdrive/ui/mici/onroad/hud_renderer.py b/selfdrive/ui/mici/onroad/hud_renderer.py index b48020759d..75bbcd018b 100644 --- a/selfdrive/ui/mici/onroad/hud_renderer.py +++ b/selfdrive/ui/mici/onroad/hud_renderer.py @@ -2,6 +2,7 @@ import math import pyray as rl from dataclasses import dataclass +from openpilot.selfdrive.ui.mici.onroad.hud_layout import steering_warning_rect from openpilot.common.constants import CV from openpilot.selfdrive.ui.onroad.starpilot.torque_bar import TorqueBar from openpilot.selfdrive.ui.onroad.starpilot.rivian_lateral_mode import rivian_lateral_mode @@ -405,9 +406,10 @@ class HudRenderer(Widget): if self._show_wheel_critical: # Draw exclamation point icon - EXCLAMATION_POINT_SPACING = 10 - exclamation_pos_x = pos_x - self._txt_exclamation_point.width / 2 + wheel_txt.width / 2 + EXCLAMATION_POINT_SPACING - exclamation_pos_y = pos_y - self._txt_exclamation_point.height / 2 + exclamation_pos_x, exclamation_pos_y, _, _ = steering_warning_rect( + pos_x, pos_y, wheel_txt.width, wheel_txt.height, rotation, + self._txt_exclamation_point.width, self._txt_exclamation_point.height, + ) rl.draw_texture(self._txt_exclamation_point, int(exclamation_pos_x), int(exclamation_pos_y), rl.WHITE) def _draw_set_speed(self, rect: rl.Rectangle) -> None: