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