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
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(Option<&Pose>, &Self::PartShape, Option<&Self::PartNormalConstraints>) -> T,
46 ) -> Option<T>;
47
48 // TODO: we need this method because the compiler won't want
49 // to cast `&Self::PartShape` to `&dyn Shape` because it complains
50 // that `PartShape` is not `Sized`.
51 fn map_untyped_part_at<T>(
52 &self,
53 shape_id: u32,
54 f: impl FnMut(Option<&Pose>, &dyn Shape, Option<&dyn NormalConstraints>) -> T,
55 ) -> Option<T>;
56}
57
58#[cfg(feature = "alloc")]
59impl TypedCompositeShape for dyn CompositeShape + '_ {
60 type PartShape = dyn Shape;
61 type PartNormalConstraints = dyn NormalConstraints;
62
63 fn map_typed_part_at<T>(
64 &self,
65 shape_id: u32,
66 mut f: impl FnMut(Option<&Pose>, &Self::PartShape, Option<&Self::PartNormalConstraints>) -> T,
67 ) -> Option<T> {
68 let mut result = None;
69 self.map_part_at(shape_id, &mut |pose, part, normals| {
70 result = Some(f(pose, part, normals));
71 });
72 result
73 }
74
75 fn map_untyped_part_at<T>(
76 &self,
77 shape_id: u32,
78 mut f: impl FnMut(Option<&Pose>, &dyn Shape, Option<&dyn NormalConstraints>) -> T,
79 ) -> Option<T> {
80 let mut result = None;
81 self.map_part_at(shape_id, &mut |pose, part, normals| {
82 result = Some(f(pose, part, normals));
83 });
84 result
85 }
86}
87
88/// A helper struct that implements scene queries on any composite shapes.
89///
90/// For example, the `RayCast` implementation of a composite shape can use this wrapper or
91/// provide its own implementation. This is for working around the lack of specialization in
92/// (stable) rust. If we did have specialization, this would just be a blanket implementation
93/// of all the geometric query traits for all `S: CompositeShape`.
94pub struct CompositeShapeRef<'a, S: ?Sized>(pub &'a S);