Add procedure to blend a list of colors to a 16-length list for LED bars
This commit is contained in:
parent
a4cd232390
commit
9e06823fed
2 changed files with 88 additions and 0 deletions
87
pyjecteur/common.py
Normal file
87
pyjecteur/common.py
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
import logging
|
||||||
|
from colour import Color
|
||||||
|
from typing import List, Callable, Optional, Union, Tuple
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
LedBarLen = 16
|
||||||
|
|
||||||
|
def remove_duplicates(colors: List[Color]) -> Tuple[List[Color], List[int]]:
|
||||||
|
if len(colors) == 0:
|
||||||
|
return ([], [])
|
||||||
|
colors_res = [colors[0]]
|
||||||
|
res_nb = [1]
|
||||||
|
for i in range(1, len(colors)):
|
||||||
|
if colors[i] != colors_res[-1]:
|
||||||
|
colors_res.append(colors[i])
|
||||||
|
res_nb.append(1)
|
||||||
|
else:
|
||||||
|
res_nb[-1] += 1
|
||||||
|
return (colors_res, res_nb)
|
||||||
|
|
||||||
|
def reduplicate(colors: List[Color], repetitions: List[int]) -> List[Color]:
|
||||||
|
"""
|
||||||
|
Re-duplicates a list. Takes in a list of elements and a list of numbers of
|
||||||
|
repetitions. Concatetantes the repeted elements.
|
||||||
|
|
||||||
|
Requires both lists to have the same length
|
||||||
|
"""
|
||||||
|
|
||||||
|
res = []
|
||||||
|
for i in range(len(colors)):
|
||||||
|
for _ in range(repetitions[i]):
|
||||||
|
res.append(colors[i])
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
class InterpType(Enum):
|
||||||
|
"""
|
||||||
|
Interpolation algorithm
|
||||||
|
"""
|
||||||
|
|
||||||
|
NEAREST = 1
|
||||||
|
LINEAR = 2
|
||||||
|
|
||||||
|
class Filling(Enum):
|
||||||
|
|
||||||
|
VOID = 1
|
||||||
|
EXTREMA = 2
|
||||||
|
GREATEST = 3
|
||||||
|
|
||||||
|
def blendLedBar(colors: List[Color],
|
||||||
|
blending: Optional[InterpType] = InterpType.NEAREST,
|
||||||
|
filling: Optional[Filling] = Filling.GREATEST,
|
||||||
|
void_color: Optional[Color] = Color("black")) -> List[Color]:
|
||||||
|
total_len = len(colors)
|
||||||
|
(deduped, rep_nb) = remove_duplicates(colors)
|
||||||
|
if len(deduped) > LedBarLen:
|
||||||
|
# After dedup, there are still too many colors. Only show the first ones
|
||||||
|
logging.warning(f"LED bar interpolation: More than {LedBarLen} colors. Dropping colors")
|
||||||
|
return deduped[:LedBarLen]
|
||||||
|
|
||||||
|
if len(colors) > LedBarLen:
|
||||||
|
# TODO: Try and dedup some colors to save space
|
||||||
|
return colors[:LedBarLen]
|
||||||
|
|
||||||
|
if blending == InterpType.NEAREST:
|
||||||
|
factor = LedBarLen // total_len
|
||||||
|
|
||||||
|
# First pass
|
||||||
|
for i in range(len(rep_nb)):
|
||||||
|
rep_nb[i] *= factor
|
||||||
|
|
||||||
|
gap = LedBarLen - total_len * factor
|
||||||
|
|
||||||
|
# TODO: Add GREATEST
|
||||||
|
# The idea is to first add a repetition to the already longest
|
||||||
|
# repetition to hurt the color ratio as little as possible
|
||||||
|
if gap == 0:
|
||||||
|
return reduplicate(deduped, rep_nb)
|
||||||
|
# If there is still
|
||||||
|
elif filling == Filling.VOID:
|
||||||
|
return (reduplicate(deduped, rep_nb) + ([void_color] * gap))
|
||||||
|
elif filling == Filling.EXTREMA:
|
||||||
|
bot_gap = gap // 2
|
||||||
|
top_gap = gap - bot_gap
|
||||||
|
return (([deduped[0]] * top_gap) + reduplicate(deduped, rep_nb) +
|
||||||
|
([deduped[-1]] * bot_gap))
|
||||||
|
|
|
@ -21,6 +21,7 @@ in
|
||||||
ps.black
|
ps.black
|
||||||
ps.pylint
|
ps.pylint
|
||||||
ps.ipython
|
ps.ipython
|
||||||
|
ps.python-lsp-server
|
||||||
]))
|
]))
|
||||||
pkgs.pyright
|
pkgs.pyright
|
||||||
];
|
];
|
||||||
|
|
Loading…
Reference in a new issue