use super::functions::{
ConvexShape, johnson_segment, johnson_tetrahedron, johnson_triangle, vlen, vlen_sq, vneg, vsub,
};
#[derive(Debug, Clone, Copy)]
pub struct EnhSphere {
pub centre: [f64; 3],
pub radius: f64,
}
impl EnhSphere {
pub fn new(centre: [f64; 3], radius: f64) -> Self {
Self { centre, radius }
}
}
pub(super) struct TranslatedShape<'a> {
pub(super) shape: &'a dyn ConvexShape,
pub(super) offset: [f64; 3],
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct SupportPoint {
pub w: [f64; 3],
pub a: [f64; 3],
pub b: [f64; 3],
}
impl SupportPoint {
pub fn new(w: [f64; 3], a: [f64; 3], b: [f64; 3]) -> Self {
Self { w, a, b }
}
}
#[derive(Debug, Clone, Default)]
pub struct WarmStartCache {
pub points: Vec<SupportPoint>,
pub direction: [f64; 3],
pub valid: bool,
}
impl WarmStartCache {
pub fn new() -> Self {
Self {
points: Vec::with_capacity(4),
direction: [1.0, 0.0, 0.0],
valid: false,
}
}
pub fn invalidate(&mut self) {
self.valid = false;
self.points.clear();
}
pub fn update(&mut self, points: &[SupportPoint], direction: [f64; 3]) {
self.points.clear();
self.points.extend_from_slice(points);
self.direction = direction;
self.valid = true;
}
}
#[derive(Debug, Clone)]
pub struct EpaEnhancedResult {
pub depth: f64,
pub normal: [f64; 3],
pub contact_point: [f64; 3],
pub iterations: u32,
}
#[derive(Debug, Clone)]
pub struct ContactResult {
pub in_contact: bool,
pub signed_distance: f64,
pub point_a: [f64; 3],
pub point_b: [f64; 3],
pub normal: [f64; 3],
pub gjk_metrics: GjkMetrics,
pub epa_iterations: u32,
}
#[derive(Debug, Clone)]
pub struct GjkResult {
pub intersecting: bool,
pub closest_a: [f64; 3],
pub closest_b: [f64; 3],
pub dist_sq: f64,
pub simplex: Vec<SupportPoint>,
pub metrics: GjkMetrics,
}
impl GjkResult {
pub fn distance(&self) -> f64 {
self.dist_sq.sqrt()
}
}
#[derive(Debug, Clone, Copy)]
pub struct TorusApprox {
pub major_r: f64,
pub minor_r: f64,
pub centre: [f64; 3],
}
impl TorusApprox {
pub fn new(centre: [f64; 3], major_r: f64, minor_r: f64) -> Self {
Self {
major_r,
minor_r,
centre,
}
}
}
#[derive(Debug, Clone)]
pub struct SupportCache {
pub last_dir: [f64; 3],
pub support_a: [f64; 3],
pub support_b: [f64; 3],
pub hits: u64,
pub total: u64,
}
impl SupportCache {
pub fn new() -> Self {
Self {
last_dir: [f64::NAN; 3],
support_a: [0.0; 3],
support_b: [0.0; 3],
hits: 0,
total: 0,
}
}
pub fn get(&mut self, dir: [f64; 3], tol: f64) -> Option<([f64; 3], [f64; 3])> {
self.total += 1;
if self.last_dir[0].is_nan() {
return None;
}
let diff = vsub(dir, self.last_dir);
if vlen(diff) < tol {
self.hits += 1;
Some((self.support_a, self.support_b))
} else {
None
}
}
pub fn put(&mut self, dir: [f64; 3], sa: [f64; 3], sb: [f64; 3]) {
self.last_dir = dir;
self.support_a = sa;
self.support_b = sb;
}
pub fn hit_rate(&self) -> f64 {
if self.total == 0 {
return 0.0;
}
self.hits as f64 / self.total as f64
}
}
#[derive(Debug, Clone)]
pub struct ToiResult {
pub hit: bool,
pub toi: f64,
pub normal: [f64; 3],
pub iterations: u32,
}
#[derive(Debug, Clone)]
pub struct EnhSimplex {
pub verts: Vec<SupportPoint>,
}
impl EnhSimplex {
pub fn new() -> Self {
Self {
verts: Vec::with_capacity(4),
}
}
pub fn from_cache(cache: &WarmStartCache) -> Self {
Self {
verts: cache.points.clone(),
}
}
pub fn dim(&self) -> i32 {
self.verts.len() as i32 - 1
}
pub fn add(&mut self, p: SupportPoint) {
self.verts.push(p);
}
pub fn reduce(&mut self) -> ([f64; 3], bool) {
match self.verts.len() {
0 => ([1.0, 0.0, 0.0], false),
1 => {
let w = vneg(self.verts[0].w);
(w, vlen_sq(self.verts[0].w) < 1e-18)
}
2 => self.reduce_line(),
3 => self.reduce_triangle(),
4 => self.reduce_tetrahedron(),
_ => ([1.0, 0.0, 0.0], false),
}
}
fn reduce_line(&mut self) -> ([f64; 3], bool) {
let a = self.verts[1].w;
let b = self.verts[0].w;
let (_, _, pt) = johnson_segment(a, b);
let dist = vlen_sq(pt);
if dist < 1e-18 {
return ([1.0, 0.0, 0.0], true);
}
let (la, lb, _) = johnson_segment(a, b);
if lb < 1e-10 {
self.verts.remove(0);
} else if la < 1e-10 {
self.verts.remove(1);
}
(vneg(pt), false)
}
fn reduce_triangle(&mut self) -> ([f64; 3], bool) {
let a = self.verts[2].w;
let b = self.verts[1].w;
let c = self.verts[0].w;
let (la, lb, lc, pt) = johnson_triangle(a, b, c);
let dist = vlen_sq(pt);
if dist < 1e-18 {
return ([1.0, 0.0, 0.0], true);
}
let mut new_verts = Vec::with_capacity(3);
let weights = [lc, lb, la];
for (i, &w) in weights.iter().enumerate() {
if w > 1e-10 {
new_verts.push(self.verts[i]);
}
}
self.verts = new_verts;
(vneg(pt), false)
}
fn reduce_tetrahedron(&mut self) -> ([f64; 3], bool) {
let a = self.verts[3].w;
let b = self.verts[2].w;
let c = self.verts[1].w;
let d = self.verts[0].w;
let (pt, inside) = johnson_tetrahedron(a, b, c, d);
if inside {
return ([1.0, 0.0, 0.0], true);
}
let faces = [(3usize, 2usize, 1usize), (3, 2, 0), (3, 1, 0), (2, 1, 0)];
let _ = pt;
let mut best_dist = f64::INFINITY;
let mut best_face = (3, 2, 1);
for &(i, j, k) in &faces {
let wi = self.verts[i].w;
let wj = self.verts[j].w;
let wk = self.verts[k].w;
let (_, _, _, fpt) = johnson_triangle(wi, wj, wk);
let d = vlen_sq(fpt);
if d < best_dist {
best_dist = d;
best_face = (i, j, k);
}
}
let (fi, fj, fk) = best_face;
self.verts = vec![self.verts[fk], self.verts[fj], self.verts[fi]];
let (_, _, _, closest) =
johnson_triangle(self.verts[2].w, self.verts[1].w, self.verts[0].w);
(vneg(closest), false)
}
}
#[derive(Debug, Clone, Copy)]
pub struct EnhCapsule {
pub a: [f64; 3],
pub b: [f64; 3],
pub radius: f64,
}
impl EnhCapsule {
pub fn new(a: [f64; 3], b: [f64; 3], radius: f64) -> Self {
Self { a, b, radius }
}
}
pub struct MinkowskiSum<'a> {
pub a: &'a dyn ConvexShape,
pub b: &'a dyn ConvexShape,
}
impl<'a> MinkowskiSum<'a> {
pub fn new(a: &'a dyn ConvexShape, b: &'a dyn ConvexShape) -> Self {
Self { a, b }
}
}
#[derive(Debug, Clone, Copy)]
pub struct EnhBox {
pub centre: [f64; 3],
pub half: [f64; 3],
}
impl EnhBox {
pub fn new(centre: [f64; 3], half: [f64; 3]) -> Self {
Self { centre, half }
}
}
#[derive(Debug, Clone)]
pub struct ConvexHull {
pub vertices: Vec<[f64; 3]>,
}
impl ConvexHull {
pub fn new(vertices: Vec<[f64; 3]>) -> Self {
Self { vertices }
}
}
#[derive(Debug, Clone, Copy)]
pub struct EnhEllipsoid {
pub centre: [f64; 3],
pub semi_axes: [f64; 3],
}
impl EnhEllipsoid {
pub fn new(centre: [f64; 3], semi_axes: [f64; 3]) -> Self {
Self { centre, semi_axes }
}
}
#[derive(Debug, Clone, Default)]
pub struct GjkMetrics {
pub iterations: u32,
pub support_calls: u32,
pub simplex_reductions: u32,
pub warm_started: bool,
pub converged_early: bool,
pub final_dist_sq: f64,
}
impl GjkMetrics {
pub fn new() -> Self {
Self::default()
}
}
#[derive(Debug, Clone, Copy)]
pub(super) struct EpaFaceE {
pub(super) indices: [usize; 3],
pub(super) normal: [f64; 3],
pub(super) dist: f64,
}