1use std::f32::consts::PI;
2
3use glam::Vec2;
4
5use crate::{Color, Mesh, Vertex};
6
7#[derive(Clone, Debug, Default, PartialEq)]
8pub struct Curve {
9 pub points: Vec<Vec2>,
10}
11
12impl Curve {
13 pub fn new() -> Self {
14 Self { points: vec![] }
15 }
16
17 pub fn arc(center: Vec2, radius: f32, start_angle: f32, end_angle: f32) -> Self {
18 let mut curve = Curve::new();
19
20 let mut angle = start_angle;
21 let step = (end_angle - start_angle) / 32.0;
22
23 while angle < end_angle {
24 let x = center.x + radius * angle.cos();
25 let y = center.y + radius * angle.sin();
26
27 curve.add_point(Vec2::new(x, y));
28
29 angle += step;
30 }
31
32 curve
33 }
34
35 pub fn len(&self) -> usize {
36 self.points.len()
37 }
38
39 pub fn is_empty(&self) -> bool {
40 self.points.is_empty()
41 }
42
43 pub fn add_point(&mut self, point: Vec2) {
44 self.points.push(point);
45 }
46
47 pub fn remove_point(&mut self, index: usize) {
48 self.points.remove(index);
49 }
50
51 pub fn clear(&mut self) {
52 self.points.clear();
53 }
54
55 pub fn rounded_mesh(self, thickness: f32, color: Color) -> Mesh {
56 if self.is_empty() {
57 return Mesh::new();
58 }
59
60 if self.len() == 1 {
61 return Mesh::circle(self.points[0], thickness, color);
62 }
63
64 let mut mesh = Mesh::new();
65
66 let center = self.points[0];
68 let next = self.points[1];
69 let angle = (center - next).normalize();
70 let angle = angle.y.atan2(angle.x);
71
72 let index = mesh.vertices.len() as u32;
73 mesh.vertices.push(Vertex::new_color(center, color));
74 for i in -10..=10 {
75 let angle = angle + i as f32 * PI / 20.0;
76 let point = center + Vec2::new(angle.cos(), angle.sin()) * thickness;
77 mesh.vertices.push(Vertex::new_color(point, color));
78
79 if i > -10 {
80 let i = mesh.vertices.len() as u32;
81 mesh.indices.push(index);
82 mesh.indices.push(i - 2);
83 mesh.indices.push(i - 1);
84 }
85 }
86
87 for i in 0..self.len() {
89 if i == self.len() - 1 {
90 let prev = self.points[i - 1];
91 let center = self.points[i];
92
93 let prev_center = (center - prev).normalize();
94
95 let hat = Vec2::new(prev_center.y, -prev_center.x);
96
97 let offset = hat * thickness;
98
99 let vertex_a = Vertex::new_color(center + offset, color);
100 let vertex_b = Vertex::new_color(center - offset, color);
101
102 let i = mesh.vertices.len() as u32;
103 mesh.vertices.push(vertex_a);
104 mesh.vertices.push(vertex_b);
105
106 mesh.indices.push(i - 2);
108 mesh.indices.push(i - 1);
109 mesh.indices.push(i + 0);
110 mesh.indices.push(i - 1);
111 mesh.indices.push(i + 1);
112 mesh.indices.push(i + 0);
113 } else if i > 0 {
114 let prev = self.points[i - 1];
115 let center = self.points[i];
116 let next = self.points[i + 1];
117
118 let prev_center = (center - prev).normalize();
119 let center_next = (next - center).normalize();
120
121 let hat_a = Vec2::new(prev_center.y, -prev_center.x);
122 let hat_b = Vec2::new(center_next.y, -center_next.x);
123
124 let offset = (hat_a + hat_b).normalize() * thickness;
125
126 let vertex_a = Vertex::new_color(center + offset, color);
127 let vertex_b = Vertex::new_color(center - offset, color);
128
129 let i = mesh.vertices.len() as u32;
130 mesh.vertices.push(vertex_a);
131 mesh.vertices.push(vertex_b);
132
133 mesh.indices.push(i - 2);
135 mesh.indices.push(i - 1);
136 mesh.indices.push(i + 0);
137 mesh.indices.push(i - 1);
138 mesh.indices.push(i + 1);
139 mesh.indices.push(i + 0);
140 } else {
141 let center = self.points[i];
142 let next = self.points[i + 1];
143
144 let center_next = (next - center).normalize();
145
146 let hat = Vec2::new(center_next.y, -center_next.x);
147
148 let offset = hat * thickness;
149
150 let vertex_a = Vertex::new_color(center + offset, color);
151 let vertex_b = Vertex::new_color(center - offset, color);
152
153 mesh.vertices.push(vertex_a);
154 mesh.vertices.push(vertex_b);
155 }
156 }
157
158 let center = self.points[self.len() - 1];
160 let prev = self.points[self.len() - 2];
161 let angle = (center - prev).normalize();
162 let angle = angle.y.atan2(angle.x);
163
164 let index = mesh.vertices.len() as u32;
165 mesh.vertices.push(Vertex::new_color(center, color));
166 for i in -10..=10 {
167 let angle = angle + i as f32 * PI / 20.0;
168 let point = center + Vec2::new(angle.cos(), angle.sin()) * thickness;
169 mesh.vertices.push(Vertex::new_color(point, color));
170
171 if i > -10 {
172 let i = mesh.vertices.len() as u32;
173 mesh.indices.push(index);
174 mesh.indices.push(i - 2);
175 mesh.indices.push(i - 1);
176 }
177 }
178
179 mesh
180 }
181}
182
183impl IntoIterator for Curve {
184 type Item = Vec2;
185 type IntoIter = std::vec::IntoIter<Vec2>;
186
187 fn into_iter(self) -> Self::IntoIter {
188 self.points.into_iter()
189 }
190}
191
192impl<'a> IntoIterator for &'a Curve {
193 type Item = &'a Vec2;
194 type IntoIter = std::slice::Iter<'a, Vec2>;
195
196 fn into_iter(self) -> Self::IntoIter {
197 self.points.iter()
198 }
199}
200
201impl<'a> IntoIterator for &'a mut Curve {
202 type Item = &'a mut Vec2;
203 type IntoIter = std::slice::IterMut<'a, Vec2>;
204
205 fn into_iter(self) -> Self::IntoIter {
206 self.points.iter_mut()
207 }
208}