Add patterns

This commit is contained in:
Rico Riedel 2022-07-29 16:50:27 +02:00
parent afe3dc4122
commit 2bdd88a7e8
No known key found for this signature in database
GPG Key ID: 75AC868575DE7B18
6 changed files with 272 additions and 0 deletions

58
src/pattern/circle.rs Normal file
View File

@ -0,0 +1,58 @@
use crate::pattern::{Config, Pattern, PatternFactory};
use crate::vec::Vector;
#[derive(Default)]
pub struct CircleFactory;
pub struct Circle {
center: Vector,
radius: f32,
}
impl PatternFactory for CircleFactory {
fn name(&self) -> String {
stringify!(Circle).to_lowercase()
}
fn create(&self, config: &Config) -> Box<dyn Pattern> {
Box::new(Circle::new(config))
}
}
impl Circle {
pub fn new(config: &Config) -> Self {
let center = config.size.center();
let radius = center.len();
Self { center, radius }
}
}
impl Pattern for Circle {
fn sample(&self, pos: Vector) -> f32 {
(pos - self.center).len() / self.radius
}
}
#[cfg(test)]
mod test {
use super::*;
use approx::*;
#[test]
fn name() {
assert_eq!("circle", CircleFactory::default().name());
}
#[test]
fn sample() {
let config = Config {
size: Vector::new(10.0, 20.0),
step: 0.0,
};
let pattern = Circle::new(&config);
assert_abs_diff_eq!(1.0, pattern.sample(Vector::new(0.0, 0.0)), epsilon = 0.1);
assert_abs_diff_eq!(0.0, pattern.sample(Vector::new(5.0, 10.0)), epsilon = 0.1);
assert_abs_diff_eq!(0.5, pattern.sample(Vector::new(7.5, 15.0)), epsilon = 0.1);
}
}

57
src/pattern/line.rs Normal file
View File

@ -0,0 +1,57 @@
use crate::pattern::{Config, Pattern, PatternFactory};
use crate::vec::Vector;
#[derive(Default)]
pub struct LineFactory;
pub struct Line {
width: f32,
}
impl PatternFactory for LineFactory {
fn name(&self) -> String {
stringify!(Line).to_lowercase()
}
fn create(&self, config: &Config) -> Box<dyn Pattern> {
Box::new(Line::new(config))
}
}
impl Line {
pub fn new(config: &Config) -> Self {
let width = config.size.x;
Self { width }
}
}
impl Pattern for Line {
fn sample(&self, pos: Vector) -> f32 {
pos.x / self.width
}
}
#[cfg(test)]
mod test {
use super::*;
use approx::*;
#[test]
fn name() {
assert_eq!("line", LineFactory::default().name());
}
#[test]
fn sample() {
let config = Config {
size: Vector::new(20.0, 0.0),
step: 0.0,
};
let pattern = Line::new(&config);
assert_abs_diff_eq!(0.0, pattern.sample(Vector::new(0.0, 4.0)), epsilon = 0.1);
assert_abs_diff_eq!(0.4, pattern.sample(Vector::new(8.0, 8.0)), epsilon = 0.1);
assert_abs_diff_eq!(0.8, pattern.sample(Vector::new(16.0, 7.0)), epsilon = 0.1);
assert_abs_diff_eq!(1.0, pattern.sample(Vector::new(20.0, 3.0)), epsilon = 0.1);
}
}

22
src/pattern/mod.rs Normal file
View File

@ -0,0 +1,22 @@
mod circle;
mod line;
mod rhombus;
mod wheel;
use crate::vec::Vector;
#[derive(Copy, Clone)]
pub struct Config {
pub size: Vector,
pub step: f32,
}
pub trait PatternFactory {
fn name(&self) -> String;
fn create(&self, config: &Config) -> Box<dyn Pattern>;
}
pub trait Pattern {
fn sample(&self, pos: Vector) -> f32;
}

59
src/pattern/rhombus.rs Normal file
View File

