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);