Function closest_points

Source
pub fn closest_points<G1, G2>(
    pos12: &Isometry<f32>,
    g1: &G1,
    g2: &G2,
    max_dist: f32,
    exact_dist: bool,
    simplex: &mut VoronoiSimplex,
) -> GJKResult
where G1: ?Sized + SupportMap, G2: ?Sized + SupportMap,
Expand description

Computes the closest points between two shapes using the GJK algorithm.

This is the core function of the GJK implementation in Parry. It can compute:

  • Whether two shapes are intersecting
  • The distance between two separated shapes
  • The closest points on both shapes
  • An approximate separation axis when exact distance isn’t needed

§How It Works

The algorithm operates on the Minkowski difference (CSO) of the two shapes and iteratively builds a simplex that approximates the point closest to the origin. The algorithm terminates when:

  • The shapes are proven to intersect (origin is inside the CSO)
  • The minimum distance is found within the tolerance
  • The shapes are proven to be farther than max_dist apart

§Parameters

  • pos12: The relative position of shape 2 with respect to shape 1. This is the isometry that transforms from shape 1’s space to shape 2’s space.
  • g1: The first shape (must implement SupportMap)
  • g2: The second shape (must implement SupportMap)
  • max_dist: Maximum distance to check. If shapes are farther than this, the algorithm returns GJKResult::NoIntersection early. Use Real::max_value() to disable this check.
  • exact_dist: Whether to compute exact closest points:
    • true: Computes exact distance and returns GJKResult::ClosestPoints
    • false: May return GJKResult::Proximity with only an approximate separation axis, which is faster when you only need to know if shapes are nearby
  • simplex: A reusable simplex structure. Initialize with VoronoiSimplex::new() before first use. Can be reused across calls for better performance.

§Returns

Returns a GJKResult which can be:

  • Intersection: The shapes are overlapping
  • ClosestPoints(p1, p2, normal): The closest points on each shape (when exact_dist is true)
  • Proximity(axis): An approximate separation axis (when exact_dist is false)
  • NoIntersection(axis): The shapes are farther than max_dist apart

§Example: Basic Distance Query

use parry3d::shape::{Ball, Cuboid};
use parry3d::query::gjk::{closest_points, VoronoiSimplex};
use parry3d::math::{Isometry, Vector};

// Create two shapes
let ball = Ball::new(1.0);
let cuboid = Cuboid::new(Vector::new(1.0, 1.0, 1.0));

// Position them in space
let pos1 = Isometry::translation(0.0, 0.0, 0.0);
let pos2 = Isometry::translation(5.0, 0.0, 0.0);

// Compute relative position
let pos12 = pos1.inv_mul(&pos2);

// Run GJK
let mut simplex = VoronoiSimplex::new();
let result = closest_points(
    &pos12,
    &ball,
    &cuboid,
    f32::MAX,  // No distance limit
    true,      // Compute exact distance
    &mut simplex,
);

match result {
    parry3d::query::gjk::GJKResult::ClosestPoints(p1, p2, normal) => {
        println!("Closest point on ball: {:?}", p1);
        println!("Closest point on cuboid: {:?}", p2);
        println!("Separation direction: {:?}", normal);
        let distance = (p2 - p1).norm();
        println!("Distance: {}", distance);
    }
    parry3d::query::gjk::GJKResult::Intersection => {
        println!("Shapes are intersecting!");
    }
    _ => {}
}

§Example: Fast Proximity Check

use parry3d::shape::Ball;
use parry3d::query::gjk::{closest_points, VoronoiSimplex};
use parry3d::math::Isometry;

let ball1 = Ball::new(1.0);
let ball2 = Ball::new(1.0);
let pos12 = Isometry::translation(3.0, 0.0, 0.0);

let mut simplex = VoronoiSimplex::new();
let result = closest_points(
    &pos12,
    &ball1,
    &ball2,
    5.0,       // Only check up to distance 5.0
    false,     // Don't compute exact distance
    &mut simplex,
);

match result {
    parry3d::query::gjk::GJKResult::Proximity(_axis) => {
        println!("Shapes are close but not intersecting");
    }
    parry3d::query::gjk::GJKResult::Intersection => {
        println!("Shapes are intersecting");
    }
    parry3d::query::gjk::GJKResult::NoIntersection(_) => {
        println!("Shapes are too far apart (> 5.0 units)");
    }
    _ => {}
}

§Performance Tips

  1. Reuse the simplex across multiple queries to avoid allocations
  2. Set exact_dist to false when you only need proximity information
  3. Use a reasonable max_dist to allow early termination
  4. GJK converges fastest when shapes are well-separated

§Notes

  • All returned points and vectors are in the local-space of shape 1
  • The algorithm typically converges in 5-10 iterations for well-separated shapes
  • Maximum iteration count is 100 to prevent infinite loops