Introduce double_circle and segments-based patterns on the Pico, refactor the Presets engine to expose a logical ring over all strips, and migrate presets/test code from the old point pattern to segments while switching to a top-level presets.json. Made-with: Cursor
85 lines
3.1 KiB
Python
85 lines
3.1 KiB
Python
class DoubleCircle:
|
|
def __init__(self, driver):
|
|
self.driver = driver
|
|
|
|
def run(self, preset):
|
|
"""
|
|
DoubleCircle: symmetric band around a center index on the logical ring.
|
|
|
|
- n1: center index on the logical ring (0-based, on reference strip 0)
|
|
- n2: radius of the band (max distance from center)
|
|
- n3: direction mode
|
|
0 → LEDs start ALL OFF and turn ON n4 LEDs at a time outward from n1 toward n1±n2
|
|
1 → LEDs start ALL ON within radius n2 and turn OFF n4 LEDs at a time inward toward n1
|
|
- n4: step size in LEDs per update
|
|
- c[0]: base color used for the band
|
|
"""
|
|
num_leds = self.driver.num_leds
|
|
if num_leds <= 0:
|
|
while True:
|
|
yield
|
|
|
|
colors = preset.c or []
|
|
base1 = colors[0] if len(colors) >= 1 else (255, 255, 255)
|
|
off = (0, 0, 0)
|
|
|
|
# Apply preset/global brightness
|
|
color_on = self.driver.apply_brightness(base1, preset.b)
|
|
color_off = off
|
|
|
|
# Center index and radius from preset; clamp center to ring length
|
|
center = int(getattr(preset, "n1", 0)) % num_leds
|
|
radius = max(1, int(getattr(preset, "n2", 0)) or 1)
|
|
mode = int(getattr(preset, "n3", 0) or 0) # 0 = grow band outward, 1 = shrink band inward
|
|
step_size = max(1, int(getattr(preset, "n4", 1)) or 1)
|
|
|
|
num_strips = len(self.driver.strips)
|
|
|
|
# Current "front" of the band, as a distance from center
|
|
# mode 0: grow band outward (0 → radius)
|
|
# mode 1: shrink band inward (radius → 0)
|
|
if mode == 0:
|
|
current = 0
|
|
else:
|
|
current = radius
|
|
|
|
while True:
|
|
# Draw current frame based on current radius
|
|
for i in range(num_leds):
|
|
# Shortest circular distance from i to center
|
|
forward = (i - center) % num_leds
|
|
backward = (center - i) % num_leds
|
|
dist = forward if forward < backward else backward
|
|
|
|
if dist > radius:
|
|
c = color_off
|
|
else:
|
|
if mode == 0:
|
|
# Grow outward: lit if within current radius
|
|
c = color_on if dist <= current else color_off
|
|
else:
|
|
# Shrink inward: lit if within current radius (band contracts toward center)
|
|
c = color_on if dist <= current else color_off
|
|
|
|
for strip_idx in range(num_strips):
|
|
self.driver.set(strip_idx, i, c)
|
|
|
|
self.driver.show_all()
|
|
|
|
# Update current radius for next frame
|
|
if mode == 0:
|
|
if current >= radius:
|
|
# Finished growing; hold final frame
|
|
while True:
|
|
yield
|
|
current = min(radius, current + step_size)
|
|
else:
|
|
if current <= 0:
|
|
# Finished shrinking; hold final frame
|
|
while True:
|
|
yield
|
|
current = max(0, current - step_size)
|
|
|
|
yield
|
|
|