Merge pull request #40 from rhooper/pixelgrid
Add PixelGrid 2D mapping helper and Rain animations
This commit is contained in:
commit
a07c8ac11d
5 changed files with 442 additions and 101 deletions
147
adafruit_led_animation/animation/grid_rain.py
Normal file
147
adafruit_led_animation/animation/grid_rain.py
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2019-2020 Roy Hooper
|
||||
# Copyright (c) 2020 Kattni Rembor for Adafruit Industries
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
"""
|
||||
`adafruit_led_animation.animation.grid_rain`
|
||||
================================================================================
|
||||
|
||||
Rain animations for CircuitPython helper library for LED animations.
|
||||
|
||||
* Author(s): Roy Hooper, Kattni Rembor
|
||||
|
||||
Implementation Notes
|
||||
--------------------
|
||||
|
||||
**Hardware:**
|
||||
|
||||
* `Adafruit NeoPixels <https://www.adafruit.com/category/168>`_
|
||||
* `Adafruit DotStars <https://www.adafruit.com/category/885>`_
|
||||
|
||||
**Software and Dependencies:**
|
||||
|
||||
* Adafruit CircuitPython firmware for the supported boards:
|
||||
https://circuitpython.org/downloads
|
||||
|
||||
"""
|
||||
|
||||
import random
|
||||
from adafruit_led_animation.animation import Animation
|
||||
|
||||
__version__ = "0.0.0-auto.0"
|
||||
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_LED_Animation.git"
|
||||
|
||||
from adafruit_led_animation.color import BLACK, colorwheel, calculate_intensity, GREEN
|
||||
|
||||
|
||||
class Rain(Animation):
|
||||
"""
|
||||
Droplets of rain.
|
||||
|
||||
:param grid_object: The initialised PixelGrid object.
|
||||
:param float speed: Animation speed in seconds, e.g. ``0.1``.
|
||||
:param color: Animation color in ``(r, g, b)`` tuple, or ``0x000000`` hex format.
|
||||
:param count: Number of sparkles to generate per animation cycle.
|
||||
:param length: Number of pixels per raindrop (Default 3)
|
||||
:param background: Background color (Default BLACK).
|
||||
"""
|
||||
|
||||
# pylint: disable=too-many-arguments
|
||||
def __init__(
|
||||
self, grid_object, speed, color, count=1, length=3, background=BLACK, name=None
|
||||
):
|
||||
self._count = count
|
||||
self._length = length
|
||||
self._background = background
|
||||
self._raindrops = []
|
||||
super().__init__(grid_object, speed, color, name=name)
|
||||
|
||||
def draw(self):
|
||||
|
||||
# Move raindrops down
|
||||
keep = []
|
||||
for raindrop in self._raindrops:
|
||||
pixels = []
|
||||
if raindrop[1][0][0] >= 0:
|
||||
self.pixel_object[raindrop[0], raindrop[1][0][0]] = self._background
|
||||
for pixel in raindrop[1]:
|
||||
pixel[0] += 1
|
||||
if pixel[0] < self.pixel_object.height:
|
||||
pixels.append(pixel)
|
||||
if pixels:
|
||||
keep.append([raindrop[0], pixels])
|
||||
self._raindrops = keep
|
||||
|
||||
# Add a raindrop
|
||||
if len(self._raindrops) < self._count:
|
||||
x = random.randint(0, self.pixel_object.width - 1)
|
||||
self._raindrops.append([x, self._generate_droplet(x, self._length)])
|
||||
|
||||
# Draw raindrops
|
||||
for x, pixels in self._raindrops:
|
||||
for y, color in pixels:
|
||||
if y >= 0:
|
||||
self.pixel_object[x, y] = color
|
||||
|
||||
def _generate_droplet(self, x, length): # pylint: disable=unused-argument
|
||||
return [[n, self.color] for n in range(-length, 0)]
|
||||
|
||||
|
||||
class RainbowRain(Rain):
|
||||
"""
|
||||
Rainbow Rain animation.
|
||||
"""
|
||||
|
||||
def __init__( # pylint: disable=too-many-arguments
|
||||
self, grid_object, speed, count=1, length=3, background=BLACK, name=None
|
||||
):
|
||||
super().__init__(grid_object, speed, BLACK, count, length, background, name)
|
||||
|
||||
def _generate_droplet(self, x, length):
|
||||
color = colorwheel(random.randint(0, 255))
|
||||
return [
|
||||
[n, calculate_intensity(color, 1.0 - -((n + 1) / (length + 1)))]
|
||||
for n in range(-length, 0)
|
||||
]
|
||||
|
||||
|
||||
class MatrixRain(Rain):
|
||||
"""
|
||||
The Matrix style animation.
|
||||
"""
|
||||
|
||||
def __init__( # pylint: disable=too-many-arguments
|
||||
self,
|
||||
grid_object,
|
||||
speed,
|
||||
color=GREEN,
|
||||
count=1,
|
||||
length=6,
|
||||
background=(0, 32, 0),
|
||||
name=None,
|
||||
):
|
||||
super().__init__(grid_object, speed, color, count, length, background, name)
|
||||
|
||||
def _generate_droplet(self, x, length):
|
||||
return [
|
||||
[n, calculate_intensity(self.color, random.randint(10, 100) * 1.0)]
|
||||
for n in range(-length, 0)
|
||||
]
|
||||
|
|
@ -74,9 +74,6 @@ class Pulse(Animation):
|
|||
"""
|
||||
Resets the animation.
|
||||
"""
|
||||
white = len(self.pixel_object[0]) > 3 and isinstance(
|
||||
self.pixel_object[0][-1], int
|
||||
)
|
||||
dotstar = len(self.pixel_object[0]) == 4 and isinstance(
|
||||
self.pixel_object[0][-1], float
|
||||
)
|
||||
|
|
@ -84,6 +81,4 @@ class Pulse(Animation):
|
|||
pulse_generator,
|
||||
)
|
||||
|
||||
self._generator = pulse_generator(
|
||||
self._period, self, white, dotstar_pwm=dotstar
|
||||
)
|
||||
self._generator = pulse_generator(self._period, self, dotstar_pwm=dotstar)
|
||||
|
|
|
|||
|
|
@ -74,14 +74,11 @@ class SparklePulse(Sparkle):
|
|||
self._max_intensity = max_intensity
|
||||
self._min_intensity = min_intensity
|
||||
self._period = period
|
||||
white = len(pixel_object) == 4 and isinstance(pixel_object[0][-1], int)
|
||||
dotstar = len(pixel_object) == 4 and isinstance(pixel_object[0][-1], float)
|
||||
super().__init__(
|
||||
pixel_object, speed=speed, color=color, num_sparkles=1, name=name
|
||||
)
|
||||
self._generator = pulse_generator(
|
||||
self._period, self, white, dotstar_pwm=dotstar
|
||||
)
|
||||
self._generator = pulse_generator(self._period, self, dotstar_pwm=dotstar)
|
||||
|
||||
def draw(self):
|
||||
self._sparkle_color = next(self._generator)
|
||||
|
|
|
|||
233
adafruit_led_animation/grid.py
Normal file
233
adafruit_led_animation/grid.py
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2019 Roy Hooper
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
"""
|
||||
`adafruit_led_animation.grid`
|
||||
================================================================================
|
||||
|
||||
PixelGrid helper for 2D animations.
|
||||
|
||||
* Author(s): Roy Hooper
|
||||
|
||||
Implementation Notes
|
||||
--------------------
|
||||
|
||||
**Hardware:**
|
||||
|
||||
* `Adafruit NeoPixels <https://www.adafruit.com/category/168>`_
|
||||
* `Adafruit DotStars <https://www.adafruit.com/category/885>`_
|
||||
|
||||
**Software and Dependencies:**
|
||||
|
||||
* Adafruit CircuitPython firmware for the supported boards:
|
||||
https://circuitpython.org/downloads
|
||||
|
||||
"""
|
||||
from micropython import const
|
||||
|
||||
from .helper import PixelMap, horizontal_strip_gridmap, vertical_strip_gridmap
|
||||
|
||||
|
||||
HORIZONTAL = const(1)
|
||||
VERTICAL = const(2)
|
||||
|
||||
|
||||
class PixelGrid:
|
||||
"""
|
||||
PixelGrid lets you address a pixel strip with x and y coordinates.
|
||||
|
||||
:param strip: An object that implements the Neopixel or Dotstar protocol.
|
||||
:param width: Grid width.
|
||||
:param height: Grid height.
|
||||
:param orientation: Orientation of the strip pixels - HORIZONTAL (default) or VERTICAL.
|
||||
:param alternating: Whether the strip alternates direction from row to row (default True).
|
||||
:param reverse_x: Whether the strip X origin is on the right side (default False).
|
||||
:param reverse_y: Whether the strip Y origin is on the bottom (default False).
|
||||
:param tuple top: (x, y) coordinates of grid top left corner (Optional)
|
||||
:param tuple bottom: (x, y) coordinates of grid bottom right corner (Optional)
|
||||
|
||||
To use with individual pixels:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import board
|
||||
import neopixel
|
||||
import time
|
||||
from adafruit_led_animation.grid import PixelGrid, VERTICAL
|
||||
|
||||
pixels = neopixel.NeoPixel(board.D11, 256, auto_write=False)
|
||||
|
||||
grid = PixelGrid(pixels, 32, 8, orientation=VERTICAL, alternating=True)
|
||||
|
||||
for x in range(32):
|
||||
for y in range(8):
|
||||
# pg[x, y] = (y*32) + x
|
||||
pg[x][y] = ((y*32) + x) << 8
|
||||
pg.show()
|
||||
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
strip,
|
||||
width,
|
||||
height,
|
||||
orientation=HORIZONTAL,
|
||||
alternating=True,
|
||||
reverse_x=False,
|
||||
reverse_y=False,
|
||||
top=0,
|
||||
bottom=0,
|
||||
): # pylint: disable=too-many-arguments,too-many-locals
|
||||
self._pixels = strip
|
||||
self._x = []
|
||||
self.height = height
|
||||
self.width = width
|
||||
|
||||
if orientation == HORIZONTAL:
|
||||
mapper = horizontal_strip_gridmap(width, alternating)
|
||||
else:
|
||||
mapper = vertical_strip_gridmap(height, alternating)
|
||||
|
||||
if reverse_x:
|
||||
mapper = reverse_x_mapper(width, mapper)
|
||||
|
||||
if reverse_y:
|
||||
mapper = reverse_y_mapper(height, mapper)
|
||||
|
||||
x_start = 0
|
||||
x_end = width
|
||||
y_start = 0
|
||||
y_end = height
|
||||
if top:
|
||||
x_start, y_start = top
|
||||
if bottom:
|
||||
x_end, y_end = bottom
|
||||
|
||||
self.height = y_end - y_start
|
||||
self.width = x_end - x_start
|
||||
|
||||
for x in range(x_start, x_end):
|
||||
self._x.append(
|
||||
PixelMap(
|
||||
strip,
|
||||
[mapper(x, y) for y in range(y_start, y_end)],
|
||||
individual_pixels=True,
|
||||
)
|
||||
)
|
||||
self.n = len(self._x)
|
||||
|
||||
def __repr__(self):
|
||||
return "[" + ", ".join([str(self[x]) for x in range(self.n)]) + "]"
|
||||
|
||||
def __setitem__(self, index, val):
|
||||
if isinstance(index, slice):
|
||||
raise NotImplementedError("PixelGrid does not support slices")
|
||||
|
||||
if isinstance(index, tuple):
|
||||
self._x[index[0]][index[1]] = val
|
||||
else:
|
||||
raise ValueError("PixelGrid assignment needs a sub-index or x,y coordinate")
|
||||
|
||||
if self._pixels.auto_write:
|
||||
self.show()
|
||||
|
||||
def __getitem__(self, index):
|
||||
if isinstance(index, slice):
|
||||
raise NotImplementedError("PixelGrid does not support slices")
|
||||
if index < 0:
|
||||
index += len(self)
|
||||
if index >= self.n or index < 0:
|
||||
raise IndexError("x is out of range")
|
||||
return self._x[index]
|
||||
|
||||
def __len__(self):
|
||||
return self.n
|
||||
|
||||
@property
|
||||
def brightness(self):
|
||||
"""
|
||||
brightness from the underlying strip.
|
||||
"""
|
||||
return self._pixels.brightness
|
||||
|
||||
@brightness.setter
|
||||
def brightness(self, brightness):
|
||||
# pylint: disable=attribute-defined-outside-init
|
||||
self._pixels.brightness = min(max(brightness, 0.0), 1.0)
|
||||
|
||||
def fill(self, color):
|
||||
"""
|
||||
Fill the PixelGrid with the specified color.
|
||||
|
||||
:param color: Color to use.
|
||||
"""
|
||||
for strip in self._x:
|
||||
strip.fill(color)
|
||||
|
||||
def show(self):
|
||||
"""
|
||||
Shows the pixels on the underlying strip.
|
||||
"""
|
||||
self._pixels.show()
|
||||
|
||||
@property
|
||||
def auto_write(self):
|
||||
"""
|
||||
auto_write from the underlying strip.
|
||||
"""
|
||||
return self._pixels.auto_write
|
||||
|
||||
@auto_write.setter
|
||||
def auto_write(self, value):
|
||||
self._pixels.auto_write = value
|
||||
|
||||
|
||||
def reverse_x_mapper(width, mapper):
|
||||
"""
|
||||
Returns a coordinate mapper function for grids with reversed X coordinates.
|
||||
|
||||
:param width: width of strip
|
||||
:param mapper: grid mapper to wrap
|
||||
:return: mapper(x, y)
|
||||
"""
|
||||
max_x = width - 1
|
||||
|
||||
def x_mapper(x, y):
|
||||
return mapper(max_x - x, y)
|
||||
|
||||
return x_mapper
|
||||
|
||||
|
||||
def reverse_y_mapper(height, mapper):
|
||||
"""
|
||||
Returns a coordinate mapper function for grids with reversed Y coordinates.
|
||||
|
||||
:param height: width of strip
|
||||
:param mapper: grid mapper to wrap
|
||||
:return: mapper(x, y)
|
||||
"""
|
||||
max_y = height - 1
|
||||
|
||||
def y_mapper(x, y):
|
||||
return mapper(x, max_y - y)
|
||||
|
||||
return y_mapper
|
||||
|
|
@ -45,6 +45,7 @@ Implementation Notes
|
|||
import math
|
||||
|
||||
from . import NANOS_PER_SECOND, monotonic_ns
|
||||
from .color import calculate_intensity
|
||||
|
||||
|
||||
class PixelMap:
|
||||
|
|
@ -69,7 +70,7 @@ class PixelMap:
|
|||
pixel_wing_horizontal[0] = (255, 255, 0)
|
||||
pixel_wing_horizontal.show()
|
||||
|
||||
To use with individual pixels:
|
||||
To use with groups of individual pixels:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
|
@ -92,24 +93,57 @@ class PixelMap:
|
|||
pixel_wing_vertical[0] = (255, 255, 0)
|
||||
pixel_wing_vertical.show()
|
||||
|
||||
To use with individual pixels:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import board
|
||||
import neopixel
|
||||
import time
|
||||
from adafruit_led_animation.helper import PixelMap
|
||||
|
||||
pixels = neopixel.NeoPixel(board.D6, 8, auto_write=False)
|
||||
|
||||
pixel_map = PixelMap(pixels, [
|
||||
0, 7, 1, 6, 2, 5, 3, 4
|
||||
], individual_pixels=True)
|
||||
|
||||
n = 0
|
||||
while True:
|
||||
pixel_map[n] = AMBER
|
||||
pixel_map.show()
|
||||
n = n + 1
|
||||
if n > 7:
|
||||
n = 0
|
||||
pixel_map.fill(0)
|
||||
time.sleep(0.25)
|
||||
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, strip, pixel_ranges, individual_pixels=False):
|
||||
self._pixels = strip
|
||||
self._ranges = pixel_ranges
|
||||
|
||||
self.n = len(self._ranges)
|
||||
if self.n == 0:
|
||||
raise ValueError("A PixelMap must have at least one pixel defined")
|
||||
self._individual_pixels = individual_pixels
|
||||
self._expand_ranges()
|
||||
|
||||
def _expand_ranges(self):
|
||||
if not self._individual_pixels:
|
||||
self._ranges = [list(range(start, end)) for start, end in self._ranges]
|
||||
return
|
||||
if isinstance(self._ranges[0], int):
|
||||
self._ranges = [[n] for n in self._ranges]
|
||||
|
||||
def __repr__(self):
|
||||
return "[" + ", ".join([str(x) for x in self]) + "]"
|
||||
return "[" + ", ".join([str(self[x]) for x in range(self.n)]) + "]"
|
||||
|
||||
def _set_pixels(self, index, val):
|
||||
if self._individual_pixels:
|
||||
for pixel in self._ranges[index]:
|
||||
self._pixels[pixel] = val
|
||||
else:
|
||||
range_start, range_stop = self._ranges[index]
|
||||
self._pixels[range_start:range_stop] = [val] * (range_stop - range_start)
|
||||
for pixel in self._ranges[index]:
|
||||
self._pixels[pixel] = val
|
||||
|
||||
def __setitem__(self, index, val):
|
||||
if isinstance(index, slice):
|
||||
|
|
@ -124,7 +158,7 @@ class PixelMap:
|
|||
else:
|
||||
self._set_pixels(index, val)
|
||||
|
||||
if not self._pixels.auto_write:
|
||||
if self._pixels.auto_write:
|
||||
self.show()
|
||||
|
||||
def __getitem__(self, index):
|
||||
|
|
@ -160,13 +194,9 @@ class PixelMap:
|
|||
|
||||
:param color: Color to fill all pixels referenced by this PixelMap definition with.
|
||||
"""
|
||||
if self._individual_pixels:
|
||||
for pixels in self._ranges:
|
||||
for pixel in pixels:
|
||||
self._pixels[pixel] = color
|
||||
else:
|
||||
for start, stop in self._ranges:
|
||||
self._pixels[start:stop] = [color] * (stop - start)
|
||||
for pixels in self._ranges:
|
||||
for pixel in pixels:
|
||||
self._pixels[pixel] = color
|
||||
|
||||
def show(self):
|
||||
"""
|
||||
|
|
@ -273,7 +303,7 @@ def horizontal_strip_gridmap(width, alternating=True):
|
|||
return mapper
|
||||
|
||||
|
||||
class PixelSubset:
|
||||
class PixelSubset(PixelMap):
|
||||
"""
|
||||
PixelSubset lets you work with a subset of a pixel object.
|
||||
|
||||
|
|
@ -295,78 +325,18 @@ class PixelSubset:
|
|||
"""
|
||||
|
||||
def __init__(self, pixel_object, start, end):
|
||||
self._pixels = pixel_object
|
||||
self._start = start
|
||||
self._end = end
|
||||
self.n = self._end - self._start
|
||||
|
||||
def __repr__(self):
|
||||
return "[" + ", ".join([str(x) for x in self]) + "]"
|
||||
|
||||
def __setitem__(self, index, val):
|
||||
if isinstance(index, slice):
|
||||
start, stop, step = index.indices(self.n)
|
||||
self._pixels[start + self._start : stop + self._start : step] = val
|
||||
else:
|
||||
self._pixels[index + self._start] = val
|
||||
|
||||
if not self._pixels.auto_write:
|
||||
self.show()
|
||||
|
||||
def __getitem__(self, index):
|
||||
if isinstance(index, slice):
|
||||
start, stop, step = index.indices(self.n)
|
||||
return self._pixels[start + self._start : stop + self._start : step]
|
||||
if index < 0:
|
||||
index += len(self)
|
||||
if index >= self.n or index < 0:
|
||||
raise IndexError
|
||||
return self._pixels[index]
|
||||
|
||||
def __len__(self):
|
||||
return self.n
|
||||
|
||||
@property
|
||||
def brightness(self):
|
||||
"""
|
||||
brightness from the underlying strip.
|
||||
"""
|
||||
return self._pixels.brightness
|
||||
|
||||
@brightness.setter
|
||||
def brightness(self, brightness):
|
||||
self._pixels.brightness = min(max(brightness, 0.0), 1.0)
|
||||
|
||||
def fill(self, color):
|
||||
"""
|
||||
Fill the used pixel ranges with color.
|
||||
"""
|
||||
self._pixels[self._start : self._end] = [color] * (self.n)
|
||||
|
||||
def show(self):
|
||||
"""
|
||||
Shows the pixels on the underlying strip.
|
||||
"""
|
||||
self._pixels.show()
|
||||
|
||||
@property
|
||||
def auto_write(self):
|
||||
"""
|
||||
auto_write from the underlying strip.
|
||||
"""
|
||||
return self._pixels.auto_write
|
||||
|
||||
@auto_write.setter
|
||||
def auto_write(self, value):
|
||||
self._pixels.auto_write = value
|
||||
super().__init__(
|
||||
pixel_object,
|
||||
pixel_ranges=[[n] for n in range(start, end)],
|
||||
individual_pixels=True,
|
||||
)
|
||||
|
||||
|
||||
def pulse_generator(period: float, animation_object, white=False, dotstar_pwm=False):
|
||||
def pulse_generator(period: float, animation_object, dotstar_pwm=False):
|
||||
"""
|
||||
Generates a sequence of colors for a pulse, based on the time period specified.
|
||||
:param period: Pulse duration in seconds.
|
||||
:param animation_object: An animation object to interact with.
|
||||
:param white: Whether the pixel strip has a white pixel.
|
||||
:param dotstar_pwm: Whether to use the dostar per pixel PWM value for brightness control.
|
||||
"""
|
||||
period = int(period * NANOS_PER_SECOND)
|
||||
|
|
@ -376,7 +346,6 @@ def pulse_generator(period: float, animation_object, white=False, dotstar_pwm=Fa
|
|||
cycle_position = 0
|
||||
last_pos = 0
|
||||
while True:
|
||||
fill_color = list(animation_object.color)
|
||||
now = monotonic_ns()
|
||||
time_since_last_draw = now - last_update
|
||||
last_update = now
|
||||
|
|
@ -388,12 +357,12 @@ def pulse_generator(period: float, animation_object, white=False, dotstar_pwm=Fa
|
|||
pos = period - pos
|
||||
intensity = pos / half_period
|
||||
if dotstar_pwm:
|
||||
fill_color = (fill_color[0], fill_color[1], fill_color[2], intensity)
|
||||
fill_color = (
|
||||
animation_object.color[0],
|
||||
animation_object.color[1],
|
||||
animation_object.color[2],
|
||||
intensity,
|
||||
)
|
||||
yield fill_color
|
||||
continue
|
||||
if white and len(fill_color) == 4:
|
||||
fill_color[3] = int(fill_color[3] * intensity)
|
||||
fill_color[0] = int(fill_color[0] * intensity)
|
||||
fill_color[1] = int(fill_color[1] * intensity)
|
||||
fill_color[2] = int(fill_color[2] * intensity)
|
||||
yield fill_color
|
||||
yield calculate_intensity(animation_object.color, intensity)
|
||||
|
|
|
|||
Loading…
Reference in a new issue