wreck/convex_polytope/
array.rs1use core::fmt;
2
3use glam::Vec3;
4
5use inherent::inherent;
6
7use super::refer::RefConvexPolytope;
8use crate::ConvexPolytope;
9use crate::cuboid::Cuboid;
10use crate::sphere::Sphere;
11use crate::{Collides, Scalable, Stretchable, Transformable};
12
13#[derive(Debug, Clone, Copy)]
21#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
22pub struct ArrayConvexPolytope<const P: usize, const V: usize> {
23 #[cfg_attr(feature = "serde", serde(with = "crate::serde_arrays::array_as_seq"))]
24 pub planes: [(Vec3, f32); P],
25 #[cfg_attr(feature = "serde", serde(with = "crate::serde_arrays::array_as_seq"))]
26 pub vertices: [Vec3; V],
27 pub obb: Cuboid,
28}
29
30impl<const P: usize, const V: usize> ArrayConvexPolytope<P, V> {
31 pub const fn new(planes: [(Vec3, f32); P], vertices: [Vec3; V], obb: Cuboid) -> Self {
34 let mut i = 0;
35 while i < P {
36 let (n, d) = planes[i];
37 debug_assert!(
38 crate::dot(n, n) >= f32::EPSILON,
39 "Plane normal cannot be zero"
40 );
41 debug_assert!(d >= 0.0, "Plane distance cannot be negative");
42 i += 1;
43 }
44 i = 0;
45 while i < V {
46 let v = vertices[i];
47 debug_assert!(
48 !v.x.is_nan() && !v.y.is_nan() && !v.z.is_nan(),
49 "Vertex cannot contain NaN"
50 );
51 debug_assert!(obb.contains_point(v), "Vertex cannot be outside the OBB");
52 i += 1;
53 }
54 Self {
55 planes,
56 vertices,
57 obb,
58 }
59 }
60
61 #[inline]
62 fn as_ref(&self) -> RefConvexPolytope<'_> {
63 RefConvexPolytope::from_array(self)
64 }
65}
66
67#[inherent]
68impl<const P: usize, const V: usize> Scalable for ArrayConvexPolytope<P, V> {
69 pub fn scale(&mut self, factor: f32) {
70 for (_, d) in &mut self.planes {
71 *d *= factor;
72 }
73 for v in &mut self.vertices {
74 *v *= factor;
75 }
76 self.obb.scale(factor);
77 }
78}
79
80#[inherent]
81impl<const P: usize, const V: usize> Transformable for ArrayConvexPolytope<P, V> {
82 pub fn translate(&mut self, offset: glam::Vec3A) {
83 let off = Vec3::from(offset);
84 for (n, d) in &mut self.planes {
85 *d += n.dot(off);
86 }
87 for v in &mut self.vertices {
88 *v += off;
89 }
90 self.obb.translate(offset);
91 }
92
93 pub fn rotate_mat(&mut self, mat: glam::Mat3A) {
94 for (n, _) in &mut self.planes {
95 *n = Vec3::from(mat * glam::Vec3A::from(*n));
96 }
97 for v in &mut self.vertices {
98 *v = Vec3::from(mat * glam::Vec3A::from(*v));
99 }
100 self.obb.rotate_mat(mat);
101 }
102
103 pub fn rotate_quat(&mut self, quat: glam::Quat) {
104 for (n, _) in &mut self.planes {
105 *n = quat * *n;
106 }
107 for v in &mut self.vertices {
108 *v = quat * *v;
109 }
110 self.obb.rotate_quat(quat);
111 }
112
113 pub fn transform(&mut self, mat: glam::Affine3A) {
114 let rot = mat.matrix3;
115 let trans = Vec3::from(mat.translation);
116 for (n, d) in &mut self.planes {
117 *n = Vec3::from(rot * glam::Vec3A::from(*n));
118 *d += n.dot(trans);
119 }
120 for v in &mut self.vertices {
121 *v = Vec3::from(mat.transform_point3a(glam::Vec3A::from(*v)));
122 }
123 self.obb.transform(mat);
124 }
125}
126
127impl<const P: usize, const V: usize> Collides<ArrayConvexPolytope<P, V>> for Sphere {
128 #[inline]
129 fn test<const BROADPHASE: bool>(&self, other: &ArrayConvexPolytope<P, V>) -> bool {
130 other.as_ref().collides_sphere::<BROADPHASE>(self)
131 }
132}
133
134impl<const P: usize, const V: usize> Collides<Sphere> for ArrayConvexPolytope<P, V> {
135 #[inline]
136 fn test<const BROADPHASE: bool>(&self, other: &Sphere) -> bool {
137 self.as_ref().collides_sphere::<BROADPHASE>(other)
138 }
139}
140
141impl<const P: usize, const V: usize> Collides<ArrayConvexPolytope<P, V>> for Cuboid {
142 #[inline]
143 fn test<const BROADPHASE: bool>(&self, other: &ArrayConvexPolytope<P, V>) -> bool {
144 other.as_ref().collides_cuboid::<BROADPHASE>(self)
145 }
146}
147
148impl<const P: usize, const V: usize> Collides<Cuboid> for ArrayConvexPolytope<P, V> {
149 #[inline]
150 fn test<const BROADPHASE: bool>(&self, other: &Cuboid) -> bool {
151 self.as_ref().collides_cuboid::<BROADPHASE>(other)
152 }
153}
154
155impl<const P: usize, const V: usize> Collides<ArrayConvexPolytope<P, V>>
156 for crate::capsule::Capsule
157{
158 #[inline]
159 fn test<const BROADPHASE: bool>(&self, other: &ArrayConvexPolytope<P, V>) -> bool {
160 other.as_ref().collides_capsule::<BROADPHASE>(self)
161 }
162}
163
164impl<const P: usize, const V: usize> Collides<crate::capsule::Capsule>
165 for ArrayConvexPolytope<P, V>
166{
167 #[inline]
168 fn test<const BROADPHASE: bool>(&self, other: &crate::capsule::Capsule) -> bool {
169 self.as_ref().collides_capsule::<BROADPHASE>(other)
170 }
171}
172
173impl<const P: usize, const V: usize, const P2: usize, const V2: usize>
178 Collides<ArrayConvexPolytope<P2, V2>> for ArrayConvexPolytope<P, V>
179{
180 #[inline]
181 fn test<const BROADPHASE: bool>(&self, other: &ArrayConvexPolytope<P2, V2>) -> bool {
182 self.as_ref()
183 .collides_polytope::<BROADPHASE>(&other.as_ref())
184 }
185}
186
187impl<const P: usize, const V: usize> Stretchable for ArrayConvexPolytope<P, V> {
188 type Output = ConvexPolytope;
189
190 fn stretch(&self, translation: Vec3) -> Self::Output {
191 let heap = ConvexPolytope::with_obb(self.planes.to_vec(), self.vertices.to_vec(), self.obb);
192 heap.stretch(translation)
193 }
194}
195
196impl<const P: usize, const V: usize> fmt::Display for ArrayConvexPolytope<P, V> {
197 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
198 write!(
199 f,
200 "ArrayConvexPolytope(planes: {}, vertices: {})",
201 P, V
202 )
203 }
204}