parry3d/query/epa/mod.rs
1//! Expanding Polytope Algorithm (EPA) for computing penetration depth and contact information.
2//!
3//! # What is EPA?
4//!
5//! The **Expanding Polytope Algorithm (EPA)** is a computational geometry algorithm used to
6//! determine how deeply two convex shapes are penetrating each other. It works as a follow-up
7//! to the GJK (Gilbert-Johnson-Keerthi) algorithm.
8//!
9//! # How EPA relates to GJK
10//!
11//! **GJK and EPA work together as a two-stage process:**
12//!
13//! 1. **GJK** (Gilbert-Johnson-Keerthi) quickly determines if two shapes are intersecting
14//! - If shapes are **separated**: GJK computes the distance between them
15//! - If shapes are **penetrating**: GJK detects the penetration but cannot compute the depth
16//!
17//! 2. **EPA** takes over when shapes are penetrating
18//! - Uses GJK's final simplex (a set of points surrounding the origin) as a starting point
19//! - Iteratively expands this simplex to find the penetration depth and contact normal
20//!
21//! # When to use EPA
22//!
23//! EPA is used when you need detailed contact information for **penetrating shapes**:
24//!
25//! - **Physics simulation**: Resolving interpenetration between colliding objects
26//! - **Contact manifold generation**: Finding contact points and normals for collision response
27//! - **Penetration depth queries**: Determining how far apart to move objects to resolve overlap
28//!
29//! **Key requirement**: Both shapes must implement the [`SupportMap`](crate::shape::SupportMap)
30//! trait, which provides support points in any direction.
31//!
32//! # How EPA works (simplified)
33//!
34//! 1. **Start with GJK simplex**: Begin with the simplex from GJK that encloses the origin
35//! in the Minkowski difference space (the CSO - Configuration Space Obstacle)
36//!
37//! 2. **Find closest face**: Identify which face of the polytope is closest to the origin
38//!
39//! 3. **Expand polytope**: Add a new support point in the direction of the closest face's normal
40//!
41//! 4. **Update and repeat**: Incorporate the new point and find the new closest face
42//!
43//! 5. **Converge**: Stop when the closest face cannot be expanded further
44//! - The distance to this face is the **penetration depth**
45//! - The face's normal is the **contact normal**
46//! - The closest points on the face map back to **contact points** on the original shapes
47//!
48//! # Example usage
49//!
50//! ```
51//! # #[cfg(all(feature = "dim3", feature = "f32"))] {
52//! use parry3d::query::epa::EPA;
53//! use parry3d::query::gjk::VoronoiSimplex;
54//! use parry3d::shape::Ball;
55//! use parry3d::na::Isometry3;
56//!
57//! let ball1 = Ball::new(1.0);
58//! let ball2 = Ball::new(1.0);
59//! let pos12 = Isometry3::translation(1.5, 0.0, 0.0); // Overlapping balls
60//!
61//! // GJK detects penetration, EPA computes contact details
62//! let simplex = VoronoiSimplex::new(); // Would be filled by GJK
63//! let mut epa = EPA::new();
64//!
65//! // If GJK detected penetration, EPA can compute:
66//! // - Contact points on each shape
67//! // - Penetration depth
68//! // - Contact normal
69//! // if let Some((pt1, pt2, normal)) = epa.closest_points(&pos12, &ball1, &ball2, &simplex) {
70//! // println!("Contact normal: {}", normal);
71//! // }
72//! # }
73//! ```
74//!
75//! # Implementation notes
76//!
77//! - **Dimension-specific**: EPA has separate implementations for 2D (`epa2`) and 3D (`epa3`)
78//! because the polytope expansion differs:
79//! - 2D: Expands polygons (edges)
80//! - 3D: Expands polyhedra (faces)
81//!
82//! - **Convergence**: EPA uses tolerances to determine when to stop expanding. In rare cases
83//! with degenerate geometry or numerical precision issues, it may return `None` if it cannot
84//! converge to a solution.
85//!
86//! - **Performance**: EPA is more expensive than GJK, which is why it's only used when shapes
87//! are actually penetrating. For separated shapes, GJK alone is sufficient.
88//!
89#[cfg(feature = "dim2")]
90pub use self::epa2::EPA;
91#[cfg(feature = "dim3")]
92pub use self::epa3::EPA;
93
94#[cfg(feature = "dim2")]
95pub mod epa2;
96#[cfg(feature = "dim3")]
97pub mod epa3;