//! The Gilbert–Johnson–Keerthi distance algorithm. use num::{Bounded, Zero}; use approx::ApproxEq; use alga::general::{Id, Real}; use alga::linear::NormedSpace; use na::{self, Unit}; use shape::{AnnotatedMinkowskiSum, AnnotatedPoint, MinkowskiSum, Reflection, SupportMap}; use query::algorithms::simplex::Simplex; use query::Proximity; use query::{ray_internal, Ray}; use math::{Isometry, Point}; /// Results of the GJK algorithm. #[derive(Clone)] pub enum GJKResult
{ /// Result of the GJK algorithm when the origin is inside of the polytope. Intersection, /// Result of the GJK algorithm when a projection of the origin on the polytope is found. Projection(P), /// Result of the GJK algorithm when the origin is to close to the polytope but not inside of it. Proximity(V), /// Result of the GJK algorithm when the origin is too far away from the polytope. NoIntersection(V), } /// Computes the closest points between two convex shapes unsing the GJK /// algorithm. /// /// # Arguments: /// * `g1` - first shape. /// * `g2` - second shape. /// * `simplex` - the simplex to be used by the GJK algorithm. It must be already initialized /// with at least one point on the shapes CSO. See /// `minkowski_sum::cso_support_point` to compute such point. pub fn closest_points
(
m1: &M,
g1: &G1,
m2: &M,
g2: &G2,
simplex: &mut S,
) -> Option<(P, P)>
where
P: Point,
S: Simplex ,
G2: SupportMap ,
{
let reflect2 = Reflection::new(g2);
let cso = AnnotatedMinkowskiSum::new(m1, g1, m2, &reflect2);
project_origin(&Id::new(), &cso, simplex).map(|p| (*p.orig1(), -*p.orig2()))
}
/// Computes the closest points between two convex shapes unsing the GJK algorithm.
///
/// # Arguments:
/// * `g1` - first shape.
/// * `g2` - second shape.
/// * `simplex` - the simplex to be used by the GJK algorithm. It must be already initialized
/// with at least one point on the shapes CSO. See `minkowski_sum::cso_support_point`
/// to compute such point.
pub fn closest_points_with_max_dist (
m1: &M,
g1: &G1,
m2: &M,
g2: &G2,
max_dist: P::Real,
simplex: &mut S,
) -> GJKResult<(P, P), P::Vector>
where
P: Point,
S: Simplex ,
G2: SupportMap ,
{
let reflect2 = Reflection::new(g2);
let cso = AnnotatedMinkowskiSum::new(m1, g1, m2, &reflect2);
match project_origin_with_max_dist(&Id::new(), &cso, max_dist, true, simplex) {
GJKResult::Projection(p) => GJKResult::Projection((*p.orig1(), -*p.orig2())),
GJKResult::Intersection => GJKResult::Intersection,
GJKResult::NoIntersection(dir) => GJKResult::NoIntersection(dir),
GJKResult::Proximity(_) => unreachable!(),
}
}
/// Computes the exact distance separating two convex shapes unsing the GJK.
/// algorithm.
///
/// # Arguments:
/// * `g1` - first shape.
/// * `g2` - second shape.
/// * `simplex` - the simplex to be used by the GJK algorithm. It must be already initialized
/// with at least one point on the shapes CSO. See `minkowski_sum::cso_support_point`
/// to compute such point.
pub fn distance (
m1: &M,
g1: &G1,
m2: &M,
g2: &G2,
simplex: &mut S,
) -> P::Real
where
P: Point,
S: Simplex ,
G1: SupportMap ,
G2: SupportMap ,
{
let reflect2 = Reflection::new(g2);
let cso = MinkowskiSum::new(m1, g1, m2, &reflect2);
match project_origin(&Id::new(), &cso, simplex) {
Some(c) => na::norm(&c.coordinates()),
None => na::zero(),
}
}
/// Computes the closest points between two convex shapes unsing the GJK algorithm.
///
/// # Arguments:
/// * `g1` - first shape.
/// * `g2` - second shape.
/// * `simplex` - the simplex to be used by the GJK algorithm. It must be already initialized
/// with at least one point on the shapes CSO. See `minkowski_sum::cso_support_point`
/// to compute such point.
pub fn proximity (
m1: &M,
g1: &G1,
m2: &M,
g2: &G2,
max_dist: P::Real,
simplex: &mut S,
) -> (Proximity, P::Vector)
where
P: Point,
S: Simplex ,
G2: SupportMap ,
{
let reflect2 = Reflection::new(g2);
let cso = AnnotatedMinkowskiSum::new(m1, g1, m2, &reflect2);
match project_origin_with_max_dist(&Id::new(), &cso, max_dist, false, simplex) {
GJKResult::NoIntersection(data) => (Proximity::Disjoint, data),
GJKResult::Proximity(data) => (Proximity::WithinMargin, data),
GJKResult::Intersection => (Proximity::Intersecting, na::zero()),
GJKResult::Projection(_) => unreachable!(),
}
}
/*
* Distance GJK
*/
/// Projects the origin on a shape unsing the GJK algorithm.
///
/// # Arguments:
/// * shape - the shape to project the origin on
/// * simplex - the simplex to be used by the GJK algorithm. It must be already initialized
/// with at least one point on the shape boundary.
pub fn project_origin (m: &M, shape: &G, simplex: &mut S) -> Option
where
P: Point,
S: Simplex ,
G: SupportMap ,
{
// FIXME: reset the simplex if it is empty?
let mut proj = simplex.project_origin_and_reduce();
let mut max_bound = na::norm_squared(&proj.coordinates());
let _eps = P::Real::default_epsilon();
let _eps_tol = eps_tol();
let _eps_rel = _eps.sqrt();
let _dimension = na::dimension:: (
m: &M,
shape: &G,
max_dist: P::Real,
exact_dist: bool,
simplex: &mut S,
) -> GJKResult
where
P: Point,
S: Simplex ,
G: SupportMap ,
{
let _eps = P::Real::default_epsilon();
let _eps_tol: P::Real = eps_tol();
let _eps_rel: P::Real = _eps_tol.sqrt();
let _dimension = na::dimension:: (
m: &M,
shape: &G,
simplex: &mut S,
ray: &Ray ,
) -> Option<(P::Real, P::Vector)>
where
P: Point,
M: Isometry ,
S: Simplex ,
G: SupportMap ,
{
let mut ltoi: P::Real = na::zero();
let _eps_tol = eps_tol();
let _dimension = na::dimension::