@ -0,0 +1,59 @@
use crate::pattern::{Config, Pattern, PatternFactory};
use crate::vec::Vector;
#[derive(Default)]
pub struct RhombusFactory;
pub struct Rhombus {
center: Vector,
distance: f32,
}
impl PatternFactory for RhombusFactory {
fn name(&self) -> String {
stringify!(Rhombus).to_lowercase()
}
fn create(&self, config: &Config) -> Box<dyn Pattern> {
Box::new(Rhombus::new(config))
}
}
impl Rhombus {
pub fn new(config: &Config) -> Rhombus {
let center = config.size.center();
let distance = center.sum();
Self { center, distance }
}
}
impl Pattern for Rhombus {
fn sample(&self, pos: Vector) -> f32 {
(pos - self.center).abs().sum() / self.distance
}
}
#[cfg(test)]
mod test {
use super::*;
use approx::*;
#[test]
fn name() {
assert_eq!("rhombus", RhombusFactory::default().name());
}
#[test]
fn sample() {
let config = Config {
size: Vector::new(10.0, 5.0),
step: 0.0,
};
let pattern = Rhombus::new(&config);
assert_abs_diff_eq!(1.0, pattern.sample(Vector::new(0.0, 0.0)), epsilon = 0.1);
assert_abs_diff_eq!(1.0, pattern.sample(Vector::new(10.0, 5.0)), epsilon = 0.1);
assert_abs_diff_eq!(0.0, pattern.sample(Vector::new(5.0, 2.5)), epsilon = 0.1);
assert_abs_diff_eq!(0.5, pattern.sample(Vector::new(7.0, 0.5)), epsilon = 0.1);
}
}

58
src/pattern/wheel.rs Normal file
View File

@ -0,0 +1,58 @@
use crate::pattern::{Config, Pattern, PatternFactory};
use crate::vec::Vector;
use std::f32::consts::PI;
#[derive(Default)]
pub struct WheelFactory;
pub struct Wheel {
center: Vector,
}
impl PatternFactory for WheelFactory {
fn name(&self) -> String {
stringify!(Wheel).to_lowercase()
}
fn create(&self, config: &Config) -> Box<dyn Pattern> {
Box::new(Wheel::new(config))
}
}
impl Wheel {
pub fn new(config: &Config) -> Self {
let center = config.size.center();
Self { center }
}
}
impl Pattern for Wheel {
fn sample(&self, pos: Vector) -> f32 {
((pos - self.center).angle() + PI) / PI / 2.0
}
}
#[cfg(test)]
mod test {
use super::*;
use approx::*;
#[test]
fn name() {
assert_eq!("wheel", WheelFactory::default().name());
}
#[test]
fn sample() {
let config = Config {
size: Vector::new(10.0, 20.0),
step: 0.0,
};
let pattern = Wheel::new(&config);
assert_abs_diff_eq!(0.0, pattern.sample(Vector::new(0.0, 9.0)), epsilon = 0.1);
assert_abs_diff_eq!(1.0, pattern.sample(Vector::new(0.0, 10.0)), epsilon = 0.1);
assert_abs_diff_eq!(0.5, pattern.sample(Vector::new(10.0, 10.0)), epsilon = 0.1);
assert_abs_diff_eq!(0.75, pattern.sample(Vector::new(5.0, 20.0)), epsilon = 0.1);
}
}

View File

@ -15,6 +15,14 @@ impl Vector {
(self.x * self.x + self.y * self.y).sqrt()
}
pub fn abs(&self) -> Vector {
Self::new(self.x.abs(), self.y.abs())
}
pub fn sum(&self) -> f32 {
self.x + self.y
}
pub fn center(&self) -> Vector {
Self::new(self.x / 2.0, self.y / 2.0)
}
@ -49,6 +57,16 @@ mod test {
assert_abs_diff_eq!(8.5, Vector::new(3.0, 8.0).len(), epsilon = 0.1);
}
#[test]
fn abs() {
assert_eq!(Vector::new(3.0, 7.0), Vector::new(-3.0, -7.0).abs());
}
#[test]
fn sum() {
assert_eq!(11.0, Vector::new(3.0, 8.0).sum());
}
#[test]
fn center() {
assert_eq!(Vector::new(4.0, 9.0), Vector::new(8.0, 18.0).center());