Skip to content

Commit baa8095

Browse files
authored
Merge pull request #35 from rhooper/comet-fixes
Fix comet length and simplification
2 parents 37e9190 + 96ed05c commit baa8095

File tree

3 files changed

+91
-72
lines changed

3 files changed

+91
-72
lines changed

adafruit_led_animation/animation/comet.py

+36-52
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
"""
4646

4747
from adafruit_led_animation.animation import Animation
48-
from adafruit_led_animation.color import BLACK
48+
from adafruit_led_animation.color import BLACK, calculate_intensity
4949

5050

5151
class Comet(Animation):
@@ -62,7 +62,7 @@ class Comet(Animation):
6262
:param bool bounce: Comet will bounce back and forth. Defaults to ``True``.
6363
"""
6464

65-
# pylint: disable=too-many-arguments
65+
# pylint: disable=too-many-arguments,too-many-instance-attributes
6666
def __init__(
6767
self,
6868
pixel_object,
@@ -75,75 +75,59 @@ def __init__(
7575
):
7676
if tail_length == 0:
7777
tail_length = len(pixel_object) // 4
78-
else:
79-
tail_length = max(2, min(tail_length, len(pixel_object)))
80-
self._tail_length = tail_length
81-
self._color_step = 0.9 / tail_length
82-
self._color_offset = 0.1
83-
self._comet_colors = None
84-
self._reverse_comet_colors = None
85-
self._initial_reverse = reverse
8678
self.reverse = reverse
8779
self.bounce = bounce
80+
self._initial_reverse = reverse
81+
self._tail_length = tail_length
82+
self._color_step = 0.95 / tail_length
83+
self._comet_colors = None
8884
self._computed_color = color
89-
self._generator = self._comet_generator()
85+
self._num_pixels = len(pixel_object)
86+
self._direction = -1 if reverse else 1
87+
self._left_side = -self._tail_length
88+
self._right_side = self._num_pixels
89+
self._tail_start = 0
90+
self.reset()
9091
super().__init__(pixel_object, speed, color, name=name)
9192

9293
on_cycle_complete_supported = True
9394

9495
def _recompute_color(self, color):
95-
pass
96+
self._comet_recompute_color(color)
9697

9798
def _comet_recompute_color(self, color):
98-
self._comet_colors = [BLACK] + [
99-
[
100-
int(color[rgb] * ((n * self._color_step) + self._color_offset))
101-
for rgb in range(len(color))
102-
]
103-
for n in range(self._tail_length - 1)
104-
]
105-
self._reverse_comet_colors = list(reversed(self._comet_colors))
99+
self._comet_colors = [BLACK]
100+
for n in range(self._tail_length):
101+
self._comet_colors.append(
102+
calculate_intensity(color, n * self._color_step + 0.05)
103+
)
106104
self._computed_color = color
107105

108-
def _get_range(self, num_pixels):
106+
def draw(self):
107+
colors = self._comet_colors
109108
if self.reverse:
110-
return range(num_pixels, -self._tail_length - 1, -1)
111-
return range(-self._tail_length, num_pixels + 1)
112-
113-
def _comet_generator(self):
114-
num_pixels = len(self.pixel_object)
115-
cycle_passes = 0
116-
while True:
117-
if self._color != self._computed_color or not self._comet_colors:
118-
self._comet_recompute_color(self._color)
119-
colors = self._reverse_comet_colors if self.reverse else self._comet_colors
120-
for start in self._get_range(num_pixels):
121-
122-
if start + self._tail_length < num_pixels:
123-
end = self._tail_length
124-
else:
125-
end = num_pixels - start
126-
if start <= 0:
127-
num_visible = self._tail_length + start
128-
self.pixel_object[0:num_visible] = colors[
129-
self._tail_length - num_visible :
130-
]
131-
else:
132-
self.pixel_object[start : start + end] = colors[0:end]
133-
yield
134-
cycle_passes += 1
109+
colors = reversed(colors)
110+
for pixel_no, color in enumerate(colors):
111+
draw_at = self._tail_start + pixel_no
112+
if draw_at < 0 or draw_at >= self._num_pixels:
113+
continue
114+
self.pixel_object[draw_at] = color
115+
116+
self._tail_start += self._direction
117+
118+
if self._tail_start < self._left_side or self._tail_start >= self._right_side:
135119
if self.bounce:
136120
self.reverse = not self.reverse
137-
if not self.bounce or cycle_passes == 2:
121+
self._direction = -self._direction
122+
if self.reverse == self._initial_reverse:
138123
self.cycle_complete = True
139-
cycle_passes = 0
140-
141-
def draw(self):
142-
next(self._generator)
143124

144125
def reset(self):
145126
"""
146127
Resets to the first color.
147128
"""
148-
self._generator = self._comet_generator()
149129
self.reverse = self._initial_reverse
130+
if self.reverse:
131+
self._tail_start = self._num_pixels + self._tail_length + 1
132+
else:
133+
self._tail_start = -self._tail_length - 1

adafruit_led_animation/animation/rainbowcomet.py

+18-20
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
"""
4646

4747
from adafruit_led_animation.animation.comet import Comet
48-
from adafruit_led_animation.color import colorwheel, BLACK
48+
from adafruit_led_animation.color import colorwheel, BLACK, calculate_intensity
4949

5050

5151
class RainbowComet(Comet):
@@ -60,6 +60,7 @@ class RainbowComet(Comet):
6060
:param bool reverse: Animates the comet in the reverse order. Defaults to ``False``.
6161
:param bool bounce: Comet will bounce back and forth. Defaults to ``True``.
6262
:param int colorwheel_offset: Offset from start of colorwheel (0-255).
63+
:param int step: Colorwheel step (defaults to automatic).
6364
"""
6465

6566
# pylint: disable=too-many-arguments
@@ -71,30 +72,27 @@ def __init__(
7172
reverse=False,
7273
bounce=False,
7374
colorwheel_offset=0,
75+
step=0,
7476
name=None,
7577
):
76-
self._colorwheel_is_tuple = isinstance(colorwheel(0), tuple)
78+
if step == 0:
79+
self._colorwheel_step = int(256 / tail_length)
80+
else:
81+
self._colorwheel_step = step
7782
self._colorwheel_offset = colorwheel_offset
78-
7983
super().__init__(pixel_object, speed, 0, tail_length, reverse, bounce, name)
8084

81-
def _calc_brightness(self, n, color):
82-
brightness = (n * self._color_step) + self._color_offset
83-
if not self._colorwheel_is_tuple:
84-
color = (color & 0xFF, ((color & 0xFF00) >> 8), (color >> 16))
85-
return [int(i * brightness) for i in color]
86-
8785
def _comet_recompute_color(self, color):
88-
factor = int(256 / self._tail_length)
89-
self._comet_colors = [BLACK] + [
90-
self._calc_brightness(
91-
n,
92-
colorwheel(
93-
int((n * factor) + self._color_offset + self._colorwheel_offset)
94-
% 256
95-
),
86+
self._comet_colors = [BLACK]
87+
for n in range(self._tail_length):
88+
invert = self._tail_length - n - 1
89+
self._comet_colors.append(
90+
calculate_intensity(
91+
colorwheel(
92+
int((invert * self._colorwheel_step) + self._colorwheel_offset)
93+
% 256
94+
),
95+
n * self._color_step + 0.05,
96+
)
9697
)
97-
for n in range(self._tail_length - 1)
98-
]
99-
self._reverse_comet_colors = list(reversed(self._comet_colors))
10098
self._computed_color = color

adafruit_led_animation/color.py

+37
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,40 @@ def colorwheel(pos):
6464
return 0, int(255 - pos * 3), int(pos * 3)
6565
pos -= 170
6666
return int(pos * 3), 0, int(255 - (pos * 3))
67+
68+
69+
def calculate_intensity(color, intensity=1.0):
70+
"""
71+
Takes a RGB[W] color tuple and adjusts the intensity.
72+
:param float intensity:
73+
:param color: color value (tuple, list or int)
74+
:return: color
75+
"""
76+
# Note: This code intentionally avoids list comprehensions and intermediate variables
77+
# for an approximately 2x performance gain.
78+
if isinstance(color, int):
79+
return (
80+
(int((color & 0xFF0000) * intensity) & 0xFF0000)
81+
| (int((color & 0xFF00) * intensity) & 0xFF00)
82+
| (int((color & 0xFF) * intensity) & 0xFF)
83+
)
84+
85+
if len(color) == 3:
86+
return (
87+
int(color[0] * intensity),
88+
int(color[1] * intensity),
89+
int(color[2] * intensity),
90+
)
91+
if len(color) == 4 and isinstance(color[3], float):
92+
return (
93+
int(color[0] * intensity),
94+
int(color[1] * intensity),
95+
int(color[2] * intensity),
96+
color[3],
97+
)
98+
return (
99+
int(color[0] * intensity),
100+
int(color[1] * intensity),
101+
int(color[2] * intensity),
102+
int(color[3] * intensity),
103+
)

0 commit comments

Comments
 (0)