Skip to main content

parry2d/shape/
composite_shape.rs

1use crate::math::Pose;
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<&Pose>, &dyn Shape, Option<&dyn NormalConstraints>),
31    );
32
33    /// Gets the acceleration structure of the composite shape.
34    fn bvh(&self) -> &Bvh;
35
36    /// Whether the parts of this shape may change between two queries made at the same pose (a
37    /// deformable mesh whose vertices move).
38    ///
39    /// The contact-manifold queries then never reuse the contact points cached from a previous
40    /// call (see [`ContactManifold::mark_shapes_deformed`]); the caller must still make sure the
41    /// [`Self::bvh`] is up to date. Defaults to `false`.
42    ///
43    /// [`ContactManifold::mark_shapes_deformed`]: crate::query::ContactManifold::mark_shapes_deformed
44    fn is_deformable(&self) -> bool {
45        false
46    }
47}
48
49#[cfg(feature = "alloc")]
50pub trait TypedCompositeShape: CompositeShape {
51    type PartShape: ?Sized + Shape;
52    type PartNormalConstraints: ?Sized + NormalConstraints;
53
54    fn map_typed_part_at<T>(
55        &self,
56        shape_id: u32,
57        f: impl FnMut(Option<&Pose>, &Self::PartShape, Option<&Self::PartNormalConstraints>) -> T,
58    ) -> Option<T>;
59
60    // TODO: we need this method because the compiler won't want
61    // to cast `&Self::PartShape` to `&dyn Shape` because it complains
62    // that `PartShape` is not `Sized`.
63    fn map_untyped_part_at<T>(
64        &self,
65        shape_id: u32,
66        f: impl FnMut(Option<&Pose>, &dyn Shape, Option<&dyn NormalConstraints>) -> T,
67    ) -> Option<T>;
68}
69
70/// The [`TypedCompositeShape`] view of a [`CompositeShape`] trait object (with or without the
71/// `Sync` marker: distinct trait-object types).
72macro_rules! impl_typed_composite_shape_for_dyn {
73    ($($object:tt)+) => {
74        #[cfg(feature = "alloc")]
75        impl TypedCompositeShape for $($object)+ {
76            type PartShape = dyn Shape;
77            type PartNormalConstraints = dyn NormalConstraints;
78
79            fn map_typed_part_at<T>(
80                &self,
81                shape_id: u32,
82                mut f: impl FnMut(
83                    Option<&Pose>,
84                    &Self::PartShape,
85                    Option<&Self::PartNormalConstraints>,
86                ) -> 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            fn map_untyped_part_at<T>(
96                &self,
97                shape_id: u32,
98                mut f: impl FnMut(Option<&Pose>, &dyn Shape, Option<&dyn NormalConstraints>) -> T,
99            ) -> Option<T> {
100                let mut result = None;
101                self.map_part_at(shape_id, &mut |pose, part, normals| {
102                    result = Some(f(pose, part, normals));
103                });
104                result
105            }
106        }
107    };
108}
109
110impl_typed_composite_shape_for_dyn!(dyn CompositeShape + '_);
111impl_typed_composite_shape_for_dyn!(dyn CompositeShape + Sync + '_);
112
113/// A helper struct that implements scene queries on any composite shapes.
114///
115/// For example, the `RayCast` implementation of a composite shape can use this wrapper or
116/// provide its own implementation. This is for working around the lack of specialization in
117/// (stable) rust. If we did have specialization, this would just be a blanket implementation
118/// of all the geometric query traits for all `S: CompositeShape`.
119pub struct CompositeShapeRef<'a, S: ?Sized>(pub &'a S);