1use std::{array, f32::consts::TAU};
2
3use glam::{Mat3, Mat4, Vec2, Vec3Swizzles};
4use smallvec::{smallvec, SmallVec};
5
6use crate::TOLERANCE;
7
8#[derive(Default, Debug, Clone)]
12pub struct Shape {
13 vertices: SmallVec<[Vec2; 8]>,
14}
15
16impl Shape {
17 pub fn new(vertices: &[Vec2]) -> Self {
18 Self {
19 vertices: SmallVec::from_slice(vertices),
20 }
21 }
22
23 pub fn regular_polygon(sides: usize, radius: f32, origin: Vec2) -> Self {
24 let turn = TAU / sides as f32;
25 let vertices = (0..=sides)
26 .map(|val| {
27 let x = (turn * val as f32).cos();
28 let y = (turn * val as f32).sin();
29
30 Vec2::new(x, y) * radius + origin
31 })
32 .collect();
33
34 Self { vertices }
35 }
36
37 pub fn rect(size: Vec2, origin: Vec2) -> Self {
38 let half_size = size / 2.0;
39 let vertices = smallvec![
40 Vec2::new(-half_size.x, -half_size.y) + origin,
41 Vec2::new(half_size.x, -half_size.y) + origin,
42 Vec2::new(half_size.x, half_size.y) + origin,
43 Vec2::new(-half_size.x, half_size.y) + origin,
44 Vec2::new(-half_size.x, -half_size.y) + origin,
45 ];
46
47 Self { vertices }
48 }
49
50 pub fn faces(&self) -> Faces {
51 Faces {
52 vertices: &self.vertices,
53 current: 0,
54 len: self.vertices.len(),
55 }
56 }
57}
58
59#[derive(Default, Debug, Copy, Clone, PartialEq)]
60#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
63pub struct Face {
64 pub(crate) normal: Vec2,
65 pub vertices: [Vec2; 2],
66}
67
68impl Face {
69 pub fn new(vertices: [Vec2; 2]) -> Self {
70 let dir = (vertices[1] - vertices[0]).normalize();
71 let normal = Vec2::new(dir.y, -dir.x);
72 Self { normal, vertices }
73 }
74
75 pub fn length(&self) -> f32 {
77 (self.vertices[0] - self.vertices[1]).length()
78 }
79
80 pub fn length_squared(&self) -> f32 {
81 (self.vertices[0] - self.vertices[1]).length_squared()
82 }
83
84 pub fn vertices(&self) -> [Vec2; 2] {
86 self.vertices
87 }
88
89 pub fn into_tuple(&self) -> (Vec2, Vec2) {
90 (self.vertices[0], self.vertices[1])
91 }
92
93 #[inline]
95 pub fn normal(&self) -> Vec2 {
96 self.normal
97 }
98
99 pub fn transform(&self, transform: Mat3) -> Self {
101 let [a, b] = self.vertices;
102 Face::new([transform.transform_point2(a), transform.transform_point2(b)])
103 }
104
105 pub fn transform_3d(&self, transform: Mat4) -> Self {
107 let a = transform.transform_point3(self.vertices[0].extend(0.0).xzy());
108 let b = transform.transform_point3(self.vertices[1].extend(0.0).xzy());
109
110 Self::new([a.xz(), b.xz()])
111 }
112
113 pub fn side_of(&self, p: Vec2, normal: Vec2) -> Side {
115 let a = (self.vertices[0] - p).dot(normal);
116 let b = (self.vertices[1] - p).dot(normal);
117
118 if a.abs() < TOLERANCE && b.abs() < TOLERANCE {
119 Side::Coplanar
120 } else if a >= -TOLERANCE && b >= -TOLERANCE {
121 Side::Front
122 } else if a <= TOLERANCE && b <= TOLERANCE {
123 Side::Back
124 } else {
125 Side::Intersecting
126 }
127 }
128
129 pub fn split(&self, p: Vec2, normal: Vec2) -> [Self; 2] {
131 let a = (self.vertices[0] - p).dot(normal);
132 if a >= -TOLERANCE {
133 [
134 Face::new([self.vertices[0], p]),
135 Face::new([p, self.vertices[1]]),
136 ]
137 } else {
138 [
139 Face::new([p, self.vertices[1]]),
140 Face::new([self.vertices[0], p]),
141 ]
142 }
143 }
144
145 pub fn adjacent(&self, other: Face) -> bool {
147 let p = other.midpoint();
148 let a = (self.vertices[0] - p).dot(other.normal);
149 let b = (self.vertices[1] - p).dot(other.normal);
150
151 (a < -TOLERANCE && b > TOLERANCE) || (b < -TOLERANCE && a > TOLERANCE)
153 }
154
155 pub fn midpoint(&self) -> Vec2 {
156 (self.vertices[0] + self.vertices[1]) / 2.0
157 }
158
159 pub fn overlaps(&self, other: &Self) -> bool {
161 let dir = self.dir();
162
163 let p = (self.vertices[0]).dot(dir);
164 let q = (self.vertices[1]).dot(dir);
165 let a = (other.vertices[0]).dot(dir);
166 let b = (other.vertices[1]).dot(dir);
167
168 let (a, b) = if dir.dot(other.dir()) > 0.0 {
170 (a, b)
171 } else {
172 (b, a)
173 };
174
175 let la = q - a;
176 let lb = b - p;
177
178 let overlap = la.min(lb);
179
180 overlap > TOLERANCE
181 }
182
183 pub fn contains_point(&self, p: Vec2) -> bool {
184 let dir = self.dir();
185
186 let d = (p - self.vertices[0]).dot(dir);
187
188 d > -TOLERANCE && d < self.length() + TOLERANCE
189 }
190
191 pub fn dir(&self) -> Vec2 {
192 (self.vertices[1] - self.vertices[0]).normalize()
193 }
194}
195
196impl<'a> IntoIterator for &'a Shape {
197 type Item = Face;
198
199 type IntoIter = Faces<'a>;
200
201 fn into_iter(self) -> Self::IntoIter {
202 self.faces()
203 }
204}
205
206impl<'a> IntoIterator for Face {
207 type Item = Vec2;
208
209 type IntoIter = array::IntoIter<Vec2, 2>;
210
211 fn into_iter(self) -> Self::IntoIter {
212 self.vertices.into_iter()
213 }
214}
215
216impl<'a> IntoIterator for &'a Face {
217 type Item = Vec2;
218
219 type IntoIter = array::IntoIter<Vec2, 2>;
220
221 fn into_iter(self) -> Self::IntoIter {
222 self.vertices.into_iter()
223 }
224}
225
226#[doc(hidden)]
227pub struct Faces<'a> {
228 vertices: &'a [Vec2],
229 current: usize,
230 len: usize,
231}
232
233impl<'a> Iterator for Faces<'a> {
234 type Item = Face;
235
236 fn next(&mut self) -> Option<Self::Item> {
238 if self.current + 1 == self.len {
239 return None;
240 }
241
242 let a = self.vertices[self.current];
243 let b = self.vertices[(self.current + 1)];
244
245 self.current += 1;
246 Some(Face::new([a, b]))
247 }
248}
249
250#[cfg(test)]
251mod tests {
252 use glam::Vec2;
253
254 use super::Shape;
255
256 #[test]
257 fn shape_rect() {
258 let rect = Shape::rect(Vec2::new(2.0, 1.0), Vec2::new(1.0, 0.0));
259
260 let faces = rect.faces();
261
262 let normals = [-Vec2::Y, Vec2::X, Vec2::Y, -Vec2::X];
263
264 assert!(faces.map(|val| val.normal).eq(normals));
265 }
266}
267
268#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
269pub enum Side {
270 Front,
271 Back,
272 Coplanar,
273 Intersecting,
274}
275
276impl Side {
277 pub fn min_side(&self, other: Self) -> Self {
278 match (self, other) {
279 (Side::Back, _) | (_, Side::Back) => Side::Back,
280 _ => *self,
281 }
282 }
283}