truchet/tile/
triangle.rs

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    ///
11    /// ```
12    /// |*       |
13    /// |***     |
14    /// |*****   |
15    /// |********|
16    /// 
17    A,
18    ///
19    /// ```
20    /// |********|
21    /// |*****   |
22    /// |***     |
23    /// |*       |
24    /// 
25    B,
26    ///
27    /// ```
28    /// |********|
29    /// |  ******|
30    /// |     ***|
31    /// |       *|
32    /// 
33    C,
34    ///
35    /// ```
36    /// |       *|
37    /// |     ***|
38    /// |  ******|
39    /// |********|
40    /// 
41    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}