//! Bounding sphere. use num::Zero; use alga::linear::NormedSpace; use na; use bounding_volume::{BoundingVolume, HasBoundingVolume}; use math::{Isometry, Point}; // Seems useful to help type inference. See issue #84. /// Computes the bounding sphere of a shape `g` transformed by `m`. /// /// Same as `g.bounding_sphere(m)`. pub fn bounding_sphere
(g: &G, m: &M) -> BoundingSphere
where
P: Point,
G: HasBoundingVolume BoundingSphere
where
P: Point,
{
/// Creates a new bounding sphere.
pub fn new(center: P, radius: P::Real) -> BoundingSphere {
BoundingSphere {
center: center,
radius: radius,
}
}
/// The bounding sphere center.
#[inline]
pub fn center(&self) -> &P {
&self.center
}
/// The bounding sphere radius.
#[inline]
pub fn radius(&self) -> P::Real {
self.radius
}
/// Transforms this bounding sphere by `m`.
#[inline]
pub fn transform_by {
BoundingSphere::new(m.transform_point(&self.center), self.radius)
}
}
impl for BoundingSphere {
#[inline]
fn center(&self) -> P {
*self.center()
}
#[inline]
fn intersects(&self, other: &BoundingSphere ) -> bool {
// FIXME: refactor that with the code from narrow_phase::ball_ball::collide(...) ?
let delta_pos = other.center - self.center;
let distance_squared = na::norm_squared(&delta_pos);
let sum_radius = self.radius + other.radius;
distance_squared <= sum_radius * sum_radius
}
#[inline]
fn contains(&self, other: &BoundingSphere ) -> bool {
let delta_pos = other.center - self.center;
let distance = na::norm(&delta_pos);
distance + other.radius <= self.radius
}
#[inline]
fn merge(&mut self, other: &BoundingSphere ) {
let mut dir = *other.center() - *self.center();
let norm = dir.normalize_mut();
if norm.is_zero() {
if other.radius > self.radius {
self.radius = other.radius
}
} else {
let s_center_dir = na::dot(&self.center.coordinates(), &dir);
let o_center_dir = na::dot(&other.center.coordinates(), &dir);
let right;
let left;
if s_center_dir + self.radius > o_center_dir + other.radius {
right = self.center + dir * self.radius;
} else {
right = other.center + dir * other.radius;
}
if -s_center_dir + self.radius > -o_center_dir + other.radius {
left = self.center.translate_by(&(-dir * self.radius));
} else {
left = other.center.translate_by(&(-dir * other.radius));
}
self.center = na::center(&left, &right);
self.radius = na::distance(&right, &self.center);
}
}
#[inline]
fn merged(&self, other: &BoundingSphere ) -> BoundingSphere {
let mut res = self.clone();
res.merge(other);
res
}
#[inline]
fn loosen(&mut self, amount: P::Real) {
assert!(
amount >= na::zero(),
"The loosening margin must be positive."
);
self.radius = self.radius + amount
}
#[inline]
fn loosened(&self, amount: P::Real) -> BoundingSphere {
assert!(
amount >= na::zero(),
"The loosening margin must be positive."
);
BoundingSphere::new(self.center, self.radius + amount)
}
#[inline]
fn tighten(&mut self, amount: P::Real) {
assert!(
amount >= na::zero(),
"The tightening margin must be positive."
);
assert!(amount <= self.radius, "The tightening margin is to large.");
self.radius = self.radius - amount
}
#[inline]
fn tightened(&self, amount: P::Real) -> BoundingSphere {
assert!(
amount >= na::zero(),
"The tightening margin must be positive."
);
assert!(amount <= self.radius, "The tightening margin is to large.");
BoundingSphere::new(self.center, self.radius - amount)
}
}
// impl Translation
// where P: Point {
// #[inline]
// fn translation(&self) -> P::Vector {
// self.center.coordinates()
// }
//
// #[inline]
// fn inverse_translation(&self) -> P::Vector {
// -self.translation()
// }
//
// #[inline]
// fn append_translation_mut(&mut self, dv: &P::Vector) {
// self.center = self.center + *dv
// }
//
// #[inline]
// fn append_translation(&self, dv: &P::Vector) -> BoundingSphere {
// BoundingSphere::new(self.center + *dv, self.radius)
// }
//
// #[inline]
// fn prepend_translation_mut(&mut self, dv: &P::Vector) {
// self.append_translation_mut(dv)
// }
//
// #[inline]
// fn prepend_translation(&self, dv: &P::Vector) -> BoundingSphere {
// self.append_translation(dv)
// }
//
// #[inline]
// fn set_translation(&mut self, v: P::Vector) {
// self.center = P::origin() + v
// }
// }