Skip to main content

traaains/shape/
shapes.rs

1use bevy::{math::Vec2, mesh::Mesh};
2use bezier::{Bezier, Constant, Cubic, Linear, Quadratic};
3use shapes::{
4    Circle, Derivable, Intersect,
5    lerp::{Lerp, LerpIterator},
6};
7
8use crate::{shape::meshes::BezierMeshProps, utils::Meshable};
9
10/// An enum grouping all of the different shapes (beziers) available.
11/// Constant can never be built, but needs to be defined because the other types use it.
12#[derive(Clone, Debug)]
13pub enum Shapes {
14    Constant(Constant),
15    Linear(Linear),
16    Quadratic(Quadratic),
17    Cubic(Cubic),
18}
19
20impl Shapes {
21    pub fn coeffs(&self) -> &[Vec2] {
22        match self {
23            Shapes::Constant(_) => todo!(),
24            Shapes::Linear(l) => &l.coeffs,
25            Shapes::Quadratic(q) => &q.coeffs,
26            Shapes::Cubic(c) => &c.coeffs,
27        }
28    }
29
30    pub fn coeffs_mut(&mut self) -> &mut [Vec2] {
31        match self {
32            Shapes::Constant(_) => todo!(),
33            Shapes::Linear(l) => &mut l.coeffs,
34            Shapes::Quadratic(q) => &mut q.coeffs,
35            Shapes::Cubic(c) => &mut c.coeffs,
36        }
37    }
38
39    pub fn set_last_point(&mut self, n: Vec2) {
40        match self {
41            Shapes::Constant(c) => c.0 = n,
42            Shapes::Linear(l) => l.coeffs[1] = n,
43            Shapes::Quadratic(q) => q.coeffs[2] = n,
44            Shapes::Cubic(c) => c.coeffs[3] = n,
45        }
46    }
47
48    pub fn translate_by(&mut self, dir: Vec2) {
49        for c in self.coeffs_mut() {
50            *c += dir;
51        }
52    }
53}
54
55impl Derivable for Shapes {
56    type Derivative = Shapes;
57
58    fn derivative(&self) -> Self::Derivative {
59        match self {
60            Shapes::Constant(c) => Shapes::Constant(c.derivative()),
61            Shapes::Linear(l) => Shapes::Constant(l.derivative()),
62            Shapes::Quadratic(q) => Shapes::Linear(q.derivative()),
63            Shapes::Cubic(c) => Shapes::Quadratic(c.derivative()),
64        }
65    }
66}
67
68impl Lerp for Shapes {
69    fn lerp(&self, idx: f32) -> Vec2 {
70        match self {
71            Shapes::Constant(c) => c.lerp(idx),
72            Shapes::Linear(l) => l.lerp(idx),
73            Shapes::Quadratic(q) => q.lerp(idx),
74            Shapes::Cubic(c) => c.lerp(idx),
75        }
76    }
77
78    fn lerp_iter<'a>(&'a self, lerps: usize) -> LerpIterator<'a, Self> {
79        LerpIterator::new(self, lerps)
80    }
81}
82
83impl Bezier for Shapes {
84    fn project(&self, p: Vec2) -> f32 {
85        match self {
86            Shapes::Constant(c) => c.project(p),
87            Shapes::Linear(l) => l.project(p),
88            Shapes::Quadratic(q) => q.project(p),
89            Shapes::Cubic(c) => c.project(p),
90        }
91    }
92
93    fn displace_by(&self, index: f32, distance: f32) -> f32 {
94        match self {
95            Shapes::Constant(c) => c.displace_by(index, distance),
96            Shapes::Linear(l) => l.displace_by(index, distance),
97            Shapes::Quadratic(q) => q.displace_by(index, distance),
98            Shapes::Cubic(c) => c.displace_by(index, distance),
99        }
100    }
101
102    fn len(&self) -> f32 {
103        match self {
104            Shapes::Constant(c) => c.len(),
105            Shapes::Linear(l) => l.len(),
106            Shapes::Quadratic(q) => q.len(),
107            Shapes::Cubic(c) => c.len(),
108        }
109    }
110
111    fn split(self, idx: f32) -> (Self, Self) {
112        match self {
113            Shapes::Constant(c) => {
114                let (c0, c1) = c.split(idx);
115                (Shapes::Constant(c0), Shapes::Constant(c1))
116            }
117            Shapes::Linear(l) => {
118                let (l0, l1) = l.split(idx);
119                (Shapes::Linear(l0), Shapes::Linear(l1))
120            }
121            Shapes::Quadratic(q) => {
122                let (q0, q1) = q.split(idx);
123                (Shapes::Quadratic(q0), Shapes::Quadratic(q1))
124            }
125            Shapes::Cubic(c) => {
126                let (c0, c1) = c.split(idx);
127                (Shapes::Cubic(c0), Shapes::Cubic(c1))
128            }
129        }
130    }
131}
132
133impl Meshable for Shapes {
134    type Props = BezierMeshProps;
135
136    fn mesh(&self, props: Self::Props) -> Mesh {
137        match self {
138            Shapes::Constant(_) => unimplemented!(),
139            Shapes::Linear(l) => l.mesh(props),
140            Shapes::Quadratic(q) => q.mesh(props),
141            Shapes::Cubic(c) => c.mesh(props),
142        }
143    }
144}
145
146impl Intersect<Circle> for Shapes {
147    fn intersections(&self, rhs: &Circle) -> Option<Vec<(f32, Vec2)>> {
148        match self {
149            Shapes::Constant(constant) => constant.intersections(rhs),
150            Shapes::Linear(linear) => linear.intersections(rhs),
151            Shapes::Quadratic(quadratic) => quadratic.intersections(rhs),
152            Shapes::Cubic(cubic) => cubic.intersections(rhs),
153        }
154    }
155}