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#[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}