add rain pattern

This commit is contained in:
Tobias Ollive 2022-03-11 18:43:48 +01:00
parent ee133379f2
commit a9abc2e05b
10 changed files with 220 additions and 74 deletions

View File

@ -17,17 +17,27 @@
# blue: 255 # blue: 255
# max_iteration: 10 # max_iteration: 10
# period: 50 # period: 50
- pattern:
type: Rain
color: &blue
red: 0
green: 0
blue: 255
background_color: &black
red: 0
green: 0
blue: 0
stability: 10
lines: 5
period: 200
- pattern: - pattern:
type: Fade type: Fade
nbr_iterations: 20 steps: 20
begin_color: &red begin_color: &red
red: 255 red: 255
green: 0 green: 0
blue: 0 blue: 0
end_color: &blue end_color: *blue
red: 0
green: 0
blue: 255
period: 200 period: 200
- pattern: - pattern:
type: ColorWipe type: ColorWipe
@ -60,6 +70,6 @@
max_iteration: 200 max_iteration: 200
period: 10 period: 10
- pattern: - pattern:
type: ColorWipe type: Scanner
color: *blue color: *blue
period: 100 period: 100

View File

@ -15,6 +15,7 @@ use crate::patterns::color_wipe::ColorWipe;
use crate::patterns::fade::Fade; use crate::patterns::fade::Fade;
use crate::patterns::fill_random::FillRandom; use crate::patterns::fill_random::FillRandom;
use crate::patterns::fill_unstable::FillUnstable; use crate::patterns::fill_unstable::FillUnstable;
use crate::patterns::rain::Rain;
use crate::patterns::rainbow::Rainbow; use crate::patterns::rainbow::Rainbow;
use crate::patterns::scanner::Scanner; use crate::patterns::scanner::Scanner;
@ -28,12 +29,14 @@ pub(crate) enum Patterns<const N: usize> {
FillRandom(FillRandom<N>), FillRandom(FillRandom<N>),
FillUnstable(FillUnstable<N>), FillUnstable(FillUnstable<N>),
Blink(Blink<N>), Blink(Blink<N>),
Rain(Rain<N>),
} }
pub trait Pattern : Iterator { pub trait Pattern : Iterator {
type Strip; type Strip;
fn init(&self) -> Option<Self::Strip>; fn init(&mut self) -> Option<Self::Strip>;
fn is_last_iteration(&self) -> bool;
} }
impl<const N: usize> Iterator for Patterns<N> { impl<const N: usize> Iterator for Patterns<N> {
@ -48,6 +51,7 @@ impl<const N: usize> Iterator for Patterns<N> {
Patterns::FillRandom(p) => p.next(), Patterns::FillRandom(p) => p.next(),
Patterns::FillUnstable(p) => p.next(), Patterns::FillUnstable(p) => p.next(),
Patterns::Blink(p) => p.next(), Patterns::Blink(p) => p.next(),
Patterns::Rain(p) => p.next(),
} }
} }
} }
@ -55,7 +59,7 @@ impl<const N: usize> Iterator for Patterns<N> {
impl<const N: usize> Pattern for Patterns<N> { impl<const N: usize> Pattern for Patterns<N> {
type Strip = Strip<N>; type Strip = Strip<N>;
fn init(&self) -> Option<Self::Strip> { fn init(&mut self) -> Option<Self::Strip> {
match self { match self {
Patterns::Rainbow(p) => p.init(), Patterns::Rainbow(p) => p.init(),
Patterns::Fade(p) => p.init(), Patterns::Fade(p) => p.init(),
@ -64,6 +68,20 @@ impl<const N: usize> Pattern for Patterns<N> {
Patterns::FillRandom(p) => p.init(), Patterns::FillRandom(p) => p.init(),
Patterns::FillUnstable(p) => p.init(), Patterns::FillUnstable(p) => p.init(),
Patterns::Blink(p) => p.init(), Patterns::Blink(p) => p.init(),
Patterns::Rain(p) => p.init(),
}
}
fn is_last_iteration(&self) -> bool {
match self {
Patterns::Rainbow(p) => p.is_last_iteration(),
Patterns::Fade(p) => p.is_last_iteration(),
Patterns::ColorWipe(p) => p.is_last_iteration(),
Patterns::Scanner(p) => p.is_last_iteration(),
Patterns::FillRandom(p) => p.is_last_iteration(),
Patterns::FillUnstable(p) => p.is_last_iteration(),
Patterns::Blink(p) => p.is_last_iteration(),
Patterns::Rain(p) => p.is_last_iteration(),
} }
} }
} }

View File

@ -17,9 +17,22 @@ pub struct Blink<const N: usize> {
impl<const N: usize> Pattern for Blink<N> { impl<const N: usize> Pattern for Blink<N> {
type Strip = Strip<N>; type Strip = Strip<N>;
fn init(&self) -> Option<Self::Strip> { fn init(&mut self) -> Option<Self::Strip> {
None None
} }
fn is_last_iteration(&self) -> bool {
match self.max_iteration {
None => { false }
Some(max_iter) => {
if self.current_iteration >= max_iter {
true
} else {
false
}
}
}
}
} }
impl<const N: usize> Iterator for Blink<N> { impl<const N: usize> Iterator for Blink<N> {
@ -29,12 +42,10 @@ impl<const N: usize> Iterator for Blink<N> {
let value = self.fade.next(); let value = self.fade.next();
match value { match value {
None => { None => {
if let Some(iter_max) = self.max_iteration { if self.is_last_iteration() {
if self.current_iteration >= iter_max { return None;
return None;
}
self.current_iteration += 1;
} }
self.current_iteration += 1;
self.fade.current_iteration = 0; self.fade.current_iteration = 0;
std::mem::swap(&mut self.fade.begin_color, &mut self.fade.end_color); std::mem::swap(&mut self.fade.begin_color, &mut self.fade.end_color);
self.fade.next() self.fade.next()

View File

@ -23,29 +23,43 @@ pub struct ColorWipe<const N: usize> {
impl<const N: usize> Pattern for ColorWipe<N> { impl<const N: usize> Pattern for ColorWipe<N> {
type Strip = Strip<N>; type Strip = Strip<N>;
fn init(&self) -> Option<Self::Strip> { fn init(&mut self) -> Option<Self::Strip> {
if let Some(color) = self.background_color { if let Some(color) = self.background_color {
Some(Strip::<N>::new(color)) Some(Strip::<N>::new(color))
} else { } else {
None None
} }
} }
fn is_last_iteration(&self) -> bool {
match self.max_iteration {
None => { false }
Some(max_iter) => {
if self.current_iteration >= max_iter {
true
} else {
false
}
}
}
}
} }
impl<const N: usize> Iterator for ColorWipe<N> { impl<const N: usize> Iterator for ColorWipe<N> {
type Item = Strip<N>; type Item = Strip<N>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if self.is_last_iteration() {
return None;
}
let mut strip = Strip::default(); let mut strip = Strip::default();
if let Some(c) = self.background_color { if let Some(c) = self.background_color {
strip.fill(c); strip.fill(c);
} }
let iteration = self.current_iteration % N; let iteration = self.current_iteration % N;
if let Some(max_iteration) = self.max_iteration {
if self.current_iteration >= max_iteration {
return None;
}
}
for i in 0..iteration { for i in 0..iteration {
strip[i] = Some(self.color); strip[i] = Some(self.color);

View File

@ -8,7 +8,7 @@ use serde::{Serialize, Deserialize};
pub struct Fade<const N: usize> { pub struct Fade<const N: usize> {
#[serde(default)] #[serde(default)]
pub(crate) current_iteration: usize, pub(crate) current_iteration: usize,
pub(crate) nbr_iterations: usize, pub(crate) steps: usize,
pub(crate) begin_color: PixelColor, pub(crate) begin_color: PixelColor,
pub(crate) end_color: PixelColor, pub(crate) end_color: PixelColor,
} }
@ -20,9 +20,13 @@ fn fade_value(value_start: u8, value_end: u8, index: usize, nbr_iter: usize) ->
impl<const N: usize> Pattern for Fade<N> { impl<const N: usize> Pattern for Fade<N> {
type Strip = Strip<N>; type Strip = Strip<N>;
fn init(&self) -> Option<Self::Strip> { fn init(&mut self) -> Option<Self::Strip> {
None None
} }
fn is_last_iteration(&self) -> bool {
self.current_iteration >= self.steps
}
} }
impl<const N: usize> Iterator for Fade<N> { impl<const N: usize> Iterator for Fade<N> {
@ -31,7 +35,7 @@ impl<const N: usize> Iterator for Fade<N> {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
let mut strip = Strip::default(); let mut strip = Strip::default();
if self.current_iteration >= self.nbr_iterations { if self.is_last_iteration() {
return None; return None;
} }
@ -39,19 +43,19 @@ impl<const N: usize> Iterator for Fade<N> {
self.begin_color.red, self.begin_color.red,
self.end_color.red, self.end_color.red,
self.current_iteration, self.current_iteration,
self.nbr_iterations, self.steps,
); );
let green = fade_value( let green = fade_value(
self.begin_color.green, self.begin_color.green,
self.end_color.green, self.end_color.green,
self.current_iteration, self.current_iteration,
self.nbr_iterations, self.steps,
); );
let blue = fade_value( let blue = fade_value(
self.begin_color.blue, self.begin_color.blue,
self.end_color.blue, self.end_color.blue,
self.current_iteration, self.current_iteration,
self.nbr_iterations, self.steps,
); );
let current_color = PixelColor { red, green, blue }; let current_color = PixelColor { red, green, blue };

View File

@ -11,26 +11,37 @@ pub struct FillRandom<const N: usize> {
pub(crate) color: PixelColor, pub(crate) color: PixelColor,
pub(crate) stability: usize, pub(crate) stability: usize,
pub(crate) max_iteration: Option<usize>, pub(crate) max_iteration: Option<usize>,
#[serde(default)]
pub(crate) current_iteration: usize,
} }
impl<const N: usize> Pattern for FillRandom<N> { impl<const N: usize> Pattern for FillRandom<N> {
type Strip = Strip<N>; type Strip = Strip<N>;
fn init(&self) -> Option<Self::Strip> { fn init(&mut self) -> Option<Self::Strip> {
None None
} }
fn is_last_iteration(&self) -> bool {
match self.max_iteration {
None => { false }
Some(max_iter) => {
if self.current_iteration >= max_iter {
true
} else {
false
}
}
}
}
} }
impl<const N: usize> Iterator for FillRandom<N> { impl<const N: usize> Iterator for FillRandom<N> {
type Item = Strip<N>; type Item = Strip<N>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if let Some(iteration) = self.max_iteration { if self.is_last_iteration() {
if iteration == 0 { return None;
return None;
} else {
self.max_iteration = Some(iteration - 1);
}
} }
let mut strip = Strip::<N>::default(); let mut strip = Strip::<N>::default();
@ -55,6 +66,7 @@ impl<const N: usize> Iterator for FillRandom<N> {
let c = PixelColor { red, green, blue }; let c = PixelColor { red, green, blue };
strip[i] = Some(c); strip[i] = Some(c);
} }
self.current_iteration += 1;
Some(strip) Some(strip)
} }
} }

View File

@ -11,26 +11,37 @@ pub struct FillUnstable<const N: usize> {
pub(crate) color: PixelColor, pub(crate) color: PixelColor,
pub(crate) stability: usize, pub(crate) stability: usize,
pub(crate) max_iteration: Option<usize>, pub(crate) max_iteration: Option<usize>,
#[serde(default)]
pub(crate) current_iteration: usize,
} }
impl<const N: usize> Pattern for FillUnstable<N> { impl<const N: usize> Pattern for FillUnstable<N> {
type Strip = Strip<N>; type Strip = Strip<N>;
fn init(&self) -> Option<Self::Strip> { fn init(&mut self) -> Option<Self::Strip> {
None None
} }
fn is_last_iteration(&self) -> bool {
match self.max_iteration {
None => { false }
Some(max_iter) => {
if self.current_iteration >= max_iter {
true
} else {
false
}
}
}
}
} }
impl<const N: usize> Iterator for FillUnstable<N> { impl<const N: usize> Iterator for FillUnstable<N> {
type Item = Strip<N>; type Item = Strip<N>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if let Some(iteration) = self.max_iteration { if self.is_last_iteration() {
if iteration == 0 { return None;
return None;
} else {
self.max_iteration = Some(iteration - 1);
}
} }
let mut strip = Strip::<N>::default(); let mut strip = Strip::<N>::default();
@ -52,6 +63,7 @@ impl<const N: usize> Iterator for FillUnstable<N> {
blue = self.color.blue.saturating_sub(blue_delta); blue = self.color.blue.saturating_sub(blue_delta);
} }
strip.fill(PixelColor { red, green, blue }); strip.fill(PixelColor { red, green, blue });
self.current_iteration += 1;
Some(strip) Some(strip)
} }
} }

View File

@ -1,47 +1,81 @@
use crate::patterns::PixelColor; use rand::Rng;
use crate::patterns::{Pattern, PixelColor};
use crate::Strip; use crate::Strip;
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
/// # scanner pattern /// # rain pattern
/// color one pixel with a color and leave a train of this color fading to black /// randomly fall colors from top or bottom.
///
/// ///
/// # note /// # note
/// ///
/// background_color work only for color not set by scanner pattern /// `stability` is the probability (between 0 an 1) that any led will light on.
/// The probability of at least one led light on is `stability*number of lines`
///
/// this pattern works only for 5x5 square
#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)] #[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)]
pub struct Scanner<const N: usize> { pub struct Rain<const N: usize> {
#[serde(default)]
current_iteration: usize,
pub(crate) color: PixelColor, pub(crate) color: PixelColor,
pub(crate) background_color: Option<PixelColor>, pub(crate) background_color: Option<PixelColor>,
pub(crate) max_iteration: Option<usize>,
#[serde(default)]
pub(crate) current_iteration: usize,
pub(crate) stability: usize, pub(crate) stability: usize,
pub(crate) lines: usize,
#[serde(skip)] #[serde(skip)]
strip : Strip<N>, drops : Strip<N>,
} }
impl<const N: usize> Iterator for Scanner<N> { impl<const N: usize> Pattern for Rain<N> {
type Strip = Strip<N>;
fn init(&mut self) -> Option<Self::Strip> {
if let Some(color) = self.background_color {
self.drops = Strip::<N>::new(color);
Some(Strip::<N>::new(color))
} else {
None
}
}
fn is_last_iteration(&self) -> bool {
match self.max_iteration {
None => { false }
Some(max_iter) => {
if self.current_iteration >= max_iter {
true
} else {
false
}
}
}
}
}
impl<const N: usize> Iterator for Rain<N> {
type Item = Strip<N>; type Item = Strip<N>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
let mut strip = Strip::<N>::default(); let mut strip = Strip::<N>::default();
if let Some(c) = self.background_color {
strip.fill(c);
} else {
strip.fill(PixelColor::default());
}
let current_led = self.current_iteration % N; for i in 0..(N-self.lines) {
let min_led; strip[i+self.lines] = self.drops[i];
if current_led < 8 {
min_led = 0;
} else {
min_led = current_led - 8;
} }
let mut c = self.color; let mut rng = rand::thread_rng();
for i in min_led..current_led { for i in 0..self.lines {
strip[i] = Some(c); if rng.gen_bool(self.stability as f64 / 100 as f64) {
c = c / 2; strip[i] = Some(self.color);
} else {
let c = strip[i+self.lines];
if self.background_color != c && c != Some(PixelColor::default()) {
strip[i] = Some(strip[i+self.lines].unwrap()/ 2);
} else {
strip[i] = self.background_color;
}
}
} }
self.drops = strip.clone();
self.current_iteration += 1; self.current_iteration += 1;
Some(strip) Some(strip)
} }

View File

@ -23,19 +23,30 @@ pub struct Rainbow<const N: usize> {
impl<const N: usize> Pattern for Rainbow<N> { impl<const N: usize> Pattern for Rainbow<N> {
type Strip = Strip<N>; type Strip = Strip<N>;
fn init(&self) -> Option<Self::Strip> { fn init(&mut self) -> Option<Self::Strip> {
None None
} }
fn is_last_iteration(&self) -> bool {
match self.max_iteration {
None => { false }
Some(max_iter) => {
if self.current_iteration >= max_iter {
true
} else {
false
}
}
}
}
} }
impl<const N: usize> Iterator for Rainbow<N> { impl<const N: usize> Iterator for Rainbow<N> {
type Item = Strip<N>; type Item = Strip<N>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if let Some(nbr_iteration) = self.max_iteration { if self.is_last_iteration() {
if nbr_iteration == self.current_iteration { return None;
return None;
}
} }
let mut strip = Strip::default(); let mut strip = Strip::default();
let step = self.step.unwrap_or(255 / N); let step = self.step.unwrap_or(255 / N);

View File

@ -14,29 +14,49 @@ pub struct Scanner<const N: usize> {
pub(crate) current_iteration: usize, pub(crate) current_iteration: usize,
pub(crate) color: PixelColor, pub(crate) color: PixelColor,
pub(crate) background_color: Option<PixelColor>, pub(crate) background_color: Option<PixelColor>,
#[serde(default)]
pub(crate) max_iteration: Option<usize>,
} }
impl<const N:usize> Pattern for Scanner<N> { impl<const N:usize> Pattern for Scanner<N> {
type Strip = Strip<N>; type Strip = Strip<N>;
fn init(&self) -> Option<Self::Strip> { fn init(&mut self) -> Option<Self::Strip> {
if let Some(color) = self.background_color { if let Some(color) = self.background_color {
Some(Strip::<N>::new(color)) Some(Strip::<N>::new(color))
} else { } else {
None None
} }
} }
fn is_last_iteration(&self) -> bool {
match self.max_iteration {
None => { false }
Some(max_iter) => {
if self.current_iteration >= max_iter {
true
} else {
false
}
}
}
}
} }
impl<const N: usize> Iterator for Scanner<N> { impl<const N: usize> Iterator for Scanner<N> {
type Item = Strip<N>; type Item = Strip<N>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
let mut strip = Strip::<N>::default(); if self.is_last_iteration() {
if let Some(c) = self.background_color { return None;
strip.fill(c); }
let mut strip : Strip<N>;
if let Some(color) = self.background_color {
strip = Strip::new(color);
} else { } else {
strip.fill(PixelColor::default()); strip = Strip::default();
} }
let current_led = self.current_iteration % N; let current_led = self.current_iteration % N;