parry3d/shape/
composite_shape.rs

1use crate::math::{Isometry, Real};
2use crate::partitioning::Bvh;
3use crate::query::details::NormalConstraints;
4use crate::shape::Shape;
5
6/// Trait implemented by shapes composed of multiple simpler shapes.
7///
8/// A composite shape is composed of several shapes. For example, this can
9/// be a convex decomposition of a concave shape; or a triangle-mesh.
10///
11/// This trait is mostly useful for using composite shapes as trait-objects.
12/// For other use-cases, call methods from [`TypedCompositeShape`] to avoid
13/// dynamic dispatches instead.
14#[cfg(feature = "alloc")]
15pub trait CompositeShape {
16    /// Applies a function to one sub-shape of this composite shape.
17    ///
18    /// This method is mostly useful for using composite shapes as trait-objects.
19    /// For other use-cases, call methods from [`TypedCompositeShape`] to avoid
20    /// dynamic dispatches instead.
21    ///
22    /// Note that if your structure also implements `TypedCompositeShape`, this method
23    /// can be implemented simply as:
24    /// ```rust ignore
25    /// self.map_untyped_part_at(shape_id, f);
26    /// ```
27    fn map_part_at(
28        &self,
29        shape_id: u32,
30        f: &mut dyn FnMut(Option<&Isometry<Real>>, &dyn Shape, Option<&dyn NormalConstraints>),
31    );
32
33    /// Gets the acceleration structure of the composite shape.
34    fn bvh(&self) -> &Bvh;
35}
36
37#[cfg(feature = "alloc")]
38pub trait TypedCompositeShape: CompositeShape {
39    type PartShape: ?Sized + Shape;
40    type PartNormalConstraints: ?Sized + NormalConstraints;
41
42    fn map_typed_part_at<T>(
43        &self,
44        shape_id: u32,
45        f: impl FnMut(
46            Option<&Isometry<Real>>,
47            &Self::PartShape,
48            Option<&Self::PartNormalConstraints>,
49        ) -> T,
50    ) -> Option<T>;
51
52    // TODO: we need this method because the compiler won't want
53    // to cast `&Self::PartShape` to `&dyn Shape` because it complains
54    // that `PartShape` is not `Sized`.
55    fn map_untyped_part_at<T>(
56        &self,
57        shape_id: u32,
58        f: impl FnMut(Option<&Isometry<Real>>, &dyn Shape, Option<&dyn NormalConstraints>) -> T,
59    ) -> Option<T>;
60}
61
62#[cfg(feature = "alloc")]
63impl TypedCompositeShape for dyn CompositeShape + '_ {
64    type PartShape = dyn Shape;
65    type PartNormalConstraints = dyn NormalConstraints;
66
67    fn map_typed_part_at<T>(
68        &self,
69        shape_id: u32,
70        mut f: impl FnMut(
71            Option<&Isometry<Real>>,
72            &Self::PartShape,
73            Option<&Self::PartNormalConstraints>,
74        ) -> T,
75    ) -> Option<T> {
76        let mut result = None;
77        self.map_part_at(shape_id, &mut |pose, part, normals| {
78            result = Some(f(pose, part, normals));
79        });
80        result
81    }
82
83    fn map_untyped_part_at<T>(
84        &self,
85        shape_id: u32,
86        mut f: impl FnMut(Option<&Isometry<Real>>, &dyn Shape, Option<&dyn NormalConstraints>) -> T,
87    ) -> Option<T> {
88        let mut result = None;
89        self.map_part_at(shape_id, &mut |pose, part, normals| {
90            result = Some(f(pose, part, normals));
91        });
92        result
93    }
94}
95
96/// A helper struct that implements scene queries on any composite shapes.
97///
98/// For example, the `RayCast` implementation of a composite shape can use this wrapper or
99/// provide its own implementation. This is for working around the lack of specialization in
100/// (stable) rust. If we did have specialization, this would just be a blanket implementation
101/// of all the geometric query traits for all `S: CompositeShape`.
102pub struct CompositeShapeRef<'a, S: ?Sized>(pub &'a S);