1use super::functions::{
6 ConvexShape, johnson_segment, johnson_tetrahedron, johnson_triangle, vlen, vlen_sq, vneg, vsub,
7};
8
9#[derive(Debug, Clone, Copy)]
11pub struct EnhSphere {
12 pub centre: [f64; 3],
14 pub radius: f64,
16}
17impl EnhSphere {
18 pub fn new(centre: [f64; 3], radius: f64) -> Self {
20 Self { centre, radius }
21 }
22}
23pub(super) struct TranslatedShape<'a> {
25 pub(super) shape: &'a dyn ConvexShape,
26 pub(super) offset: [f64; 3],
27}
28#[derive(Debug, Clone, Copy, PartialEq)]
30pub struct SupportPoint {
31 pub w: [f64; 3],
33 pub a: [f64; 3],
35 pub b: [f64; 3],
37}
38impl SupportPoint {
39 pub fn new(w: [f64; 3], a: [f64; 3], b: [f64; 3]) -> Self {
41 Self { w, a, b }
42 }
43}
44#[derive(Debug, Clone, Default)]
48pub struct WarmStartCache {
49 pub points: Vec<SupportPoint>,
51 pub direction: [f64; 3],
53 pub valid: bool,
55}
56impl WarmStartCache {
57 pub fn new() -> Self {
59 Self {
60 points: Vec::with_capacity(4),
61 direction: [1.0, 0.0, 0.0],
62 valid: false,
63 }
64 }
65 pub fn invalidate(&mut self) {
67 self.valid = false;
68 self.points.clear();
69 }
70 pub fn update(&mut self, points: &[SupportPoint], direction: [f64; 3]) {
72 self.points.clear();
73 self.points.extend_from_slice(points);
74 self.direction = direction;
75 self.valid = true;
76 }
77}
78#[derive(Debug, Clone)]
80pub struct EpaEnhancedResult {
81 pub depth: f64,
83 pub normal: [f64; 3],
85 pub contact_point: [f64; 3],
87 pub iterations: u32,
89}
90#[derive(Debug, Clone)]
92pub struct ContactResult {
93 pub in_contact: bool,
95 pub signed_distance: f64,
97 pub point_a: [f64; 3],
99 pub point_b: [f64; 3],
101 pub normal: [f64; 3],
103 pub gjk_metrics: GjkMetrics,
105 pub epa_iterations: u32,
107}
108#[derive(Debug, Clone)]
110pub struct GjkResult {
111 pub intersecting: bool,
113 pub closest_a: [f64; 3],
115 pub closest_b: [f64; 3],
117 pub dist_sq: f64,
119 pub simplex: Vec<SupportPoint>,
121 pub metrics: GjkMetrics,
123}
124impl GjkResult {
125 pub fn distance(&self) -> f64 {
127 self.dist_sq.sqrt()
128 }
129}
130#[derive(Debug, Clone, Copy)]
136pub struct TorusApprox {
137 pub major_r: f64,
139 pub minor_r: f64,
141 pub centre: [f64; 3],
143}
144impl TorusApprox {
145 pub fn new(centre: [f64; 3], major_r: f64, minor_r: f64) -> Self {
147 Self {
148 major_r,
149 minor_r,
150 centre,
151 }
152 }
153}
154#[derive(Debug, Clone)]
156pub struct SupportCache {
157 pub last_dir: [f64; 3],
159 pub support_a: [f64; 3],
161 pub support_b: [f64; 3],
163 pub hits: u64,
165 pub total: u64,
167}
168impl SupportCache {
169 pub fn new() -> Self {
171 Self {
172 last_dir: [f64::NAN; 3],
173 support_a: [0.0; 3],
174 support_b: [0.0; 3],
175 hits: 0,
176 total: 0,
177 }
178 }
179 pub fn get(&mut self, dir: [f64; 3], tol: f64) -> Option<([f64; 3], [f64; 3])> {
183 self.total += 1;
184 if self.last_dir[0].is_nan() {
185 return None;
186 }
187 let diff = vsub(dir, self.last_dir);
188 if vlen(diff) < tol {
189 self.hits += 1;
190 Some((self.support_a, self.support_b))
191 } else {
192 None
193 }
194 }
195 pub fn put(&mut self, dir: [f64; 3], sa: [f64; 3], sb: [f64; 3]) {
197 self.last_dir = dir;
198 self.support_a = sa;
199 self.support_b = sb;
200 }
201 pub fn hit_rate(&self) -> f64 {
203 if self.total == 0 {
204 return 0.0;
205 }
206 self.hits as f64 / self.total as f64
207 }
208}
209#[derive(Debug, Clone)]
211pub struct ToiResult {
212 pub hit: bool,
214 pub toi: f64,
216 pub normal: [f64; 3],
218 pub iterations: u32,
220}
221#[derive(Debug, Clone)]
223pub struct EnhSimplex {
224 pub verts: Vec<SupportPoint>,
226}
227impl EnhSimplex {
228 pub fn new() -> Self {
230 Self {
231 verts: Vec::with_capacity(4),
232 }
233 }
234 pub fn from_cache(cache: &WarmStartCache) -> Self {
236 Self {
237 verts: cache.points.clone(),
238 }
239 }
240 pub fn dim(&self) -> i32 {
242 self.verts.len() as i32 - 1
243 }
244 pub fn add(&mut self, p: SupportPoint) {
246 self.verts.push(p);
247 }
248 pub fn reduce(&mut self) -> ([f64; 3], bool) {
252 match self.verts.len() {
253 0 => ([1.0, 0.0, 0.0], false),
254 1 => {
255 let w = vneg(self.verts[0].w);
256 (w, vlen_sq(self.verts[0].w) < 1e-18)
257 }
258 2 => self.reduce_line(),
259 3 => self.reduce_triangle(),
260 4 => self.reduce_tetrahedron(),
261 _ => ([1.0, 0.0, 0.0], false),
262 }
263 }
264 fn reduce_line(&mut self) -> ([f64; 3], bool) {
265 let a = self.verts[1].w;
266 let b = self.verts[0].w;
267 let (_, _, pt) = johnson_segment(a, b);
268 let dist = vlen_sq(pt);
269 if dist < 1e-18 {
270 return ([1.0, 0.0, 0.0], true);
271 }
272 let (la, lb, _) = johnson_segment(a, b);
273 if lb < 1e-10 {
274 self.verts.remove(0);
275 } else if la < 1e-10 {
276 self.verts.remove(1);
277 }
278 (vneg(pt), false)
279 }
280 fn reduce_triangle(&mut self) -> ([f64; 3], bool) {
281 let a = self.verts[2].w;
282 let b = self.verts[1].w;
283 let c = self.verts[0].w;
284 let (la, lb, lc, pt) = johnson_triangle(a, b, c);
285 let dist = vlen_sq(pt);
286 if dist < 1e-18 {
287 return ([1.0, 0.0, 0.0], true);
288 }
289 let mut new_verts = Vec::with_capacity(3);
290 let weights = [lc, lb, la];
291 for (i, &w) in weights.iter().enumerate() {
292 if w > 1e-10 {
293 new_verts.push(self.verts[i]);
294 }
295 }
296 self.verts = new_verts;
297 (vneg(pt), false)
298 }
299 fn reduce_tetrahedron(&mut self) -> ([f64; 3], bool) {
300 let a = self.verts[3].w;
301 let b = self.verts[2].w;
302 let c = self.verts[1].w;
303 let d = self.verts[0].w;
304 let (pt, inside) = johnson_tetrahedron(a, b, c, d);
305 if inside {
306 return ([1.0, 0.0, 0.0], true);
307 }
308 let faces = [(3usize, 2usize, 1usize), (3, 2, 0), (3, 1, 0), (2, 1, 0)];
309 let _ = pt;
310 let mut best_dist = f64::INFINITY;
311 let mut best_face = (3, 2, 1);
312 for &(i, j, k) in &faces {
313 let wi = self.verts[i].w;
314 let wj = self.verts[j].w;
315 let wk = self.verts[k].w;
316 let (_, _, _, fpt) = johnson_triangle(wi, wj, wk);
317 let d = vlen_sq(fpt);
318 if d < best_dist {
319 best_dist = d;
320 best_face = (i, j, k);
321 }
322 }
323 let (fi, fj, fk) = best_face;
324 self.verts = vec![self.verts[fk], self.verts[fj], self.verts[fi]];
325 let (_, _, _, closest) =
326 johnson_triangle(self.verts[2].w, self.verts[1].w, self.verts[0].w);
327 (vneg(closest), false)
328 }
329}
330#[derive(Debug, Clone, Copy)]
332pub struct EnhCapsule {
333 pub a: [f64; 3],
335 pub b: [f64; 3],
337 pub radius: f64,
339}
340impl EnhCapsule {
341 pub fn new(a: [f64; 3], b: [f64; 3], radius: f64) -> Self {
343 Self { a, b, radius }
344 }
345}
346pub struct MinkowskiSum<'a> {
350 pub a: &'a dyn ConvexShape,
352 pub b: &'a dyn ConvexShape,
354}
355impl<'a> MinkowskiSum<'a> {
356 pub fn new(a: &'a dyn ConvexShape, b: &'a dyn ConvexShape) -> Self {
358 Self { a, b }
359 }
360}
361#[derive(Debug, Clone, Copy)]
363pub struct EnhBox {
364 pub centre: [f64; 3],
366 pub half: [f64; 3],
368}
369impl EnhBox {
370 pub fn new(centre: [f64; 3], half: [f64; 3]) -> Self {
372 Self { centre, half }
373 }
374}
375#[derive(Debug, Clone)]
377pub struct ConvexHull {
378 pub vertices: Vec<[f64; 3]>,
380}
381impl ConvexHull {
382 pub fn new(vertices: Vec<[f64; 3]>) -> Self {
384 Self { vertices }
385 }
386}
387#[derive(Debug, Clone, Copy)]
389pub struct EnhEllipsoid {
390 pub centre: [f64; 3],
392 pub semi_axes: [f64; 3],
394}
395impl EnhEllipsoid {
396 pub fn new(centre: [f64; 3], semi_axes: [f64; 3]) -> Self {
398 Self { centre, semi_axes }
399 }
400}
401#[derive(Debug, Clone, Default)]
403pub struct GjkMetrics {
404 pub iterations: u32,
406 pub support_calls: u32,
408 pub simplex_reductions: u32,
410 pub warm_started: bool,
412 pub converged_early: bool,
414 pub final_dist_sq: f64,
416}
417impl GjkMetrics {
418 pub fn new() -> Self {
420 Self::default()
421 }
422}
423#[derive(Debug, Clone, Copy)]
425pub(super) struct EpaFaceE {
426 pub(super) indices: [usize; 3],
427 pub(super) normal: [f64; 3],
428 pub(super) dist: f64,
429}