Compare commits
1 Commits
5a8866add7
...
a22702df4d
| Author | SHA1 | Date | |
|---|---|---|---|
| a22702df4d |
89
src/patterns/radiate.py
Normal file
89
src/patterns/radiate.py
Normal file
@@ -0,0 +1,89 @@
|
||||
import utime
|
||||
|
||||
|
||||
class Radiate:
|
||||
def __init__(self, driver):
|
||||
self.driver = driver
|
||||
|
||||
def run(self, preset):
|
||||
"""Radiate from nodes every n1 LEDs, retriggering every delay (d).
|
||||
|
||||
- n1: node spacing in LEDs
|
||||
- n2: outbound travel time in ms
|
||||
- n3: return travel time in ms
|
||||
- d: retrigger interval in ms
|
||||
"""
|
||||
colors = preset.c if preset.c else [(255, 255, 255)]
|
||||
base_on = colors[0]
|
||||
base_off = colors[1] if len(colors) > 1 else (0, 0, 0)
|
||||
|
||||
spacing = max(1, int(preset.n1))
|
||||
outward_ms = max(1, int(preset.n2))
|
||||
return_ms = max(1, int(preset.n3))
|
||||
max_dist = spacing // 2
|
||||
|
||||
lit_color = self.driver.apply_brightness(base_on, preset.b)
|
||||
off_color = self.driver.apply_brightness(base_off, preset.b)
|
||||
|
||||
now = utime.ticks_ms()
|
||||
last_trigger = now
|
||||
active_pulses = [now]
|
||||
|
||||
if not preset.a:
|
||||
# Single-step render uses only the first instant pulse.
|
||||
active_pulses = [utime.ticks_ms()]
|
||||
|
||||
while True:
|
||||
now = utime.ticks_ms()
|
||||
delay_ms = max(1, int(preset.d))
|
||||
spacing = max(1, int(preset.n1))
|
||||
outward_ms = max(1, int(preset.n2))
|
||||
return_ms = max(1, int(preset.n3))
|
||||
max_dist = spacing // 2
|
||||
lit_color = self.driver.apply_brightness(base_on, preset.b)
|
||||
off_color = self.driver.apply_brightness(base_off, preset.b)
|
||||
|
||||
if preset.a and utime.ticks_diff(now, last_trigger) >= delay_ms:
|
||||
active_pulses.append(now)
|
||||
last_trigger = utime.ticks_add(last_trigger, delay_ms)
|
||||
|
||||
# Drop pulses once their out-and-back lifetime ends.
|
||||
pulse_lifetime = outward_ms + return_ms
|
||||
kept = []
|
||||
for start in active_pulses:
|
||||
age = utime.ticks_diff(now, start)
|
||||
if age <= pulse_lifetime:
|
||||
kept.append(start)
|
||||
active_pulses = kept
|
||||
|
||||
for i in range(self.driver.num_leds):
|
||||
# Nearest node distance for a repeating node grid every `spacing` LEDs.
|
||||
offset = i % spacing
|
||||
dist = min(offset, spacing - offset)
|
||||
|
||||
lit = False
|
||||
for start in active_pulses:
|
||||
age = utime.ticks_diff(now, start)
|
||||
if age < 0:
|
||||
continue
|
||||
if age <= outward_ms:
|
||||
front = (age * max_dist) / outward_ms
|
||||
elif age <= outward_ms + return_ms:
|
||||
back_age = age - outward_ms
|
||||
front = ((return_ms - back_age) * max_dist) / return_ms
|
||||
else:
|
||||
continue
|
||||
|
||||
if dist <= front:
|
||||
lit = True
|
||||
break
|
||||
|
||||
self.driver.n[i] = lit_color if lit else off_color
|
||||
|
||||
self.driver.n.write()
|
||||
|
||||
if not preset.a:
|
||||
yield
|
||||
return
|
||||
|
||||
yield
|
||||
Reference in New Issue
Block a user