1use phyz_math::{Mat3, Vec3};
4
5#[derive(Debug, Clone)]
7pub enum Geometry {
8 Sphere {
10 radius: f64,
12 },
13 Capsule {
15 radius: f64,
17 length: f64,
19 },
20 Box {
22 half_extents: Vec3,
24 },
25 Cylinder {
27 radius: f64,
29 height: f64,
31 },
32 Mesh {
34 vertices: Vec<Vec3>,
36 faces: Vec<[usize; 3]>,
38 },
39 Plane {
41 normal: Vec3,
43 },
44}
45
46#[derive(Debug, Clone, Copy)]
48pub struct AABB {
49 pub min: Vec3,
51 pub max: Vec3,
53}
54
55impl AABB {
56 pub fn new(min: Vec3, max: Vec3) -> Self {
58 Self { min, max }
59 }
60
61 pub fn expanded(&self, pad: f64) -> Self {
70 let p = Vec3::new(pad, pad, pad);
71 Self {
72 min: self.min - p,
73 max: self.max + p,
74 }
75 }
76
77 pub fn from_geometry(geom: &Geometry, pos: &Vec3, rot: &Mat3) -> Self {
79 match geom {
80 Geometry::Sphere { radius } => {
81 let r = Vec3::new(*radius, *radius, *radius);
82 AABB::new(pos - r, pos + r)
83 }
84 Geometry::Capsule { radius, length } => {
85 let half_len = length * 0.5;
86 let r = Vec3::new(*radius, *radius, half_len + *radius);
87 let corners = [
89 *rot * Vec3::new(r.x, r.y, r.z),
90 *rot * Vec3::new(-r.x, r.y, r.z),
91 *rot * Vec3::new(r.x, -r.y, r.z),
92 *rot * Vec3::new(-r.x, -r.y, r.z),
93 *rot * Vec3::new(r.x, r.y, -r.z),
94 *rot * Vec3::new(-r.x, r.y, -r.z),
95 *rot * Vec3::new(r.x, -r.y, -r.z),
96 *rot * Vec3::new(-r.x, -r.y, -r.z),
97 ];
98 let mut min = pos + corners[0];
99 let mut max = min;
100 for corner in &corners[1..] {
101 let c = *pos + *corner;
102 min = min.component_min(c);
103 max = max.component_max(c);
104 }
105 AABB::new(min, max)
106 }
107 Geometry::Box { half_extents } => {
108 let corners = [
109 *rot * Vec3::new(half_extents.x, half_extents.y, half_extents.z),
110 *rot * Vec3::new(-half_extents.x, half_extents.y, half_extents.z),
111 *rot * Vec3::new(half_extents.x, -half_extents.y, half_extents.z),
112 *rot * Vec3::new(-half_extents.x, -half_extents.y, half_extents.z),
113 *rot * Vec3::new(half_extents.x, half_extents.y, -half_extents.z),
114 *rot * Vec3::new(-half_extents.x, half_extents.y, -half_extents.z),
115 *rot * Vec3::new(half_extents.x, -half_extents.y, -half_extents.z),
116 *rot * Vec3::new(-half_extents.x, -half_extents.y, -half_extents.z),
117 ];
118 let mut min = pos + corners[0];
119 let mut max = min;
120 for corner in &corners[1..] {
121 let c = *pos + *corner;
122 min = min.component_min(c);
123 max = max.component_max(c);
124 }
125 AABB::new(min, max)
126 }
127 Geometry::Cylinder { radius, height } => {
128 let half_h = height * 0.5;
129 let r = Vec3::new(*radius, *radius, half_h);
130 let corners = [
131 *rot * Vec3::new(r.x, 0.0, r.z),
132 *rot * Vec3::new(-r.x, 0.0, r.z),
133 *rot * Vec3::new(0.0, r.y, r.z),
134 *rot * Vec3::new(0.0, -r.y, r.z),
135 *rot * Vec3::new(r.x, 0.0, -r.z),
136 *rot * Vec3::new(-r.x, 0.0, -r.z),
137 *rot * Vec3::new(0.0, r.y, -r.z),
138 *rot * Vec3::new(0.0, -r.y, -r.z),
139 ];
140 let mut min = pos + corners[0];
141 let mut max = min;
142 for corner in &corners[1..] {
143 let c = *pos + *corner;
144 min = min.component_min(c);
145 max = max.component_max(c);
146 }
147 AABB::new(min, max)
148 }
149 Geometry::Mesh { vertices, .. } => {
150 if vertices.is_empty() {
151 return AABB::new(*pos, *pos);
152 }
153 let v0 = *pos + *rot * vertices[0];
154 let mut min = v0;
155 let mut max = v0;
156 for v in vertices.iter().skip(1) {
157 let vt = *pos + *rot * v;
158 min = min.component_min(vt);
159 max = max.component_max(vt);
160 }
161 AABB::new(min, max)
162 }
163 Geometry::Plane { .. } => {
164 let large = 1e6;
166 AABB::new(
167 Vec3::new(-large, -large, -large),
168 Vec3::new(large, large, large),
169 )
170 }
171 }
172 }
173
174 pub fn overlaps(&self, other: &AABB) -> bool {
176 self.min.x <= other.max.x
177 && self.max.x >= other.min.x
178 && self.min.y <= other.max.y
179 && self.max.y >= other.min.y
180 && self.min.z <= other.max.z
181 && self.max.z >= other.min.z
182 }
183}
184
185impl Geometry {
186 pub fn support(&self, dir: &Vec3, pos: &Vec3, rot: &Mat3) -> Vec3 {
188 match self {
189 Geometry::Sphere { radius } => {
190 let d = dir.normalize();
191 pos + d * *radius
192 }
193 Geometry::Capsule { radius, length } => {
194 let half_len = length * 0.5;
195 let axis = *rot * Vec3::z();
196 let p1 = pos + axis * half_len;
197 let p2 = pos - axis * half_len;
198 let d = dir.normalize();
199 if dir.dot(axis) > 0.0 {
200 p1 + d * *radius
201 } else {
202 p2 + d * *radius
203 }
204 }
205 Geometry::Box { half_extents } => {
206 let local_dir = rot.transpose() * dir;
207 let sx = if local_dir.x >= 0.0 {
208 half_extents.x
209 } else {
210 -half_extents.x
211 };
212 let sy = if local_dir.y >= 0.0 {
213 half_extents.y
214 } else {
215 -half_extents.y
216 };
217 let sz = if local_dir.z >= 0.0 {
218 half_extents.z
219 } else {
220 -half_extents.z
221 };
222 pos + *rot * Vec3::new(sx, sy, sz)
223 }
224 Geometry::Cylinder { radius, height } => {
225 let half_h = height * 0.5;
226 let axis = *rot * Vec3::z();
227 let local_dir = rot.transpose() * dir;
228 let radial = Vec3::new(local_dir.x, local_dir.y, 0.0);
229 let radial_norm = radial.norm();
230 let radial_dir = if radial_norm > 1e-10 {
231 radial / radial_norm
232 } else {
233 Vec3::x()
234 };
235 let sz = if local_dir.z >= 0.0 { half_h } else { -half_h };
236 pos + *rot * (radial_dir * *radius) + axis * sz
237 }
238 Geometry::Mesh { vertices, .. } => {
239 let mut best = pos + *rot * vertices[0];
240 let mut best_dot = dir.dot(best);
241 for v in vertices.iter().skip(1) {
242 let vt = pos + *rot * v;
243 let d = dir.dot(vt);
244 if d > best_dot {
245 best = vt;
246 best_dot = d;
247 }
248 }
249 best
250 }
251 Geometry::Plane { normal } => {
252 const PLANE_EXTENT: f64 = 1e3;
269 let n = *rot * *normal;
270 let n_norm = n.norm();
271 let n = if n_norm > 1e-12 {
272 n / n_norm
273 } else {
274 Vec3::z()
275 };
276
277 let d_n = dir.dot(n);
278 let tangent = *dir - n * d_n;
279 let t_norm = tangent.norm();
280 let lateral = if t_norm > 1e-12 {
281 tangent * (PLANE_EXTENT / t_norm)
282 } else {
283 Vec3::zeros()
284 };
285 let along = if d_n > 0.0 { 0.0 } else { -PLANE_EXTENT };
286 pos + lateral + n * along
287 }
288 }
289 }
290}