Files
StarPilot/openpilot/starpilot/ui/rainbow_path.py
T
firestar5683 aaac7a6733 Shared settings and onroad views
Present saved configuration and live driving state through native Small and Big UI layouts. Support per-field tune resets, movable widgets, camera availability, and a unified speed card while preserving decision-bound actions.
2026-10-03 22:34:37 +00:00

65 lines
2.2 KiB
Python

"""Speed-scrolling gradient for the onroad path."""
import colorsys
import math
import pyray as rl
from openpilot.starpilot.ui.appearance_preferences import read_visibility
from openpilot.system.ui.lib.shader_polygon import Gradient
HUE_RANGE = 120.0
SCROLL_DEG_PER_SEC_PER_MPS = 5.0
NUM_STOPS = 12
MAX_SAMPLE_AGE_NS = 500_000_000
MAX_FRAME_GAP_NS = 250_000_000
PREFERENCE_POLL_NS = 1_000_000_000
class RainbowPath:
def __init__(self) -> None:
self.phase_deg = 0.0
self.last_ns: int | None = None
self.sample_ns: int | None = None
self.speed_mps = 0.0
self.enabled = False
self.next_preference_ns = 0
def refresh_enabled(self, params, now_ns: int) -> bool:
if now_ns < self.next_preference_ns and now_ns >= 0:
return self.enabled
saved = read_visibility(params, "RainbowPath")
self.enabled = saved.value is True and saved.readable
self.next_preference_ns = now_ns + PREFERENCE_POLL_NS
return self.enabled
def update(self, now_ns: int, speed_mps: float | None, *, source_alive: bool) -> None:
if now_ns < 0 or self.last_ns is not None and now_ns < self.last_ns:
self.sample_ns = None
self.last_ns = now_ns
return
if not source_alive:
self.sample_ns = None
elif speed_mps is not None:
if math.isfinite(speed_mps) and 0.0 <= speed_mps <= 80.0:
self.speed_mps = speed_mps
self.sample_ns = now_ns
else:
self.sample_ns = None
dt_ns = 0 if self.last_ns is None else now_ns - self.last_ns
self.last_ns = now_ns
if (self.sample_ns is not None and now_ns - self.sample_ns <= MAX_SAMPLE_AGE_NS and
0 < dt_ns <= MAX_FRAME_GAP_NS):
self.phase_deg = (self.phase_deg + self.speed_mps * SCROLL_DEG_PER_SEC_PER_MPS * dt_ns / 1e9) % 360.0
def gradient(self) -> Gradient:
stops = [index / (NUM_STOPS - 1) for index in range(NUM_STOPS)]
colors = []
for stop in stops:
hue = ((stop * HUE_RANGE + self.phase_deg) % 360.0) / 360.0
red, green, blue = colorsys.hls_to_rgb(hue, 0.5, 1.0)
alpha = 0.5 + (0.1 - 0.5) * stop
colors.append(rl.Color(int(red * 255), int(green * 255), int(blue * 255), int(alpha * 255)))
return Gradient(start=(0.0, 0.0), end=(0.0, 1.0), colors=colors, stops=stops)