1use rand::{prelude::Distribution, distributions::Standard};
2use svg::{node::element::Polygon, Node};
3
4use crate::{to_svg::ToSVG, vec2::Vec2};
5
6use super::traits::Tile;
7
8#[derive(Clone, Copy)]
9pub enum ElasticTileType {
10 A,
18 B,
26 C,
34 D
42}
43
44impl ToString for ElasticTileType {
45 fn to_string(&self) -> String {
46 return match self {
47 ElasticTileType::A => "A".to_owned(),
48 ElasticTileType::B => "B".to_owned(),
49 ElasticTileType::C => "C".to_owned(),
50 ElasticTileType::D => "D".to_owned(),
51 };
52 }
53}
54
55#[derive(Clone, Copy)]
56pub struct ElasticTriangleTile {
57 t: f32,
58 tile_type: ElasticTileType
59}
60
61impl ElasticTriangleTile {
62 pub const fn new(t: f32, tile_type: ElasticTileType) -> Self {
63 return Self { t, tile_type };
64 }
65
66 pub const fn type_a() -> Self {
67 return Self::new(0.5, ElasticTileType::A);
68 }
69
70 pub const fn type_b() -> Self {
71 return Self::new(0.5, ElasticTileType::B);
72 }
73
74 pub const fn type_c() -> Self {
75 return Self::new(0.5, ElasticTileType::C);
76 }
77
78 pub const fn type_d() -> Self {
79 return Self::new(0.5, ElasticTileType::D);
80 }
81
82 fn point(&self) -> Vec2<f32> {
83 return match self.tile_type {
84 ElasticTileType::A => Vec2::new(1.0 - (0.5 * self.t + 0.25), 0.5 * self.t + 0.25),
85 ElasticTileType::B => Vec2::new(1.0 - (0.5 * self.t + 0.25), 1.0 - (0.5 * self.t + 0.25)),
86 ElasticTileType::C => Vec2::new(0.5 * self.t + 0.25, 1.0 - (0.5 * self.t + 0.25)),
87 ElasticTileType::D => Vec2::new(0.5 * self.t + 0.25, 0.5 * self.t + 0.25),
88 };
89 }
90}
91
92impl Default for ElasticTriangleTile {
93 #[inline]
94 fn default() -> Self {
95 return Self::type_a();
96 }
97}
98
99impl Tile for ElasticTriangleTile {
100 fn set_brightness(&mut self, brightness: f32) {
101 if brightness < 0.25 {
102 self.t = 0.0;
103 } else if brightness > 0.75 {
104 self.t = 1.0;
105 } else {
106 self.t = 2.0 * brightness - 0.5;
107 }
108 }
109}
110
111impl ToSVG for ElasticTriangleTile {
112 fn to_svg_node(&self) -> Box<dyn Node> {
113 let (mut x, mut y) = match self.tile_type {
114 ElasticTileType::A => (vec![1_f32, 0_f32, 0_f32], vec![1_f32, 1_f32, 0_f32]),
115 ElasticTileType::B => (vec![0_f32, 0_f32, 1_f32], vec![1_f32, 0_f32, 0_f32]),
116 ElasticTileType::C => (vec![0_f32, 1_f32, 1_f32], vec![0_f32, 0_f32, 1_f32]),
117 ElasticTileType::D => (vec![1_f32, 1_f32, 0_f32], vec![0_f32, 1_f32, 1_f32])
118 };
119
120 let t = self.point();
121 x.push(t.x());
122 y.push(t.y());
123
124 let points: Vec<f32> = x.into_iter()
125 .zip(
126 y.into_iter()
127 )
128 .flat_map(|(x, y)| [x, y])
129 .collect();
130
131 let polygon = Polygon::new()
132 .set("points", points)
133 .set("t", self.t)
134 .set("type", self.tile_type.to_string());
135
136 return Box::new(polygon);
137 }
138}
139
140impl Distribution<ElasticTriangleTile> for Standard {
141 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> ElasticTriangleTile {
142 match rng.gen_range(0..=3) {
143 0 => ElasticTriangleTile::type_a(),
144 1 => ElasticTriangleTile::type_b(),
145 2 => ElasticTriangleTile::type_c(),
146 _ => ElasticTriangleTile::type_d()
147 }
148 }
149}