parry3d/query/distance/distance.rs
1use crate::math::{Isometry, Real};
2
3use crate::query::{DefaultQueryDispatcher, QueryDispatcher, Unsupported};
4use crate::shape::Shape;
5
6/// Computes the minimum distance separating two shapes.
7///
8/// This is one of the most fundamental geometric queries in collision detection.
9/// It calculates the shortest distance between any two points on the surfaces of
10/// the two shapes.
11///
12/// # Behavior
13///
14/// - Returns the **shortest distance** between the two shape surfaces
15/// - Returns `0.0` if the shapes are **touching** (surfaces just make contact)
16/// - Returns `0.0` if the shapes are **penetrating** (overlapping)
17/// - Always returns a **non-negative** value
18///
19/// # Arguments
20///
21/// * `pos1` - Position and orientation of the first shape in world space
22/// * `g1` - The first shape (can be any shape implementing the `Shape` trait)
23/// * `pos2` - Position and orientation of the second shape in world space
24/// * `g2` - The second shape (can be any shape implementing the `Shape` trait)
25///
26/// # Returns
27///
28/// * `Ok(distance)` - The minimum distance between the shapes
29/// * `Err(Unsupported)` - If this shape pair combination is not supported
30///
31/// # Performance
32///
33/// Performance varies by shape type:
34/// - **Ball-Ball**: Very fast (analytical solution)
35/// - **Cuboid-Cuboid**: Fast (SAT-based)
36/// - **Convex-Convex**: Moderate (GJK algorithm)
37/// - **Concave shapes**: Slower (requires BVH traversal)
38///
39/// # Example
40///
41/// ```rust
42/// # #[cfg(all(feature = "dim3", feature = "f32"))] {
43/// use parry3d::query::distance;
44/// use parry3d::shape::Ball;
45/// use nalgebra::Isometry3;
46///
47/// // Create two balls
48/// let ball1 = Ball::new(1.0);
49/// let ball2 = Ball::new(2.0);
50///
51/// // Position them 10 units apart along the x-axis
52/// let pos1 = Isometry3::translation(0.0, 0.0, 0.0);
53/// let pos2 = Isometry3::translation(10.0, 0.0, 0.0);
54///
55/// // Compute distance
56/// let dist = distance(&pos1, &ball1, &pos2, &ball2).unwrap();
57///
58/// // Distance = 10.0 (separation) - 1.0 (radius1) - 2.0 (radius2) = 7.0
59/// assert_eq!(dist, 7.0);
60/// # }
61/// ```
62///
63/// ```rust
64/// # #[cfg(all(feature = "dim3", feature = "f32"))] {
65/// use parry3d::query::distance;
66/// use parry3d::shape::Cuboid;
67/// use nalgebra::{Isometry3, Vector3};
68///
69/// // Create two boxes
70/// let box1 = Cuboid::new(Vector3::new(1.0, 1.0, 1.0));
71/// let box2 = Cuboid::new(Vector3::new(0.5, 0.5, 0.5));
72///
73/// // Position them so they're touching
74/// let pos1 = Isometry3::translation(0.0, 0.0, 0.0);
75/// let pos2 = Isometry3::translation(1.5, 0.0, 0.0); // Edge to edge
76///
77/// let dist = distance(&pos1, &box1, &pos2, &box2).unwrap();
78///
79/// // They're touching, so distance is 0.0
80/// assert_eq!(dist, 0.0);
81/// # }
82/// ```
83///
84/// # See Also
85///
86/// - [`closest_points`](crate::query::closest_points()) - For finding the actual closest points
87/// - [`contact`](crate::query::contact()) - For penetration depth when overlapping
88/// - [`intersection_test`](crate::query::intersection_test()) - For boolean overlap test
89pub fn distance(
90 pos1: &Isometry<Real>,
91 g1: &dyn Shape,
92 pos2: &Isometry<Real>,
93 g2: &dyn Shape,
94) -> Result<Real, Unsupported> {
95 let pos12 = pos1.inv_mul(pos2);
96 DefaultQueryDispatcher.distance(&pos12, g1, g2)
97}