ncollide3d/shape/
compound.rsuse crate::bounding_volume::{BoundingVolume, AABB};
use crate::math::Isometry;
use crate::partitioning::{BVHImpl, BVT};
use crate::query::{Contact, ContactKinematic, ContactPrediction, ContactPreprocessor};
use crate::shape::{CompositeShape, FeatureId, Shape, ShapeHandle};
use na::{self, RealField};
use std::mem;
#[derive(Clone)]
pub struct Compound<N: RealField + Copy> {
shapes: Vec<(Isometry<N>, ShapeHandle<N>)>,
bvt: BVT<usize, AABB<N>>,
bvs: Vec<AABB<N>>,
nbits: usize,
}
impl<N: RealField + Copy> Compound<N> {
pub fn new(shapes: Vec<(Isometry<N>, ShapeHandle<N>)>) -> Compound<N> {
let mut bvs = Vec::new();
let mut leaves = Vec::new();
for (i, &(ref delta, ref shape)) in shapes.iter().enumerate() {
let bv = shape.as_ref().aabb(delta).loosened(na::convert(0.04f64));
bvs.push(bv.clone());
leaves.push((i, bv));
if let Some(_comp) = shape.as_composite_shape() {
panic!("Nested composite shapes are not allowed.");
}
}
let nbits = mem::size_of::<usize>() * 8 - leaves.len().leading_zeros() as usize;
let bvt = BVT::new_balanced(leaves);
Compound {
shapes: shapes,
bvt: bvt,
bvs: bvs,
nbits,
}
}
}
impl<N: RealField + Copy> Compound<N> {
#[inline]
pub fn shapes(&self) -> &[(Isometry<N>, ShapeHandle<N>)] {
&self.shapes[..]
}
#[inline]
pub fn bvt(&self) -> &BVT<usize, AABB<N>> {
&self.bvt
}
#[inline]
pub fn aabb(&self) -> &AABB<N> {
self.bvt()
.root_bounding_volume()
.expect("An empty Compound has no AABB.")
}
#[inline]
pub fn bounding_volumes(&self) -> &[AABB<N>] {
&self.bvs[..]
}
#[inline]
pub fn aabb_at(&self, i: usize) -> &AABB<N> {
&self.bvs[i]
}
pub fn subshape_feature_id(&self, fid: FeatureId) -> (usize, FeatureId) {
match fid {
FeatureId::Face(i) => (
(i & !(usize::max_value() << self.nbits)),
FeatureId::Face(i >> self.nbits),
),
#[cfg(feature = "dim3")]
FeatureId::Edge(i) => (
(i & !(usize::max_value() << self.nbits)),
FeatureId::Edge(i >> self.nbits),
),
FeatureId::Vertex(i) => (
(i & !(usize::max_value() << self.nbits)),
FeatureId::Vertex(i >> self.nbits),
),
FeatureId::Unknown => (0, FeatureId::Unknown),
}
}
}
impl<N: RealField + Copy> CompositeShape<N> for Compound<N> {
#[inline]
fn nparts(&self) -> usize {
self.shapes.len()
}
#[inline(always)]
fn map_part_at(
&self,
i: usize,
m: &Isometry<N>,
f: &mut dyn FnMut(&Isometry<N>, &dyn Shape<N>),
) {
let elt = &self.shapes()[i];
let pos = m * elt.0;
f(&pos, elt.1.as_ref())
}
fn map_part_and_preprocessor_at(
&self,
i: usize,
m: &Isometry<N>,
_prediction: &ContactPrediction<N>,
f: &mut dyn FnMut(&Isometry<N>, &dyn Shape<N>, &dyn ContactPreprocessor<N>),
) {
let elt = &self.shapes()[i];
let pos = m * elt.0;
let proc = CompoundContactProcessor::new(&elt.0, i, self.nbits);
f(&pos, elt.1.as_ref(), &proc)
}
#[inline]
fn aabb_at(&self, i: usize) -> AABB<N> {
self.bounding_volumes()[i].clone()
}
#[inline]
fn bvh(&self) -> BVHImpl<N, usize, AABB<N>> {
BVHImpl::BVT(&self.bvt)
}
}
struct CompoundContactProcessor<'a, N: RealField + Copy> {
part_pos: &'a Isometry<N>,
part_id: usize,
nbits: usize,
}
impl<'a, N: RealField + Copy> CompoundContactProcessor<'a, N> {
pub fn new(part_pos: &'a Isometry<N>, part_id: usize, nbits: usize) -> Self {
CompoundContactProcessor {
part_pos,
part_id,
nbits,
}
}
}
impl<'a, N: RealField + Copy> ContactPreprocessor<N> for CompoundContactProcessor<'a, N> {
fn process_contact(
&self,
_c: &mut Contact<N>,
kinematic: &mut ContactKinematic<N>,
is_first: bool,
) -> bool {
let feature = if is_first {
kinematic.feature1()
} else {
kinematic.feature2()
};
let actual_feature = match feature {
FeatureId::Vertex(i) => FeatureId::Vertex((i << self.nbits) | self.part_id),
#[cfg(feature = "dim3")]
FeatureId::Edge(i) => FeatureId::Edge((i << self.nbits) | self.part_id),
FeatureId::Face(i) => FeatureId::Face((i << self.nbits) | self.part_id),
FeatureId::Unknown => return false,
};
if is_first {
kinematic.set_feature1(actual_feature);
kinematic.transform1(self.part_pos);
} else {
kinematic.set_feature2(actual_feature);
kinematic.transform2(self.part_pos);
}
true
}
}