mirror of
https://github.com/ricoriedel/wipe.git
synced 2024-11-23 00:16:38 +00:00
Add rhombus rotation and stripes
This commit is contained in:
parent
8b551c3d1c
commit
d8fdc142e6
@ -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
51
src/animation/rhombus.rs
Normal 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
46
src/animation/rotation.rs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
@ -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
35
src/fill/stripes.rs
Normal 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)));
|
||||||
|
}
|
||||||
|
}
|
17
src/main.rs
17
src/main.rs
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
12
src/vec.rs
12
src/vec.rs
@ -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.
|
||||||
|
Loading…
Reference in New Issue
Block a user