mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-07-20 08:42:11 +08:00
fixes and Themes
This commit is contained in:
Binary file not shown.
@@ -316,11 +316,13 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"LaneChanges", {PERSISTENT, BOOL, "1", "1", 0}},
|
||||
{"LaneChangeTime", {PERSISTENT, FLOAT, "1.0", "0.0", 1}},
|
||||
{"LaneDetectionWidth", {PERSISTENT, FLOAT, "0.0", "0.0", 1}},
|
||||
{"LaneLinesColor", {PERSISTENT, STRING, "", "", 2}},
|
||||
{"LaneLinesWidth", {PERSISTENT, FLOAT, "4.0", "2.0", 2}},
|
||||
{"LastMapsUpdate", {PERSISTENT, STRING, "", ""}},
|
||||
{"LateralTune", {PERSISTENT, BOOL, "1", "0", 1}},
|
||||
{"LeadDepartingAlert", {PERSISTENT, BOOL, "0", "0", 0}},
|
||||
{"LeadDetectionThreshold", {PERSISTENT, INT, "35", "50", 3}},
|
||||
{"LeadIndicator", {PERSISTENT, BOOL, "1", "1", 2}},
|
||||
{"LeadInfo", {PERSISTENT, BOOL, "1", "0", 3}},
|
||||
{"LKASButtonControl", {PERSISTENT, INT, "5", "0", 2}},
|
||||
{"LockDoors", {PERSISTENT, BOOL, "1", "0", 0}},
|
||||
@@ -383,6 +385,8 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"OnroadDistanceButtonPressed", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
|
||||
{"openpilotMinutes", {PERSISTENT, INT, "0", "0", 0}},
|
||||
{"OverpassRequests", {PERSISTENT, JSON, "{}", "{}"}},
|
||||
{"PathColor", {PERSISTENT, STRING, "", "", 2}},
|
||||
{"PathEdgesColor", {PERSISTENT, STRING, "", "", 2}},
|
||||
{"PathEdgeWidth", {PERSISTENT, FLOAT, "20.0", "0.0", 2}},
|
||||
{"PathWidth", {PERSISTENT, FLOAT, "6.1", "5.9", 2}},
|
||||
{"PauseAOLOnBrake", {PERSISTENT, BOOL, "0", "0", 1}},
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,2 +1,2 @@
|
||||
extern const uint8_t gitversion[19];
|
||||
const uint8_t gitversion[19] = "DEV-ee3f32ad-DEBUG";
|
||||
const uint8_t gitversion[19] = "DEV-392d38c5-DEBUG";
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
DEV-ee3f32ad-DEBUG
|
||||
DEV-392d38c5-DEBUG
|
||||
Binary file not shown.
@@ -26,6 +26,30 @@ _THEME_COLOR_CACHE: dict[str, object] = {
|
||||
}
|
||||
|
||||
|
||||
def _as_color(value: object, fallback: tuple[int, int, int, int] = (255, 255, 255, 255)) -> rl.Color:
|
||||
if all(hasattr(value, channel) for channel in ("r", "g", "b", "a")):
|
||||
return rl.Color(
|
||||
_clamp_channel(getattr(value, "r"), fallback[0]),
|
||||
_clamp_channel(getattr(value, "g"), fallback[1]),
|
||||
_clamp_channel(getattr(value, "b"), fallback[2]),
|
||||
_clamp_channel(getattr(value, "a"), fallback[3]),
|
||||
)
|
||||
|
||||
if isinstance(value, (tuple, list)):
|
||||
items = list(value)
|
||||
if len(items) == 3:
|
||||
items.append(fallback[3])
|
||||
if len(items) >= 4:
|
||||
return rl.Color(
|
||||
_clamp_channel(items[0], fallback[0]),
|
||||
_clamp_channel(items[1], fallback[1]),
|
||||
_clamp_channel(items[2], fallback[2]),
|
||||
_clamp_channel(items[3], fallback[3]),
|
||||
)
|
||||
|
||||
return rl.Color(*fallback)
|
||||
|
||||
|
||||
def _file_stamp(path: Path) -> tuple[str, int | None, int | None]:
|
||||
try:
|
||||
stat = path.stat()
|
||||
@@ -84,9 +108,43 @@ def _load_theme_colors() -> dict[str, rl.Color]:
|
||||
def get_theme_color(key: str, fallback: rl.Color | None = None) -> rl.Color:
|
||||
color = _load_theme_colors().get(key)
|
||||
if color is not None:
|
||||
return color
|
||||
return fallback if fallback is not None else rl.WHITE
|
||||
return _as_color(color)
|
||||
return _as_color(fallback if fallback is not None else rl.WHITE)
|
||||
|
||||
|
||||
def get_param_color(params, key: str, fallback_alpha: int = 255) -> rl.Color | None:
|
||||
value = params.get(key, encoding="utf-8") if params is not None else None
|
||||
if not value:
|
||||
return None
|
||||
|
||||
color = value.strip()
|
||||
if not color or color.lower() == "stock":
|
||||
return None
|
||||
if color.startswith("#"):
|
||||
color = color[1:]
|
||||
|
||||
if len(color) not in (6, 8):
|
||||
return None
|
||||
|
||||
try:
|
||||
red = int(color[0:2], 16)
|
||||
green = int(color[2:4], 16)
|
||||
blue = int(color[4:6], 16)
|
||||
alpha = int(color[6:8], 16) if len(color) == 8 else fallback_alpha
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
return rl.Color(red, green, blue, alpha)
|
||||
|
||||
|
||||
def get_visual_color(params, param_key: str, theme_key: str, fallback: rl.Color | None = None) -> rl.Color:
|
||||
base = _as_color(fallback if fallback is not None else rl.WHITE)
|
||||
override = get_param_color(params, param_key, base.a)
|
||||
if override is not None:
|
||||
return override
|
||||
return get_theme_color(theme_key, base)
|
||||
|
||||
|
||||
def with_alpha(color: rl.Color, alpha: int) -> rl.Color:
|
||||
color = _as_color(color)
|
||||
return rl.Color(color.r, color.g, color.b, max(0, min(255, int(alpha))))
|
||||
|
||||
@@ -14,3 +14,13 @@ def get_border_width(base_width: int, params: Params | None = None) -> int:
|
||||
scale = min(250.0, max(25.0, scale))
|
||||
|
||||
return max(1, int(round(base_width * scale / 100.0)))
|
||||
|
||||
|
||||
def lead_indicator_enabled(params: Params | None = None) -> bool:
|
||||
active_params = params if params is not None else Params()
|
||||
|
||||
enabled = not active_params.get_bool("HideLeadMarker", default=False)
|
||||
if active_params.get("LeadIndicator") is not None:
|
||||
enabled = enabled and active_params.get_bool("LeadIndicator", default=True)
|
||||
|
||||
return enabled
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.selfdrive.ui.mici.widgets.button import BigButton, BigParamControl
|
||||
from openpilot.selfdrive.ui.lib.starpilot_visuals import lead_indicator_enabled
|
||||
from openpilot.selfdrive.ui.mici.widgets.button import BigButton, BigParamControl, BigToggle
|
||||
from openpilot.selfdrive.ui.mici.widgets.dialog import BigDialog, BigMultiOptionDialog
|
||||
from openpilot.system.ui.lib.application import gui_app
|
||||
from openpilot.system.ui.widgets.scroller import NavScroller
|
||||
@@ -38,12 +39,29 @@ class CameraViewBigButton(BigButton):
|
||||
gui_app.push_widget(dialog)
|
||||
|
||||
|
||||
class LeadIndicatorBigButton(BigToggle):
|
||||
def __init__(self):
|
||||
super().__init__("lead indicator")
|
||||
self.params = Params()
|
||||
self.refresh()
|
||||
|
||||
def _handle_mouse_release(self, mouse_pos):
|
||||
super()._handle_mouse_release(mouse_pos)
|
||||
self.params.put_bool("LeadIndicator", self._checked)
|
||||
self.params.put_bool("HideLeadMarker", not self._checked)
|
||||
|
||||
def refresh(self):
|
||||
self.set_checked(lead_indicator_enabled(self.params))
|
||||
|
||||
|
||||
class VisualsLayoutMici(NavScroller):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._camera_view_btn = CameraViewBigButton()
|
||||
self._driver_camera_btn = BigParamControl("driver camera on reverse", "DriverCamera")
|
||||
self._stopped_timer_btn = BigParamControl("stopped timer", "StoppedTimer")
|
||||
self._rainbow_path_btn = BigParamControl("rainbow road", "RainbowPath")
|
||||
self._lead_indicator_btn = LeadIndicatorBigButton()
|
||||
self._speed_limit_signs_btn = BigParamControl("speed limit signs", "ShowSpeedLimits")
|
||||
self._slc_confirmation_btn = BigParamControl("confirm new speed limits", "SLCConfirmation")
|
||||
self._slc_confirmation_lower_btn = BigParamControl("confirm lower limits", "SLCConfirmationLower")
|
||||
@@ -53,6 +71,8 @@ class VisualsLayoutMici(NavScroller):
|
||||
self._camera_view_btn,
|
||||
self._driver_camera_btn,
|
||||
self._stopped_timer_btn,
|
||||
self._rainbow_path_btn,
|
||||
self._lead_indicator_btn,
|
||||
self._speed_limit_signs_btn,
|
||||
self._slc_confirmation_btn,
|
||||
self._slc_confirmation_lower_btn,
|
||||
@@ -69,6 +89,7 @@ class VisualsLayoutMici(NavScroller):
|
||||
|
||||
def _refresh(self):
|
||||
self._camera_view_btn.refresh()
|
||||
self._lead_indicator_btn.refresh()
|
||||
confirmation_enabled = self._slc_confirmation_btn.params.get_bool("SLCConfirmation")
|
||||
self._slc_confirmation_lower_btn.set_visible(confirmation_enabled)
|
||||
self._slc_confirmation_higher_btn.set_visible(confirmation_enabled)
|
||||
|
||||
@@ -7,7 +7,8 @@ from openpilot.common.params import Params
|
||||
from openpilot.common.constants import CV
|
||||
from openpilot.common.filter_simple import FirstOrderFilter
|
||||
from openpilot.selfdrive.locationd.calibrationd import HEIGHT_INIT
|
||||
from openpilot.selfdrive.ui.lib.starpilot_theme import get_theme_color, with_alpha
|
||||
from openpilot.selfdrive.ui.lib.starpilot_theme import get_param_color, get_theme_color, get_visual_color, with_alpha
|
||||
from openpilot.selfdrive.ui.lib.starpilot_visuals import lead_indicator_enabled
|
||||
from openpilot.selfdrive.ui.ui_state import ui_state, UIStatus
|
||||
from openpilot.selfdrive.ui.mici.onroad import blend_colors
|
||||
from openpilot.selfdrive.ui.mici.onroad.starpilot_status import get_border_color, get_path_edge_color
|
||||
@@ -18,6 +19,8 @@ from openpilot.system.ui.widgets import Widget
|
||||
CLIP_MARGIN = 500
|
||||
MIN_DRAW_DISTANCE = 10.0
|
||||
MAX_DRAW_DISTANCE = 100.0
|
||||
RAINBOW_GRADIENT_COLOR_COUNT = 19
|
||||
RAINBOW_SCROLL_SPEED_DEG_PER_SEC = 60.0
|
||||
|
||||
THROTTLE_COLORS = [
|
||||
rl.Color(13, 248, 122, 102), # HSLF(148/360, 0.94, 0.51, 0.4)
|
||||
@@ -117,7 +120,7 @@ class ModelRenderer(Widget):
|
||||
model = sm['modelV2']
|
||||
radar_state = sm['radarState'] if sm.valid['radarState'] else None
|
||||
lead_one = radar_state.leadOne if radar_state else None
|
||||
render_lead_indicator = self._longitudinal_control and radar_state is not None
|
||||
render_lead_indicator = self._longitudinal_control and radar_state is not None and lead_indicator_enabled(self._params)
|
||||
|
||||
# Update model data when needed
|
||||
model_updated = sm.updated['modelV2']
|
||||
@@ -137,8 +140,8 @@ class ModelRenderer(Widget):
|
||||
self._draw_lane_lines()
|
||||
self._draw_path(sm)
|
||||
|
||||
# if render_lead_indicator and radar_state:
|
||||
# self._draw_lead_indicator()
|
||||
if render_lead_indicator and radar_state:
|
||||
self._draw_lead_indicator()
|
||||
|
||||
def _update_raw_points(self, model):
|
||||
"""Update raw 3D points from model data"""
|
||||
@@ -243,10 +246,22 @@ class ModelRenderer(Widget):
|
||||
|
||||
def _update_experimental_gradient(self):
|
||||
"""Pre-calculate experimental mode gradient colors"""
|
||||
if not (self._experimental_mode or self._params.get_bool("AccelerationPath", default=True)):
|
||||
use_rainbow = self._params.get_bool("RainbowPath", default=False)
|
||||
use_acceleration = not use_rainbow and (self._experimental_mode or self._params.get_bool("AccelerationPath", default=True))
|
||||
|
||||
if not (use_rainbow or use_acceleration):
|
||||
return
|
||||
|
||||
max_len = min(len(self._path.projected_points) // 2, len(self._acceleration_x))
|
||||
if use_rainbow:
|
||||
gradient_bottom, gradient_top = self._get_visible_gradient_bounds()
|
||||
self._exp_gradient = self._build_rainbow_gradient(gradient_bottom, gradient_top)
|
||||
return
|
||||
|
||||
custom_theme_selected = (self._params.get("ColorScheme", encoding="utf-8", default="stock") or "stock").lower() != "stock"
|
||||
path_color = None
|
||||
if custom_theme_selected or get_param_color(self._params, "PathColor", 255) is not None:
|
||||
path_color = get_visual_color(self._params, "PathColor", "Path", rl.Color(48, 255, 156, 255))
|
||||
|
||||
segment_colors = []
|
||||
gradient_stops = []
|
||||
@@ -262,6 +277,14 @@ class ModelRenderer(Widget):
|
||||
# Calculate color based on acceleration (0 is bottom, 1 is top)
|
||||
lin_grad_point = 1 - (track_y - self._rect.y) / self._rect.height
|
||||
|
||||
if path_color is not None and abs(self._acceleration_x[i]) < 0.25:
|
||||
alpha = np.interp(lin_grad_point, [0.0, 1.0], [path_color.a, path_color.a * 0.10])
|
||||
color = with_alpha(path_color, int(alpha))
|
||||
gradient_stops.append(lin_grad_point)
|
||||
segment_colors.append(color)
|
||||
i += 1 + (1 if (i + 2) < max_len else 0)
|
||||
continue
|
||||
|
||||
# speed up: 120, slow down: 0
|
||||
path_hue = np.clip(60 + self._acceleration_x[i] * 35, 0, 120)
|
||||
|
||||
@@ -281,6 +304,40 @@ class ModelRenderer(Widget):
|
||||
# Store the gradient in the path object
|
||||
self._exp_gradient.colors = segment_colors
|
||||
self._exp_gradient.stops = gradient_stops
|
||||
self._exp_gradient.start = (0.0, 1.0)
|
||||
self._exp_gradient.end = (0.0, 0.0)
|
||||
|
||||
def _get_visible_gradient_bounds(self) -> tuple[float, float]:
|
||||
if self._path.projected_points.size == 0:
|
||||
return 1.0, 0.0
|
||||
|
||||
polygon_y = self._path.projected_points[:, 1]
|
||||
visible_track_y = polygon_y[(polygon_y >= self._rect.y) & (polygon_y <= (self._rect.y + self._rect.height))]
|
||||
|
||||
if visible_track_y.size == 0:
|
||||
return 1.0, 0.0
|
||||
|
||||
gradient_bottom = np.clip((float(np.max(visible_track_y)) - self._rect.y) / self._rect.height, 0.0, 1.0)
|
||||
gradient_top = np.clip((float(np.min(visible_track_y)) - self._rect.y) / self._rect.height, 0.0, 1.0)
|
||||
return float(gradient_bottom), float(gradient_top)
|
||||
|
||||
def _build_rainbow_gradient(self, gradient_bottom: float, gradient_top: float) -> Gradient:
|
||||
hue_offset = (rl.get_time() * RAINBOW_SCROLL_SPEED_DEG_PER_SEC) % 360.0
|
||||
stops = [i / (RAINBOW_GRADIENT_COLOR_COUNT - 1) for i in range(RAINBOW_GRADIENT_COLOR_COUNT)]
|
||||
colors = []
|
||||
|
||||
for i, stop in enumerate(stops):
|
||||
hue_progress = i / RAINBOW_GRADIENT_COLOR_COUNT
|
||||
path_hue = (hue_progress * 360.0 - hue_offset) % 360.0
|
||||
alpha = np.interp(stop, [0.0, 1.0], [0.48, 0.18])
|
||||
colors.append(self._hsla_to_color(path_hue / 360.0, 1.0, 0.5, alpha))
|
||||
|
||||
return Gradient(
|
||||
start=(0.0, gradient_bottom),
|
||||
end=(0.0, gradient_top),
|
||||
colors=colors,
|
||||
stops=stops,
|
||||
)
|
||||
|
||||
def _update_lead_vehicle(self, d_rel, v_rel, point, rect):
|
||||
speed_buff, lead_buff = 10.0, 40.0
|
||||
@@ -309,8 +366,12 @@ class ModelRenderer(Widget):
|
||||
def _get_ll_color(self, prob: float, adjacent: bool, left: bool):
|
||||
alpha = np.clip(prob, 0.0, 0.7)
|
||||
if adjacent:
|
||||
_base_color = get_path_edge_color(ui_state)
|
||||
color = rl.Color(_base_color.r, _base_color.g, _base_color.b, int(alpha * 255))
|
||||
override = get_param_color(self._params, "PathEdgesColor", 255)
|
||||
if override is not None:
|
||||
color = with_alpha(override, int(alpha * override.a))
|
||||
else:
|
||||
_base_color = get_path_edge_color(ui_state)
|
||||
color = rl.Color(_base_color.r, _base_color.g, _base_color.b, int(alpha * 255))
|
||||
|
||||
# turn adjacent lls orange if torque is high
|
||||
torque = self._torque_filter.x
|
||||
@@ -322,7 +383,7 @@ class ModelRenderer(Widget):
|
||||
np.interp(abs(torque), [0.6, 0.8], [0.0, 1.0])
|
||||
)
|
||||
else:
|
||||
lane_lines_color = get_theme_color("LaneLines", rl.WHITE)
|
||||
lane_lines_color = get_visual_color(self._params, "LaneLinesColor", "LaneLines", rl.WHITE)
|
||||
color = with_alpha(lane_lines_color, int(alpha * lane_lines_color.a))
|
||||
|
||||
return color
|
||||
@@ -353,17 +414,20 @@ class ModelRenderer(Widget):
|
||||
lateral_ui_active = ui_state.status == UIStatus.ENGAGED or ui_state.always_on_lateral_active
|
||||
allow_throttle = sm['longitudinalPlan'].allowThrottle or not self._longitudinal_control or ui_state.always_on_lateral_active
|
||||
self._blend_filter.update(int(allow_throttle))
|
||||
use_rainbow = self._params.get_bool("RainbowPath", default=False)
|
||||
use_accel_path = not use_rainbow and self._params.get_bool("AccelerationPath", default=True)
|
||||
path_override = get_param_color(self._params, "PathColor", 255)
|
||||
custom_theme_selected = (self._params.get("ColorScheme", encoding="utf-8", default="stock") or "stock").lower() != "stock"
|
||||
|
||||
if self._experimental_mode or self._params.get_bool("AccelerationPath", default=True):
|
||||
if use_rainbow or self._experimental_mode or use_accel_path:
|
||||
# Draw with acceleration coloring
|
||||
if len(self._exp_gradient.colors) > 1:
|
||||
draw_polygon(self._rect, self._path.projected_points, gradient=self._exp_gradient)
|
||||
else:
|
||||
fallback = get_border_color(ui_state)
|
||||
draw_polygon(self._rect, self._path.projected_points, rl.Color(fallback.r, fallback.g, fallback.b, 90))
|
||||
elif custom_theme_selected:
|
||||
path_color = get_theme_color("Path", rl.Color(48, 255, 156, 255))
|
||||
elif path_override is not None or custom_theme_selected:
|
||||
path_color = get_visual_color(self._params, "PathColor", "Path", rl.Color(48, 255, 156, 255))
|
||||
gradient = Gradient(
|
||||
start=(0.0, 1.0),
|
||||
end=(0.0, 0.0),
|
||||
@@ -391,12 +455,13 @@ class ModelRenderer(Widget):
|
||||
|
||||
def _draw_lead_indicator(self):
|
||||
# Draw lead vehicles if available
|
||||
lead_color = get_theme_color("LeadMarker", rl.Color(201, 34, 49, 255))
|
||||
for lead in self._lead_vehicles:
|
||||
if not lead.glow or not lead.chevron:
|
||||
continue
|
||||
|
||||
rl.draw_triangle_fan(lead.glow, len(lead.glow), rl.Color(218, 202, 37, 255))
|
||||
rl.draw_triangle_fan(lead.chevron, len(lead.chevron), rl.Color(201, 34, 49, lead.fill_alpha))
|
||||
rl.draw_triangle_fan(lead.chevron, len(lead.chevron), with_alpha(lead_color, lead.fill_alpha))
|
||||
|
||||
@staticmethod
|
||||
def _get_path_length_idx(pos_x_array: np.ndarray, path_height: float) -> int:
|
||||
|
||||
@@ -7,7 +7,8 @@ from openpilot.common.filter_simple import FirstOrderFilter
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.constants import CV
|
||||
from openpilot.selfdrive.locationd.calibrationd import HEIGHT_INIT
|
||||
from openpilot.selfdrive.ui.lib.starpilot_theme import get_theme_color, with_alpha
|
||||
from openpilot.selfdrive.ui.lib.starpilot_theme import get_param_color, get_theme_color, get_visual_color, with_alpha
|
||||
from openpilot.selfdrive.ui.lib.starpilot_visuals import lead_indicator_enabled
|
||||
from openpilot.selfdrive.ui.ui_state import ui_state, UIStatus
|
||||
from openpilot.system.ui.lib.application import gui_app
|
||||
from openpilot.system.ui.lib.shader_polygon import draw_polygon, Gradient
|
||||
@@ -16,6 +17,8 @@ from openpilot.system.ui.widgets import Widget
|
||||
CLIP_MARGIN = 500
|
||||
MIN_DRAW_DISTANCE = 10.0
|
||||
MAX_DRAW_DISTANCE = 100.0
|
||||
RAINBOW_GRADIENT_COLOR_COUNT = 19
|
||||
RAINBOW_SCROLL_SPEED_DEG_PER_SEC = 60.0
|
||||
|
||||
THROTTLE_COLORS = [
|
||||
rl.Color(13, 248, 122, 102), # HSLF(148/360, 0.94, 0.51, 0.4)
|
||||
@@ -59,10 +62,6 @@ class ModelRenderer(Widget):
|
||||
self._adjacent_path_vertices = [np.empty((0, 2), dtype=np.float32), np.empty((0, 2), dtype=np.float32)]
|
||||
# Outer path polygon for edge rendering
|
||||
self._track_edge_vertices = np.empty((0, 2), dtype=np.float32)
|
||||
# Rainbow animation state
|
||||
self._rainbow_hue_offset = 0.0
|
||||
# Cached speed for rainbow animation
|
||||
self._speed = 0.0
|
||||
|
||||
# Initialize ModelPoints objects
|
||||
self._path = ModelPoints()
|
||||
@@ -107,7 +106,6 @@ class ModelRenderer(Widget):
|
||||
|
||||
# Update state
|
||||
self._experimental_mode = sm['selfdriveState'].experimentalMode
|
||||
self._speed = sm['carState'].vEgo
|
||||
|
||||
live_calib = sm['liveCalibration']
|
||||
self._path_offset_z = live_calib.height[0] if live_calib.height else HEIGHT_INIT[0]
|
||||
@@ -118,7 +116,7 @@ class ModelRenderer(Widget):
|
||||
model = sm['modelV2']
|
||||
radar_state = sm['radarState'] if sm.valid['radarState'] else None
|
||||
lead_one = radar_state.leadOne if radar_state else None
|
||||
render_lead_indicator = self._longitudinal_control and radar_state is not None
|
||||
render_lead_indicator = self._longitudinal_control and radar_state is not None and lead_indicator_enabled(self._params)
|
||||
|
||||
# Update model data when needed
|
||||
model_updated = sm.updated['modelV2']
|
||||
@@ -244,13 +242,22 @@ class ModelRenderer(Widget):
|
||||
|
||||
def _update_experimental_gradient(self):
|
||||
"""Pre-calculate experimental mode gradient colors"""
|
||||
use_acceleration = self._experimental_mode or self._params.get_bool('AccelerationPath', default=True)
|
||||
use_rainbow = self._params.get_bool('RainbowPath') and not use_acceleration
|
||||
use_rainbow = self._params.get_bool('RainbowPath', default=False)
|
||||
use_acceleration = not use_rainbow and (self._experimental_mode or self._params.get_bool('AccelerationPath', default=True))
|
||||
|
||||
if not use_acceleration and not use_rainbow:
|
||||
return
|
||||
|
||||
max_len = min(len(self._path.projected_points) // 2, len(self._acceleration_x))
|
||||
if use_rainbow:
|
||||
gradient_bottom, gradient_top = self._get_visible_gradient_bounds()
|
||||
self._exp_gradient = self._build_rainbow_gradient(gradient_bottom, gradient_top)
|
||||
return
|
||||
|
||||
custom_theme_selected = (self._params.get('ColorScheme', encoding='utf-8', default='stock') or 'stock').lower() != 'stock'
|
||||
path_color = None
|
||||
if custom_theme_selected or get_param_color(self._params, 'PathColor', 255) is not None:
|
||||
path_color = get_visual_color(self._params, 'PathColor', 'Path', rl.Color(48, 255, 156, 255))
|
||||
|
||||
segment_colors = []
|
||||
gradient_stops = []
|
||||
@@ -266,16 +273,9 @@ class ModelRenderer(Widget):
|
||||
# Calculate color based on acceleration (0 is bottom, 1 is top)
|
||||
lin_grad_point = 1 - (track_y - self._rect.y) / self._rect.height
|
||||
|
||||
if use_rainbow:
|
||||
# Rainbow: hue based on gradient position + animated offset
|
||||
self._rainbow_hue_offset += self._speed * 0.02
|
||||
if self._rainbow_hue_offset >= 360.0:
|
||||
self._rainbow_hue_offset = self._rainbow_hue_offset % 360.0
|
||||
path_hue = (lin_grad_point * 120.0 + self._rainbow_hue_offset) % 360.0
|
||||
saturation = 1.0
|
||||
lightness = 0.5
|
||||
alpha = np.interp(lin_grad_point, [0.0, 1.0], [0.5, 0.1])
|
||||
color = self._hsla_to_color(path_hue / 360.0, saturation, lightness, alpha)
|
||||
if path_color is not None and abs(self._acceleration_x[i]) < 0.25:
|
||||
alpha = np.interp(lin_grad_point, [0.0, 1.0], [path_color.a, path_color.a * 0.10])
|
||||
color = with_alpha(path_color, int(alpha))
|
||||
gradient_stops.append(lin_grad_point)
|
||||
segment_colors.append(color)
|
||||
i += 1 + (1 if (i + 2) < max_len else 0)
|
||||
@@ -305,6 +305,38 @@ class ModelRenderer(Widget):
|
||||
stops=gradient_stops,
|
||||
)
|
||||
|
||||
def _get_visible_gradient_bounds(self) -> tuple[float, float]:
|
||||
if self._path.projected_points.size == 0:
|
||||
return 1.0, 0.0
|
||||
|
||||
polygon_y = self._path.projected_points[:, 1]
|
||||
visible_track_y = polygon_y[(polygon_y >= self._rect.y) & (polygon_y <= (self._rect.y + self._rect.height))]
|
||||
|
||||
if visible_track_y.size == 0:
|
||||
return 1.0, 0.0
|
||||
|
||||
gradient_bottom = np.clip((float(np.max(visible_track_y)) - self._rect.y) / self._rect.height, 0.0, 1.0)
|
||||
gradient_top = np.clip((float(np.min(visible_track_y)) - self._rect.y) / self._rect.height, 0.0, 1.0)
|
||||
return float(gradient_bottom), float(gradient_top)
|
||||
|
||||
def _build_rainbow_gradient(self, gradient_bottom: float, gradient_top: float) -> Gradient:
|
||||
hue_offset = (rl.get_time() * RAINBOW_SCROLL_SPEED_DEG_PER_SEC) % 360.0
|
||||
stops = [i / (RAINBOW_GRADIENT_COLOR_COUNT - 1) for i in range(RAINBOW_GRADIENT_COLOR_COUNT)]
|
||||
colors = []
|
||||
|
||||
for i, stop in enumerate(stops):
|
||||
hue_progress = i / RAINBOW_GRADIENT_COLOR_COUNT
|
||||
path_hue = (hue_progress * 360.0 - hue_offset) % 360.0
|
||||
alpha = np.interp(stop, [0.0, 1.0], [0.48, 0.18])
|
||||
colors.append(self._hsla_to_color(path_hue / 360.0, 1.0, 0.5, alpha))
|
||||
|
||||
return Gradient(
|
||||
start=(0.0, gradient_bottom),
|
||||
end=(0.0, gradient_top),
|
||||
colors=colors,
|
||||
stops=stops,
|
||||
)
|
||||
|
||||
def _update_lead_vehicle(self, d_rel, v_rel, point, rect):
|
||||
speed_buff, lead_buff = 10.0, 40.0
|
||||
|
||||
@@ -331,7 +363,7 @@ class ModelRenderer(Widget):
|
||||
|
||||
def _draw_lane_lines(self):
|
||||
"""Draw lane lines and road edges"""
|
||||
lane_lines_color = get_theme_color("LaneLines", rl.WHITE)
|
||||
lane_lines_color = get_visual_color(self._params, "LaneLinesColor", "LaneLines", rl.WHITE)
|
||||
|
||||
for i, lane_line in enumerate(self._lane_lines):
|
||||
if lane_line.projected_points.size == 0:
|
||||
@@ -357,15 +389,17 @@ class ModelRenderer(Widget):
|
||||
allow_throttle = sm['longitudinalPlan'].allowThrottle or not self._longitudinal_control
|
||||
self._blend_filter.update(int(allow_throttle))
|
||||
|
||||
use_accel_path = self._params.get_bool('AccelerationPath', default=True)
|
||||
use_rainbow = self._params.get_bool('RainbowPath', default=False)
|
||||
use_accel_path = not use_rainbow and self._params.get_bool('AccelerationPath', default=True)
|
||||
path_override = get_param_color(self._params, 'PathColor', 255)
|
||||
custom_theme_selected = (self._params.get('ColorScheme', encoding='utf-8', default='stock') or 'stock').lower() != 'stock'
|
||||
if self._experimental_mode or use_accel_path:
|
||||
if use_rainbow or self._experimental_mode or use_accel_path:
|
||||
if len(self._exp_gradient.colors) > 1:
|
||||
draw_polygon(self._rect, self._path.projected_points, gradient=self._exp_gradient)
|
||||
else:
|
||||
draw_polygon(self._rect, self._path.projected_points, rl.Color(255, 255, 255, 30))
|
||||
elif custom_theme_selected:
|
||||
path_color = get_theme_color("Path", rl.Color(48, 255, 156, 255))
|
||||
elif path_override is not None or custom_theme_selected:
|
||||
path_color = get_visual_color(self._params, "PathColor", "Path", rl.Color(48, 255, 156, 255))
|
||||
gradient = Gradient(
|
||||
start=(0.0, 1.0),
|
||||
end=(0.0, 0.0),
|
||||
|
||||
@@ -6,7 +6,7 @@ import numpy as np
|
||||
import pyray as rl
|
||||
|
||||
from openpilot.selfdrive.ui.lib.starpilot_state import starpilot_state
|
||||
from openpilot.selfdrive.ui.lib.starpilot_theme import get_theme_color, with_alpha
|
||||
from openpilot.selfdrive.ui.lib.starpilot_theme import get_param_color, get_theme_color, with_alpha
|
||||
from openpilot.selfdrive.ui.ui_state import ui_state
|
||||
from openpilot.system.ui.lib.shader_polygon import draw_polygon, Gradient
|
||||
|
||||
@@ -177,8 +177,11 @@ def render_path_edges(renderer) -> None:
|
||||
elif ui_state.traffic_mode_enabled:
|
||||
base_color = rl.Color(201, 34, 49, 241)
|
||||
else:
|
||||
override = get_param_color(renderer._params, "PathEdgesColor", 241)
|
||||
color_scheme = renderer._params.get("ColorScheme", encoding="utf-8", default="stock")
|
||||
if color_scheme != "stock":
|
||||
if override is not None:
|
||||
base_color = rl.Color(override.r, override.g, override.b, 241)
|
||||
elif color_scheme != "stock":
|
||||
theme_color = get_theme_color("PathEdge", rl.Color(23, 134, 68, 241))
|
||||
base_color = rl.Color(theme_color.r, theme_color.g, theme_color.b, 241)
|
||||
else:
|
||||
|
||||
Binary file not shown.
@@ -1608,6 +1608,14 @@
|
||||
"ui_type": "toggle",
|
||||
"parent_key": "CustomUI"
|
||||
},
|
||||
{
|
||||
"key": "RainbowPath",
|
||||
"label": "Rainbow Road",
|
||||
"description": "Color the driving path like a rainbow road.\n\nOn the Python UIs this overrides acceleration and braking path coloring.",
|
||||
"data_type": "bool",
|
||||
"ui_type": "toggle",
|
||||
"parent_key": "CustomUI"
|
||||
},
|
||||
{
|
||||
"key": "AdjacentPath",
|
||||
"label": "Adjacent Lanes",
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -142,11 +142,13 @@ LKASButtonControl
|
||||
LaneChangeTime
|
||||
LaneChanges
|
||||
LaneDetectionWidth
|
||||
LaneLinesColor
|
||||
LaneLinesWidth
|
||||
LanguageSetting
|
||||
LateralTune
|
||||
LeadDepartingAlert
|
||||
LeadDetectionThreshold
|
||||
LeadIndicator
|
||||
LeadInfo
|
||||
LiveDelay
|
||||
LiveParameters
|
||||
@@ -197,6 +199,8 @@ OneLaneChange
|
||||
OnroadDistanceButton
|
||||
OpenpilotEnabledToggle
|
||||
OverpassRequests
|
||||
PathColor
|
||||
PathEdgesColor
|
||||
PathEdgeWidth
|
||||
PathWidth
|
||||
PauseAOLOnBrake
|
||||
|
||||
Reference in New Issue
Block a user