1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//!
//! Shape composed from the union of primitives.
//!

use crate::bounding_volume::{BoundingVolume, AABB};
use crate::math::{Isometry, Real};
use crate::partitioning::SimdQuadTree;
use crate::shape::{Shape, SharedShape, SimdCompositeShape, TypedSimdCompositeShape};

/// A compound shape with an aabb bounding volume.
///
/// A compound shape is a shape composed of the union of several simpler shape. This is
/// the main way of creating a concave shape from convex parts. Each parts can have its own
/// delta transformation to shift or rotate it with regard to the other shapes.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone)]
pub struct Compound {
    shapes: Vec<(Isometry<Real>, SharedShape)>,
    quadtree: SimdQuadTree<u32>,
    aabbs: Vec<AABB>,
    aabb: AABB,
}

impl Compound {
    /// Builds a new compound shape.
    ///
    /// Panics if the input vector is empty, of if some of the provided shapes
    /// are also composite shapes (nested composite shapes are not allowed).
    pub fn new(shapes: Vec<(Isometry<Real>, SharedShape)>) -> Compound {
        assert!(
            !shapes.is_empty(),
            "A compound shape must contain at least one shape."
        );
        let mut aabbs = Vec::new();
        let mut leaves = Vec::new();
        let mut aabb = AABB::new_invalid();

        for (i, &(ref delta, ref shape)) in shapes.iter().enumerate() {
            let bv = shape.compute_aabb(delta);

            aabb.merge(&bv);
            aabbs.push(bv.clone());
            leaves.push((i as u32, bv));

            if shape.as_composite_shape().is_some() {
                panic!("Nested composite shapes are not allowed.");
            }
        }

        let mut quadtree = SimdQuadTree::new();
        // NOTE: we apply no dilation factor because we won't
        // update this tree dynamically.
        quadtree.clear_and_rebuild(leaves.into_iter(), 0.0);

        Compound {
            shapes,
            quadtree,
            aabbs,
            aabb,
        }
    }
}

impl Compound {
    /// The shapes of this compound shape.
    #[inline]
    pub fn shapes(&self) -> &[(Isometry<Real>, SharedShape)] {
        &self.shapes[..]
    }

    /// The AABB of this compound in its local-space.
    #[inline]
    pub fn local_aabb(&self) -> &AABB {
        &self.aabb
    }

    /// The shapes AABBs.
    #[inline]
    pub fn aabbs(&self) -> &[AABB] {
        &self.aabbs[..]
    }

    /// The acceleration structure used by this compound shape.
    #[inline]
    pub fn quadtree(&self) -> &SimdQuadTree<u32> {
        &self.quadtree
    }
}

impl SimdCompositeShape for Compound {
    #[inline]
    fn map_part_at(&self, shape_id: u32, f: &mut dyn FnMut(Option<&Isometry<Real>>, &dyn Shape)) {
        if let Some(shape) = self.shapes.get(shape_id as usize) {
            f(Some(&shape.0), &*shape.1)
        }
    }

    #[inline]
    fn quadtree(&self) -> &SimdQuadTree<u32> {
        &self.quadtree
    }
}

impl TypedSimdCompositeShape for Compound {
    type PartShape = dyn Shape;
    type PartId = u32;

    #[inline(always)]
    fn map_typed_part_at(
        &self,
        i: u32,
        mut f: impl FnMut(Option<&Isometry<Real>>, &Self::PartShape),
    ) {
        if let Some((part_pos, part)) = self.shapes.get(i as usize) {
            f(Some(part_pos), &**part)
        }
    }

    #[inline(always)]
    fn map_untyped_part_at(
        &self,
        i: u32,
        mut f: impl FnMut(Option<&Isometry<Real>>, &Self::PartShape),
    ) {
        if let Some((part_pos, part)) = self.shapes.get(i as usize) {
            f(Some(part_pos), &**part)
        }
    }

    #[inline]
    fn typed_quadtree(&self) -> &SimdQuadTree<u32> {
        &self.quadtree
    }
}