use std::marker::PhantomData;
use na::{Identity, Translate, Translation};
use na;
use entities::bounding_volume::{self, HasBoundingVolume, AABB};
use entities::partitioning::BVTCostFn;
use entities::inspection::Repr;
use point::PointQuery;
use entities::shape::CompositeShape;
use geometry::Proximity;
use geometry::proximity_internal;
use math::{Point, Vector, Isometry};
/// Proximity between a composite shape (`Mesh`, `Compound`) and any other shape.
pub fn composite_shape_against_any
(
m1: &M, g1: &G1,
m2: &M, g2: &G2,
margin: ::Scalar)
-> Proximity
where P: Point,
P::Vect: Translate,
M: Isometry
+ Translation,
G1: CompositeShape,
G2: Repr
+ HasBoundingVolume> {
let mut cost_fn = CompositeShapeAgainstAnyInterfCostFn::new(m1, g1, m2, g2, margin);
match g1.bvt().best_first_search(&mut cost_fn).map(|(_, res)| res) {
None => Proximity::Disjoint,
Some(prox) => prox
}
}
/// Proximity between a shape and a composite (`Mesh`, `Compound`) shape.
pub fn any_against_composite_shape(
m1: &M, g1: &G1,
m2: &M, g2: &G2,
margin: ::Scalar)
-> Proximity
where P: Point,
P::Vect: Translate,
M: Isometry
+ Translation,
G1: Repr + HasBoundingVolume>,
G2: CompositeShape {
composite_shape_against_any(m2, g2, m1, g1, margin)
}
struct CompositeShapeAgainstAnyInterfCostFn<'a, P: 'a + Point, M: 'a, G1: ?Sized + 'a, G2: ?Sized + 'a> {
msum_shift: P::Vect,
msum_margin: P::Vect,
m1: &'a M,
g1: &'a G1,
m2: &'a M,
g2: &'a G2,
margin: ::Scalar,
found_intersection: bool,
point_type: PhantomData
}
impl<'a, P, M, G1: ?Sized, G2: ?Sized> CompositeShapeAgainstAnyInterfCostFn<'a, P, M, G1, G2>
where P: Point,
M: Isometry
,
G1: CompositeShape
,
G2: Repr
+ HasBoundingVolume> {
pub fn new(m1: &'a M, g1: &'a G1, m2: &'a M, g2: &'a G2, margin: ::Scalar)
-> CompositeShapeAgainstAnyInterfCostFn<'a, P, M, G1, G2> {
let ls_m2 = na::inverse(m1).expect("The transformation `m1` must be inversible.") * *m2;
let ls_aabb2 = bounding_volume::aabb(g2, &ls_m2);
CompositeShapeAgainstAnyInterfCostFn {
msum_shift: -ls_aabb2.center().to_vector(),
msum_margin: ls_aabb2.half_extents(),
m1: m1,
g1: g1,
m2: m2,
g2: g2,
margin: margin,
found_intersection: false,
point_type: PhantomData
}
}
}
impl<'a, P, M, G1: ?Sized, G2: ?Sized> BVTCostFn<::Scalar, usize, AABB>
for CompositeShapeAgainstAnyInterfCostFn<'a, P, M, G1, G2>
where P: Point,
P::Vect: Translate
,
M: Isometry
+ Translation,
G1: CompositeShape,
G2: Repr
+ HasBoundingVolume> {
type UserData = Proximity;
#[inline]
fn compute_bv_cost(&mut self, bv: &AABB) -> Option<::Scalar> {
// No need to continue if some parts intersect.
if self.found_intersection {
return None;
}
// Compute the minkowski sum of the two AABBs.
let msum = AABB::new(*bv.mins() + self.msum_shift + (-self.msum_margin),
*bv.maxs() + self.msum_shift + self.msum_margin);
// Compute the distance to the origin.
let distance = msum.distance_to_point(&Identity::new(), &na::origin());
if distance <= self.margin {
Some(distance)
}
else {
None
}
}
#[inline]
fn compute_b_cost(&mut self, b: &usize) -> Option<(::Scalar, Proximity)> {
let mut res = None;
self.g1.map_transformed_part_at(*b, self.m1, &mut |m1, g1| {
res = match proximity_internal::proximity_internal(m1, g1, self.m2, self.g2, self.margin) {
Proximity::Disjoint => None,
Proximity::WithinMargin => Some((self.margin, Proximity::WithinMargin)),
Proximity::Intersecting => {
self.found_intersection = true;
Some((na::zero(), Proximity::Intersecting))
}
}
});
res
}
}