Add rhombus rotation and stripes

This commit is contained in:
Nicolas 2022-04-09 19:29:30 +02:00
parent 8b551c3d1c
commit d8fdc142e6
7 changed files with 160 additions and 4 deletions

View File

@ -1,4 +1,6 @@
pub mod circle; pub mod circle;
pub mod rotation;
pub mod rhombus;
use crate::vec::Vector; use crate::vec::Vector;

51
src/animation/rhombus.rs Normal file
View File

@ -0,0 +1,51 @@
use crate::animation::Animation;
use crate::vec::Vector;
const THICKNESS: f32 = 0.2;
const FINAL_DISTANCE: f32 = 1.0 + THICKNESS * 2.0;
pub struct RhombusAnimation {
center: Vector,
thickness: f32,
final_distance: f32,
}
impl RhombusAnimation {
pub fn new(size: Vector) -> Self {
let center = size.center();
let distance = center.sum();
Self {
center,
thickness: distance * THICKNESS,
final_distance: distance * FINAL_DISTANCE,
}
}
}
impl Animation for RhombusAnimation {
fn sample(&self, step: f32, pos: Vector) -> f32 {
let dist = self.final_distance * step - self.thickness;
let pos_dist = (self.center - pos).abs().sum();
(pos_dist - dist) / self.thickness
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn sample() {
let anim = RhombusAnimation::new(Vector::new(30.0, 10.0));
let sample_1 = anim.sample(0.2, Vector::new(5.0, 16.0));
let sample_2 = anim.sample(0.7, Vector::new(22.0, 2.0));
let sample_3 = anim.sample(0.5, Vector::new(4.0, 7.0));
assert!(4.8 < sample_1 && sample_1 < 4.9);
assert!(-1.5 < sample_2 && sample_2 < -1.4);
assert!(0.7 < sample_3 && sample_3 < 0.8);
}
}

46
src/animation/rotation.rs Normal file
View File

@ -0,0 +1,46 @@
use std::f32::consts::PI;
use crate::animation::Animation;
use crate::vec::Vector;
const TWO_PI: f32 = PI * 2.0;
const THICKNESS: f32 = TWO_PI * 0.1;
const FULL_ROTATION: f32 = TWO_PI + THICKNESS * 2.0;
pub struct RotationAnimation {
center: Vector
}
impl RotationAnimation {
pub fn new(size: Vector) -> Self {
Self {
center: size.center()
}
}
}
impl Animation for RotationAnimation {
fn sample(&self, step: f32, pos: Vector) -> f32 {
let angle = FULL_ROTATION * step - PI - THICKNESS;
let pos_angle = (pos - self.center).angle();
(pos_angle - angle) / THICKNESS
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn sample() {
let anim = RotationAnimation::new(Vector::new(30.0, 10.0));
let sample_1 = anim.sample(0.2, Vector::new(5.0, 16.0));
let sample_2 = anim.sample(0.7, Vector::new(22.0, 2.0));
let sample_3 = anim.sample(0.5, Vector::new(4.0, 7.0));
assert!(2.4 < sample_1 && sample_1 < 2.5);
assert!(0.7 < sample_2 && sample_2 < 0.8);
assert!(-2.3 < sample_3 && sample_3 < -2.2);
}
}

View File

@ -1,5 +1,6 @@
pub mod level; pub mod level;
pub mod circle; pub mod circle;
pub mod stripes;
use crate::vec::Vector; use crate::vec::Vector;

35
src/fill/stripes.rs Normal file
View File

@ -0,0 +1,35 @@
use crate::FillMode;
use crate::vec::Vector;
const INTERVAL: f32 = 4.0;
pub struct StripesFillMode {
interval: f32
}
impl StripesFillMode {
pub fn new(size: Vector) -> Self {
Self {
interval: size.smaller() / INTERVAL
}
}
}
impl FillMode for StripesFillMode {
fn sample(&self, _: f32, pos: Vector) -> f32 {
(pos.sum() % self.interval) / self.interval
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn sample() {
let mode = StripesFillMode::new(Vector::new(8.0, 4.0));
assert_eq!(0.25, mode.sample(0.0, Vector::new(1.5, 0.75)));
assert_eq!(0.5, mode.sample(0.0, Vector::new(4.0, 2.5)));
}
}

View File

@ -6,12 +6,15 @@ use clap::ArgEnum;
use rand::rngs::OsRng; use rand::rngs::OsRng;
use crate::animation::Animation; use crate::animation::Animation;
use crate::animation::circle::CircleAnimation; use crate::animation::circle::CircleAnimation;
use crate::animation::rhombus::RhombusAnimation;
use crate::animation::rotation::RotationAnimation;
use crate::char::SimpleCharSampler; use crate::char::SimpleCharSampler;
use crate::choose::{Chooser, Options}; use crate::choose::{Chooser, Options};
use crate::color::{ColorSampler, SimpleColorSampler}; use crate::color::{ColorSampler, SimpleColorSampler};
use crate::fill::circle::CircleFillMode; use crate::fill::circle::CircleFillMode;
use crate::fill::FillMode; use crate::fill::FillMode;
use crate::fill::level::LevelFillMode; use crate::fill::level::LevelFillMode;
use crate::fill::stripes::StripesFillMode;
use crate::render::{Renderer, SamplerRenderer}; use crate::render::{Renderer, SamplerRenderer};
use crate::runner::Runner; use crate::runner::Runner;
use crate::sampler::ComposedSampler; use crate::sampler::ComposedSampler;
@ -34,14 +37,16 @@ mod choose;
#[derive(Copy, Clone, ArgEnum)] #[derive(Copy, Clone, ArgEnum)]
enum AnimationType { enum AnimationType {
Circle Circle,
Rhombus,
Rotation
} }
impl Options for AnimationType { impl Options for AnimationType {
fn all() -> Vec<Self> where Self: Sized { fn all() -> Vec<Self> where Self: Sized {
use AnimationType::*; use AnimationType::*;
vec![Circle] vec![Circle, Rhombus, Rotation]
} }
} }
@ -68,7 +73,8 @@ impl Options for ColorType {
#[derive(Copy, Clone, ArgEnum)] #[derive(Copy, Clone, ArgEnum)]
enum FillModeType { enum FillModeType {
Circle, Circle,
Level Level,
Stripes
} }
impl Options for FillModeType { impl Options for FillModeType {
@ -128,7 +134,9 @@ fn main() -> Result<(), Error> {
fn create_animation(animation: AnimationType, size: Vector) -> Box<dyn Animation> { fn create_animation(animation: AnimationType, size: Vector) -> Box<dyn Animation> {
match animation { match animation {
AnimationType::Circle => Box::new(CircleAnimation::new(size)) AnimationType::Circle => Box::new(CircleAnimation::new(size)),
AnimationType::Rhombus => Box::new(RhombusAnimation::new(size)),
AnimationType::Rotation => Box::new(RotationAnimation::new(size)),
} }
} }
@ -136,6 +144,7 @@ fn create_fill(fill: FillModeType, size: Vector) -> Box<dyn FillMode> {
match fill { match fill {
FillModeType::Circle => Box::new(CircleFillMode::new(size)), FillModeType::Circle => Box::new(CircleFillMode::new(size)),
FillModeType::Level => Box::new(LevelFillMode::new()), FillModeType::Level => Box::new(LevelFillMode::new()),
FillModeType::Stripes => Box::new(StripesFillMode::new(size))
} }
} }

View File

@ -20,10 +20,22 @@ impl Vector {
(self.x * self.x + self.y * self.y).sqrt() (self.x * self.x + self.y * self.y).sqrt()
} }
pub fn angle(self) -> f32 {
self.x.atan2(self.y)
}
pub fn smaller(self) -> f32 { pub fn smaller(self) -> f32 {
self.x.min(self.y) self.x.min(self.y)
} }
pub fn abs(self) -> Vector {
Self::new(self.x.abs(), self.y.abs())
}
pub fn sum(self) -> f32 {
self.x + self.y
}
/// Creates a vector with the on screen coordinates based on the terminal coordinates. /// Creates a vector with the on screen coordinates based on the terminal coordinates.
/// # Arguments /// # Arguments
/// * `x`: The x axis of the terminal character. /// * `x`: The x axis of the terminal character.