parry3d/shape/
shape.rs

1#[cfg(feature = "alloc")]
2use alloc::{boxed::Box, vec::Vec};
3use core::fmt::Debug;
4
5use crate::bounding_volume::{Aabb, BoundingSphere, BoundingVolume};
6use crate::mass_properties::MassProperties;
7use crate::math::{Pose, Real, RealField, Vector};
8use crate::query::{PointQuery, RayCast};
9#[cfg(feature = "serde-serialize")]
10use crate::shape::SharedShape;
11#[cfg(feature = "alloc")]
12use crate::shape::{composite_shape::CompositeShape, Compound, HeightField, Polyline, TriMesh};
13use crate::shape::{
14    Ball, Capsule, Cuboid, FeatureId, HalfSpace, PolygonalFeatureMap, RoundCuboid, RoundShape,
15    RoundTriangle, Segment, SupportMap, Triangle,
16};
17#[cfg(feature = "dim3")]
18use crate::shape::{Cone, Cylinder, RoundCone, RoundCylinder};
19
20#[cfg(feature = "dim3")]
21#[cfg(feature = "alloc")]
22use crate::shape::{ConvexPolyhedron, RoundConvexPolyhedron, Voxels};
23
24#[cfg(feature = "dim2")]
25#[cfg(feature = "alloc")]
26use crate::shape::{ConvexPolygon, RoundConvexPolygon, Voxels};
27use downcast_rs::{impl_downcast, DowncastSync};
28use num::Zero;
29use num_derive::FromPrimitive;
30
31#[derive(Copy, Clone, Debug, FromPrimitive, PartialEq, Eq, Hash)]
32/// Enum representing the type of a shape.
33pub enum ShapeType {
34    /// A ball shape.
35    Ball = 0,
36    /// A cuboid shape.
37    Cuboid,
38    /// A capsule shape.
39    Capsule,
40    /// A segment shape.
41    Segment,
42    /// A triangle shape.
43    Triangle,
44    /// A shape defined as a voxel grid.
45    Voxels,
46    /// A triangle mesh shape.
47    TriMesh,
48    /// A set of segments.
49    Polyline,
50    /// A shape representing a full half-space.
51    HalfSpace,
52    /// A heightfield shape.
53    HeightField,
54    /// A Compound shape.
55    Compound,
56    #[cfg(feature = "dim2")]
57    ConvexPolygon,
58    #[cfg(feature = "dim3")]
59    /// A convex polyhedron.
60    ConvexPolyhedron,
61    #[cfg(feature = "dim3")]
62    /// A cylindrical shape.
63    Cylinder,
64    #[cfg(feature = "dim3")]
65    /// A cone shape.
66    Cone,
67    // /// A custom shape type.
68    // Custom(u8),
69    /// A cuboid with rounded corners.
70    RoundCuboid,
71    /// A triangle with rounded corners.
72    RoundTriangle,
73    // /// A triangle-mesh with rounded corners.
74    // RoundedTriMesh,
75    // /// An heightfield with rounded corners.
76    // RoundedHeightField,
77    /// A cylinder with rounded corners.
78    #[cfg(feature = "dim3")]
79    RoundCylinder,
80    /// A cone with rounded corners.
81    #[cfg(feature = "dim3")]
82    RoundCone,
83    /// A convex polyhedron with rounded corners.
84    #[cfg(feature = "dim3")]
85    RoundConvexPolyhedron,
86    /// A convex polygon with rounded corners.
87    #[cfg(feature = "dim2")]
88    RoundConvexPolygon,
89    /// A custom user-defined shape.
90    Custom,
91}
92
93#[derive(Copy, Clone)]
94#[cfg_attr(feature = "serde-serialize", derive(Serialize))]
95/// Enum representing the shape with its actual type
96pub enum TypedShape<'a> {
97    /// A ball shape.
98    Ball(&'a Ball),
99    /// A cuboid shape.
100    Cuboid(&'a Cuboid),
101    /// A capsule shape.
102    Capsule(&'a Capsule),
103    /// A segment shape.
104    Segment(&'a Segment),
105    /// A triangle shape.
106    Triangle(&'a Triangle),
107    #[cfg(feature = "alloc")]
108    /// A shape defined as a voxel grid.
109    Voxels(&'a Voxels),
110    /// A triangle mesh shape.
111    #[cfg(feature = "alloc")]
112    TriMesh(&'a TriMesh),
113    /// A set of segments.
114    #[cfg(feature = "alloc")]
115    Polyline(&'a Polyline),
116    /// A shape representing a full half-space.
117    HalfSpace(&'a HalfSpace),
118    /// A heightfield shape.
119    #[cfg(feature = "alloc")]
120    HeightField(&'a HeightField),
121    /// A Compound shape.
122    #[cfg(feature = "alloc")]
123    Compound(&'a Compound),
124    #[cfg(feature = "dim2")]
125    #[cfg(feature = "alloc")]
126    ConvexPolygon(&'a ConvexPolygon),
127    #[cfg(feature = "dim3")]
128    #[cfg(feature = "alloc")]
129    /// A convex polyhedron.
130    ConvexPolyhedron(&'a ConvexPolyhedron),
131    #[cfg(feature = "dim3")]
132    /// A cylindrical shape.
133    Cylinder(&'a Cylinder),
134    #[cfg(feature = "dim3")]
135    /// A cone shape.
136    Cone(&'a Cone),
137    /// A cuboid with rounded corners.
138    RoundCuboid(&'a RoundCuboid),
139    /// A triangle with rounded corners.
140    RoundTriangle(&'a RoundTriangle),
141    // /// A triangle-mesh with rounded corners.
142    // RoundedTriMesh,
143    // /// An heightfield with rounded corners.
144    // RoundedHeightField,
145    /// A cylinder with rounded corners.
146    #[cfg(feature = "dim3")]
147    RoundCylinder(&'a RoundCylinder),
148    /// A cone with rounded corners.
149    #[cfg(feature = "dim3")]
150    RoundCone(&'a RoundCone),
151    /// A convex polyhedron with rounded corners.
152    #[cfg(feature = "dim3")]
153    #[cfg(feature = "alloc")]
154    RoundConvexPolyhedron(&'a RoundConvexPolyhedron),
155    /// A convex polygon with rounded corners.
156    #[cfg(feature = "dim2")]
157    #[cfg(feature = "alloc")]
158    RoundConvexPolygon(&'a RoundConvexPolygon),
159    /// A custom user-defined shape.
160    #[cfg_attr(feature = "serde-serialize", serde(skip))]
161    Custom(&'a dyn Shape),
162}
163impl Debug for TypedShape<'_> {
164    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
165        match self {
166            Self::Ball(arg0) => f.debug_tuple("Ball").field(arg0).finish(),
167            Self::Cuboid(arg0) => f.debug_tuple("Cuboid").field(arg0).finish(),
168            Self::Capsule(arg0) => f.debug_tuple("Capsule").field(arg0).finish(),
169            Self::Segment(arg0) => f.debug_tuple("Segment").field(arg0).finish(),
170            Self::Triangle(arg0) => f.debug_tuple("Triangle").field(arg0).finish(),
171            #[cfg(feature = "alloc")]
172            Self::Voxels(arg0) => f.debug_tuple("Voxels").field(arg0).finish(),
173            #[cfg(feature = "alloc")]
174            Self::TriMesh(arg0) => f.debug_tuple("TriMesh").field(arg0).finish(),
175            #[cfg(feature = "alloc")]
176            Self::Polyline(arg0) => f.debug_tuple("Polyline").field(arg0).finish(),
177            Self::HalfSpace(arg0) => f.debug_tuple("HalfSpace").field(arg0).finish(),
178            #[cfg(feature = "alloc")]
179            Self::HeightField(arg0) => f.debug_tuple("HeightField").field(arg0).finish(),
180            #[cfg(feature = "alloc")]
181            Self::Compound(arg0) => f.debug_tuple("Compound").field(arg0).finish(),
182            #[cfg(feature = "dim2")]
183            #[cfg(feature = "alloc")]
184            Self::ConvexPolygon(arg0) => f.debug_tuple("ConvexPolygon").field(arg0).finish(),
185            #[cfg(feature = "dim3")]
186            #[cfg(feature = "alloc")]
187            Self::ConvexPolyhedron(arg0) => f.debug_tuple("ConvexPolyhedron").field(arg0).finish(),
188            #[cfg(feature = "dim3")]
189            Self::Cylinder(arg0) => f.debug_tuple("Cylinder").field(arg0).finish(),
190            #[cfg(feature = "dim3")]
191            Self::Cone(arg0) => f.debug_tuple("Cone").field(arg0).finish(),
192            Self::RoundCuboid(arg0) => f.debug_tuple("RoundCuboid").field(arg0).finish(),
193            Self::RoundTriangle(arg0) => f.debug_tuple("RoundTriangle").field(arg0).finish(),
194            #[cfg(feature = "dim3")]
195            Self::RoundCylinder(arg0) => f.debug_tuple("RoundCylinder").field(arg0).finish(),
196            #[cfg(feature = "dim3")]
197            Self::RoundCone(arg0) => f.debug_tuple("RoundCone").field(arg0).finish(),
198            #[cfg(feature = "dim3")]
199            #[cfg(feature = "alloc")]
200            Self::RoundConvexPolyhedron(arg0) => {
201                f.debug_tuple("RoundConvexPolyhedron").field(arg0).finish()
202            }
203            #[cfg(feature = "dim2")]
204            #[cfg(feature = "alloc")]
205            Self::RoundConvexPolygon(arg0) => {
206                f.debug_tuple("RoundConvexPolygon").field(arg0).finish()
207            }
208            Self::Custom(_) => f.debug_tuple("Custom").finish(),
209        }
210    }
211}
212
213#[cfg(feature = "serde-serialize")]
214#[derive(Deserialize)]
215// NOTE: This enum MUST match the `TypedShape` enum.
216/// Enum representing the shape with its actual type
217pub(crate) enum DeserializableTypedShape {
218    /// A ball shape.
219    Ball(Ball),
220    /// A cuboid shape.
221    Cuboid(Cuboid),
222    /// A capsule shape.
223    Capsule(Capsule),
224    /// A segment shape.
225    Segment(Segment),
226    /// A triangle shape.
227    Triangle(Triangle),
228    /// A shape defined as a voxel grid.
229    #[cfg(feature = "alloc")]
230    Voxels(Voxels),
231    /// A triangle mesh shape.
232    #[cfg(feature = "alloc")]
233    TriMesh(TriMesh),
234    /// A set of segments.
235    #[cfg(feature = "alloc")]
236    Polyline(Polyline),
237    /// A shape representing a full half-space.
238    HalfSpace(HalfSpace),
239    /// A heightfield shape.
240    #[cfg(feature = "alloc")]
241    HeightField(HeightField),
242    /// A Compound shape.
243    #[cfg(feature = "alloc")]
244    Compound(Compound),
245    #[cfg(feature = "dim2")]
246    #[cfg(feature = "alloc")]
247    ConvexPolygon(ConvexPolygon),
248    #[cfg(feature = "dim3")]
249    #[cfg(feature = "alloc")]
250    /// A convex polyhedron.
251    ConvexPolyhedron(ConvexPolyhedron),
252    #[cfg(feature = "dim3")]
253    /// A cylindrical shape.
254    Cylinder(Cylinder),
255    #[cfg(feature = "dim3")]
256    /// A cone shape.
257    Cone(Cone),
258    // /// A custom shape type.
259    // Custom(u8),
260    /// A cuboid with rounded corners.
261    RoundCuboid(RoundCuboid),
262    /// A triangle with rounded corners.
263    RoundTriangle(RoundTriangle),
264    // /// A triangle-mesh with rounded corners.
265    // RoundedTriMesh,
266    // /// An heightfield with rounded corners.
267    // RoundedHeightField,
268    /// A cylinder with rounded corners.
269    #[cfg(feature = "dim3")]
270    RoundCylinder(RoundCylinder),
271    /// A cone with rounded corners.
272    #[cfg(feature = "dim3")]
273    RoundCone(RoundCone),
274    /// A convex polyhedron with rounded corners.
275    #[cfg(feature = "dim3")]
276    #[cfg(feature = "alloc")]
277    RoundConvexPolyhedron(RoundConvexPolyhedron),
278    /// A convex polygon with rounded corners.
279    #[cfg(feature = "dim2")]
280    #[cfg(feature = "alloc")]
281    RoundConvexPolygon(RoundConvexPolygon),
282    /// A custom user-defined shape.
283    #[allow(dead_code)]
284    Custom,
285}
286
287#[cfg(feature = "serde-serialize")]
288impl DeserializableTypedShape {
289    /// Converts `self` to a `SharedShape` if `self` isn't `Custom`.
290    pub fn into_shared_shape(self) -> Option<SharedShape> {
291        match self {
292            DeserializableTypedShape::Ball(s) => Some(SharedShape::new(s)),
293            DeserializableTypedShape::Cuboid(s) => Some(SharedShape::new(s)),
294            DeserializableTypedShape::Capsule(s) => Some(SharedShape::new(s)),
295            DeserializableTypedShape::Segment(s) => Some(SharedShape::new(s)),
296            DeserializableTypedShape::Triangle(s) => Some(SharedShape::new(s)),
297            #[cfg(feature = "alloc")]
298            DeserializableTypedShape::Voxels(s) => Some(SharedShape::new(s)),
299            #[cfg(feature = "alloc")]
300            DeserializableTypedShape::TriMesh(s) => Some(SharedShape::new(s)),
301            #[cfg(feature = "alloc")]
302            DeserializableTypedShape::Polyline(s) => Some(SharedShape::new(s)),
303            DeserializableTypedShape::HalfSpace(s) => Some(SharedShape::new(s)),
304            #[cfg(feature = "alloc")]
305            DeserializableTypedShape::HeightField(s) => Some(SharedShape::new(s)),
306            #[cfg(feature = "alloc")]
307            DeserializableTypedShape::Compound(s) => Some(SharedShape::new(s)),
308            #[cfg(feature = "dim2")]
309            #[cfg(feature = "alloc")]
310            DeserializableTypedShape::ConvexPolygon(s) => Some(SharedShape::new(s)),
311            #[cfg(feature = "dim3")]
312            #[cfg(feature = "alloc")]
313            DeserializableTypedShape::ConvexPolyhedron(s) => Some(SharedShape::new(s)),
314            #[cfg(feature = "dim3")]
315            DeserializableTypedShape::Cylinder(s) => Some(SharedShape::new(s)),
316            #[cfg(feature = "dim3")]
317            DeserializableTypedShape::Cone(s) => Some(SharedShape::new(s)),
318            DeserializableTypedShape::RoundCuboid(s) => Some(SharedShape::new(s)),
319            DeserializableTypedShape::RoundTriangle(s) => Some(SharedShape::new(s)),
320            #[cfg(feature = "dim3")]
321            DeserializableTypedShape::RoundCylinder(s) => Some(SharedShape::new(s)),
322            #[cfg(feature = "dim3")]
323            DeserializableTypedShape::RoundCone(s) => Some(SharedShape::new(s)),
324            #[cfg(feature = "dim3")]
325            #[cfg(feature = "alloc")]
326            DeserializableTypedShape::RoundConvexPolyhedron(s) => Some(SharedShape::new(s)),
327            #[cfg(feature = "dim2")]
328            #[cfg(feature = "alloc")]
329            DeserializableTypedShape::RoundConvexPolygon(s) => Some(SharedShape::new(s)),
330            DeserializableTypedShape::Custom => None,
331        }
332    }
333}
334
335/// Trait implemented by shapes usable by Rapier.
336pub trait Shape: RayCast + PointQuery + DowncastSync {
337    /// Computes the [`Aabb`] of this shape.
338    fn compute_local_aabb(&self) -> Aabb;
339    /// Computes the bounding-sphere of this shape.
340    fn compute_local_bounding_sphere(&self) -> BoundingSphere;
341
342    /// Clones this shape into a boxed trait-object.
343    ///
344    /// The boxed trait-object has the same concrete type as `Self`.
345    #[cfg(feature = "alloc")]
346    #[deprecated = "renamed to `clone_dyn`"]
347    fn clone_box(&self) -> Box<dyn Shape> {
348        self.clone_dyn()
349    }
350
351    /// Clones this shape into a boxed trait-object.
352    ///
353    /// The boxed trait-object has the same concrete type as `Self`.
354    #[cfg(feature = "alloc")]
355    fn clone_dyn(&self) -> Box<dyn Shape>;
356
357    /// Scales this shape by `scale` into a boxed trait-object.
358    ///
359    /// In some cases, the resulting shape doesn’t have the same type as Self. For example,
360    /// if a non-uniform scale is provided and Self as a [`Ball`], then the result will be discretized
361    /// (based on the `num_subdivisions` parameter) as a `ConvexPolyhedron` (in 3D) or `ConvexPolygon` (in 2D).
362    #[cfg(feature = "alloc")]
363    fn scale_dyn(&self, scale: Vector, num_subdivisions: u32) -> Option<Box<dyn Shape>>;
364
365    /// Computes the [`Aabb`] of this shape with the given position.
366    fn compute_aabb(&self, position: &Pose) -> Aabb {
367        self.compute_local_aabb().transform_by(position)
368    }
369    /// Computes the bounding-sphere of this shape with the given position.
370    fn compute_bounding_sphere(&self, position: &Pose) -> BoundingSphere {
371        self.compute_local_bounding_sphere().transform_by(position)
372    }
373
374    /// Compute the mass-properties of this shape given its uniform density.
375    fn mass_properties(&self, density: Real) -> MassProperties;
376
377    /// Gets the type tag of this shape.
378    fn shape_type(&self) -> ShapeType;
379
380    /// Gets the underlying shape as an enum.
381    fn as_typed_shape(&self) -> TypedShape<'_>;
382
383    fn ccd_thickness(&self) -> Real;
384
385    // TODO: document this.
386    // This should probably be the largest sharp edge angle (in radians) in [0; PI].
387    // Though this isn't a very good description considering this is PI / 2
388    // for capsule (which doesn't have any sharp angle). I guess a better way
389    // to phrase this is: "the smallest angle such that rotating the shape by
390    // that angle may result in different contact points".
391    fn ccd_angular_thickness(&self) -> Real;
392
393    /// Is this shape known to be convex?
394    ///
395    /// If this returns `true` then `self` is known to be convex.
396    /// If this returns `false` then it is not known whether or
397    /// not `self` is convex.
398    fn is_convex(&self) -> bool {
399        false
400    }
401
402    /// Converts this shape into its support mapping, if it has one.
403    fn as_support_map(&self) -> Option<&dyn SupportMap> {
404        None
405    }
406
407    #[cfg(feature = "alloc")]
408    fn as_composite_shape(&self) -> Option<&dyn CompositeShape> {
409        None
410    }
411
412    /// Converts this shape to a polygonal feature-map, if it is one.
413    fn as_polygonal_feature_map(&self) -> Option<(&dyn PolygonalFeatureMap, Real)> {
414        None
415    }
416
417    // fn as_rounded(&self) -> Option<&Rounded<Box<AnyShape>>> {
418    //     None
419    // }
420
421    /// The shape's normal at the given point located on a specific feature.
422    fn feature_normal_at_point(&self, _feature: FeatureId, _point: Vector) -> Option<Vector> {
423        None
424    }
425
426    /// Computes the swept [`Aabb`] of this shape, i.e., the space it would occupy by moving from
427    /// the given start position to the given end position.
428    fn compute_swept_aabb(&self, start_pos: &Pose, end_pos: &Pose) -> Aabb {
429        let aabb1 = self.compute_aabb(start_pos);
430        let aabb2 = self.compute_aabb(end_pos);
431        aabb1.merged(&aabb2)
432    }
433}
434
435impl_downcast!(sync Shape);
436
437impl dyn Shape {
438    /// Converts this abstract shape to the given shape, if it is one.
439    pub fn as_shape<T: Shape>(&self) -> Option<&T> {
440        self.downcast_ref()
441    }
442    /// Converts this abstract shape to the given mutable shape, if it is one.
443    pub fn as_shape_mut<T: Shape>(&mut self) -> Option<&mut T> {
444        self.downcast_mut()
445    }
446
447    /// Converts this abstract shape to a ball, if it is one.
448    pub fn as_ball(&self) -> Option<&Ball> {
449        self.downcast_ref()
450    }
451    /// Converts this abstract shape to a mutable ball, if it is one.
452    pub fn as_ball_mut(&mut self) -> Option<&mut Ball> {
453        self.downcast_mut()
454    }
455
456    /// Converts this abstract shape to a cuboid, if it is one.
457    pub fn as_cuboid(&self) -> Option<&Cuboid> {
458        self.downcast_ref()
459    }
460    /// Converts this abstract shape to a mutable cuboid, if it is one.
461    pub fn as_cuboid_mut(&mut self) -> Option<&mut Cuboid> {
462        self.downcast_mut()
463    }
464
465    /// Converts this abstract shape to a halfspace, if it is one.
466    pub fn as_halfspace(&self) -> Option<&HalfSpace> {
467        self.downcast_ref()
468    }
469    /// Converts this abstract shape to a halfspace, if it is one.
470    pub fn as_halfspace_mut(&mut self) -> Option<&mut HalfSpace> {
471        self.downcast_mut()
472    }
473
474    /// Converts this abstract shape to a segment, if it is one.
475    pub fn as_segment(&self) -> Option<&Segment> {
476        self.downcast_ref()
477    }
478    /// Converts this abstract shape to a mutable segment, if it is one.
479    pub fn as_segment_mut(&mut self) -> Option<&mut Segment> {
480        self.downcast_mut()
481    }
482
483    /// Converts this abstract shape to a capsule, if it is one.
484    pub fn as_capsule(&self) -> Option<&Capsule> {
485        self.downcast_ref()
486    }
487    /// Converts this abstract shape to a mutable capsule, if it is one.
488    pub fn as_capsule_mut(&mut self) -> Option<&mut Capsule> {
489        self.downcast_mut()
490    }
491
492    /// Converts this abstract shape to a triangle, if it is one.
493    pub fn as_triangle(&self) -> Option<&Triangle> {
494        self.downcast_ref()
495    }
496    /// Converts this abstract shape to a mutable triangle, if it is one.
497    pub fn as_triangle_mut(&mut self) -> Option<&mut Triangle> {
498        self.downcast_mut()
499    }
500
501    /// Converts this abstract shape to voxels, if it is one.
502    #[cfg(feature = "alloc")]
503    pub fn as_voxels(&self) -> Option<&Voxels> {
504        self.downcast_ref()
505    }
506    /// Converts this abstract shape to mutable voxels, if it is one.
507    #[cfg(feature = "alloc")]
508    pub fn as_voxels_mut(&mut self) -> Option<&mut Voxels> {
509        self.downcast_mut()
510    }
511
512    /// Converts this abstract shape to a compound shape, if it is one.
513    #[cfg(feature = "alloc")]
514    pub fn as_compound(&self) -> Option<&Compound> {
515        self.downcast_ref()
516    }
517    /// Converts this abstract shape to a mutable compound shape, if it is one.
518    #[cfg(feature = "alloc")]
519    pub fn as_compound_mut(&mut self) -> Option<&mut Compound> {
520        self.downcast_mut()
521    }
522
523    /// Converts this abstract shape to a triangle mesh, if it is one.
524    #[cfg(feature = "alloc")]
525    pub fn as_trimesh(&self) -> Option<&TriMesh> {
526        self.downcast_ref()
527    }
528    /// Converts this abstract shape to a mutable triangle mesh, if it is one.
529    #[cfg(feature = "alloc")]
530    pub fn as_trimesh_mut(&mut self) -> Option<&mut TriMesh> {
531        self.downcast_mut()
532    }
533
534    /// Converts this abstract shape to a polyline, if it is one.
535    #[cfg(feature = "alloc")]
536    pub fn as_polyline(&self) -> Option<&Polyline> {
537        self.downcast_ref()
538    }
539    /// Converts this abstract shape to a mutable polyline, if it is one.
540    #[cfg(feature = "alloc")]
541    pub fn as_polyline_mut(&mut self) -> Option<&mut Polyline> {
542        self.downcast_mut()
543    }
544
545    /// Converts this abstract shape to a heightfield, if it is one.
546    #[cfg(feature = "alloc")]
547    pub fn as_heightfield(&self) -> Option<&HeightField> {
548        self.downcast_ref()
549    }
550    /// Converts this abstract shape to a mutable heightfield, if it is one.
551    #[cfg(feature = "alloc")]
552    pub fn as_heightfield_mut(&mut self) -> Option<&mut HeightField> {
553        self.downcast_mut()
554    }
555
556    /// Converts this abstract shape to a round cuboid, if it is one.
557    pub fn as_round_cuboid(&self) -> Option<&RoundCuboid> {
558        self.downcast_ref()
559    }
560    /// Converts this abstract shape to a mutable round cuboid, if it is one.
561    pub fn as_round_cuboid_mut(&mut self) -> Option<&mut RoundCuboid> {
562        self.downcast_mut()
563    }
564
565    /// Converts this abstract shape to a round triangle, if it is one.
566    pub fn as_round_triangle(&self) -> Option<&RoundTriangle> {
567        self.downcast_ref()
568    }
569    /// Converts this abstract shape to a round triangle, if it is one.
570    pub fn as_round_triangle_mut(&mut self) -> Option<&mut RoundTriangle> {
571        self.downcast_mut()
572    }
573
574    /// Converts this abstract shape to a convex polygon, if it is one.
575    #[cfg(feature = "dim2")]
576    #[cfg(feature = "alloc")]
577    pub fn as_convex_polygon(&self) -> Option<&ConvexPolygon> {
578        self.downcast_ref()
579    }
580    /// Converts this abstract shape to a mutable convex polygon, if it is one.
581    #[cfg(feature = "dim2")]
582    #[cfg(feature = "alloc")]
583    pub fn as_convex_polygon_mut(&mut self) -> Option<&mut ConvexPolygon> {
584        self.downcast_mut()
585    }
586
587    /// Converts this abstract shape to a round convex polygon, if it is one.
588    #[cfg(feature = "dim2")]
589    #[cfg(feature = "alloc")]
590    pub fn as_round_convex_polygon(&self) -> Option<&RoundConvexPolygon> {
591        self.downcast_ref()
592    }
593    /// Converts this abstract shape to a mutable round convex polygon, if it is one.
594    #[cfg(feature = "dim2")]
595    #[cfg(feature = "alloc")]
596    pub fn as_round_convex_polygon_mut(&mut self) -> Option<&mut RoundConvexPolygon> {
597        self.downcast_mut()
598    }
599
600    #[cfg(feature = "dim3")]
601    #[cfg(feature = "alloc")]
602    pub fn as_convex_polyhedron(&self) -> Option<&ConvexPolyhedron> {
603        self.downcast_ref()
604    }
605    #[cfg(feature = "dim3")]
606    #[cfg(feature = "alloc")]
607    pub fn as_convex_polyhedron_mut(&mut self) -> Option<&mut ConvexPolyhedron> {
608        self.downcast_mut()
609    }
610
611    /// Converts this abstract shape to a cylinder, if it is one.
612    #[cfg(feature = "dim3")]
613    pub fn as_cylinder(&self) -> Option<&Cylinder> {
614        self.downcast_ref()
615    }
616    /// Converts this abstract shape to a mutable cylinder, if it is one.
617    #[cfg(feature = "dim3")]
618    pub fn as_cylinder_mut(&mut self) -> Option<&mut Cylinder> {
619        self.downcast_mut()
620    }
621
622    /// Converts this abstract shape to a cone, if it is one.
623    #[cfg(feature = "dim3")]
624    pub fn as_cone(&self) -> Option<&Cone> {
625        self.downcast_ref()
626    }
627    /// Converts this abstract shape to a mutable cone, if it is one.
628    #[cfg(feature = "dim3")]
629    pub fn as_cone_mut(&mut self) -> Option<&mut Cone> {
630        self.downcast_mut()
631    }
632
633    /// Converts this abstract shape to a round cylinder, if it is one.
634    #[cfg(feature = "dim3")]
635    pub fn as_round_cylinder(&self) -> Option<&RoundCylinder> {
636        self.downcast_ref()
637    }
638    /// Converts this abstract shape to a mutable round cylinder, if it is one.
639    #[cfg(feature = "dim3")]
640    pub fn as_round_cylinder_mut(&mut self) -> Option<&mut RoundCylinder> {
641        self.downcast_mut()
642    }
643
644    /// Converts this abstract shape to a round cone, if it is one.
645    #[cfg(feature = "dim3")]
646    pub fn as_round_cone(&self) -> Option<&RoundCone> {
647        self.downcast_ref()
648    }
649    /// Converts this abstract shape to a mutable round cone, if it is one.
650    #[cfg(feature = "dim3")]
651    pub fn as_round_cone_mut(&mut self) -> Option<&mut RoundCone> {
652        self.downcast_mut()
653    }
654
655    /// Converts this abstract shape to a round convex polyhedron, if it is one.
656    #[cfg(feature = "dim3")]
657    #[cfg(feature = "alloc")]
658    pub fn as_round_convex_polyhedron(&self) -> Option<&RoundConvexPolyhedron> {
659        self.downcast_ref()
660    }
661    /// Converts this abstract shape to a mutable round convex polyhedron, if it is one.
662    #[cfg(feature = "dim3")]
663    #[cfg(feature = "alloc")]
664    pub fn as_round_convex_polyhedron_mut(&mut self) -> Option<&mut RoundConvexPolyhedron> {
665        self.downcast_mut()
666    }
667}
668
669impl Shape for Ball {
670    #[cfg(feature = "alloc")]
671    fn clone_dyn(&self) -> Box<dyn Shape> {
672        Box::new(*self)
673    }
674
675    #[cfg(feature = "alloc")]
676    fn scale_dyn(&self, scale: Vector, num_subdivisions: u32) -> Option<Box<dyn Shape>> {
677        let scaled = self.scaled(scale, num_subdivisions)?;
678        Some(scaled.either::<_, _, Box<dyn Shape>>(|x| Box::new(x), |x| Box::new(x)))
679    }
680
681    fn compute_local_aabb(&self) -> Aabb {
682        self.local_aabb()
683    }
684
685    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
686        self.local_bounding_sphere()
687    }
688
689    fn compute_aabb(&self, position: &Pose) -> Aabb {
690        self.aabb(position)
691    }
692
693    fn mass_properties(&self, density: Real) -> MassProperties {
694        MassProperties::from_ball(density, self.radius)
695    }
696
697    fn ccd_thickness(&self) -> Real {
698        self.radius
699    }
700
701    fn ccd_angular_thickness(&self) -> Real {
702        Real::pi()
703    }
704
705    fn is_convex(&self) -> bool {
706        true
707    }
708
709    fn shape_type(&self) -> ShapeType {
710        ShapeType::Ball
711    }
712
713    fn as_typed_shape(&self) -> TypedShape<'_> {
714        TypedShape::Ball(self)
715    }
716
717    fn as_support_map(&self) -> Option<&dyn SupportMap> {
718        Some(self as &dyn SupportMap)
719    }
720
721    /// The shape's normal at the given point located on a specific feature.
722    #[inline]
723    fn feature_normal_at_point(&self, _: FeatureId, point: Vector) -> Option<Vector> {
724        (point).try_normalize()
725    }
726}
727
728impl Shape for Cuboid {
729    #[cfg(feature = "alloc")]
730    fn clone_dyn(&self) -> Box<dyn Shape> {
731        Box::new(*self)
732    }
733
734    #[cfg(feature = "alloc")]
735    fn scale_dyn(&self, scale: Vector, _num_subdivisions: u32) -> Option<Box<dyn Shape>> {
736        Some(Box::new(self.scaled(scale)))
737    }
738
739    fn compute_local_aabb(&self) -> Aabb {
740        self.local_aabb()
741    }
742
743    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
744        self.local_bounding_sphere()
745    }
746
747    fn compute_aabb(&self, position: &Pose) -> Aabb {
748        self.aabb(position)
749    }
750
751    fn mass_properties(&self, density: Real) -> MassProperties {
752        MassProperties::from_cuboid(density, self.half_extents)
753    }
754
755    fn is_convex(&self) -> bool {
756        true
757    }
758
759    fn shape_type(&self) -> ShapeType {
760        ShapeType::Cuboid
761    }
762
763    fn as_typed_shape(&self) -> TypedShape<'_> {
764        TypedShape::Cuboid(self)
765    }
766
767    fn ccd_thickness(&self) -> Real {
768        self.half_extents.min_element()
769    }
770
771    fn ccd_angular_thickness(&self) -> Real {
772        Real::frac_pi_2()
773    }
774
775    fn as_support_map(&self) -> Option<&dyn SupportMap> {
776        Some(self as &dyn SupportMap)
777    }
778
779    fn as_polygonal_feature_map(&self) -> Option<(&dyn PolygonalFeatureMap, Real)> {
780        Some((self as &dyn PolygonalFeatureMap, 0.0))
781    }
782
783    fn feature_normal_at_point(&self, feature: FeatureId, _point: Vector) -> Option<Vector> {
784        self.feature_normal(feature)
785    }
786}
787
788impl Shape for Capsule {
789    #[cfg(feature = "alloc")]
790    fn clone_dyn(&self) -> Box<dyn Shape> {
791        Box::new(*self)
792    }
793
794    #[cfg(feature = "alloc")]
795    fn scale_dyn(&self, scale: Vector, num_subdivisions: u32) -> Option<Box<dyn Shape>> {
796        let scaled = self.scaled(scale, num_subdivisions)?;
797        Some(scaled.either::<_, _, Box<dyn Shape>>(|x| Box::new(x), |x| Box::new(x)))
798    }
799
800    fn compute_local_aabb(&self) -> Aabb {
801        self.local_aabb()
802    }
803
804    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
805        self.local_bounding_sphere()
806    }
807
808    fn compute_aabb(&self, position: &Pose) -> Aabb {
809        self.aabb(position)
810    }
811
812    fn mass_properties(&self, density: Real) -> MassProperties {
813        MassProperties::from_capsule(density, self.segment.a, self.segment.b, self.radius)
814    }
815
816    fn is_convex(&self) -> bool {
817        true
818    }
819
820    fn shape_type(&self) -> ShapeType {
821        ShapeType::Capsule
822    }
823
824    fn as_typed_shape(&self) -> TypedShape<'_> {
825        TypedShape::Capsule(self)
826    }
827
828    fn ccd_thickness(&self) -> Real {
829        self.radius
830    }
831
832    fn ccd_angular_thickness(&self) -> Real {
833        Real::frac_pi_2()
834    }
835
836    fn as_support_map(&self) -> Option<&dyn SupportMap> {
837        Some(self as &dyn SupportMap)
838    }
839
840    fn as_polygonal_feature_map(&self) -> Option<(&dyn PolygonalFeatureMap, Real)> {
841        Some((&self.segment as &dyn PolygonalFeatureMap, self.radius))
842    }
843}
844
845impl Shape for Triangle {
846    #[cfg(feature = "alloc")]
847    fn clone_dyn(&self) -> Box<dyn Shape> {
848        Box::new(*self)
849    }
850
851    #[cfg(feature = "alloc")]
852    fn scale_dyn(&self, scale: Vector, _num_subdivisions: u32) -> Option<Box<dyn Shape>> {
853        Some(Box::new(self.scaled(scale)))
854    }
855
856    fn compute_local_aabb(&self) -> Aabb {
857        self.local_aabb()
858    }
859
860    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
861        self.local_bounding_sphere()
862    }
863
864    fn compute_aabb(&self, position: &Pose) -> Aabb {
865        self.aabb(position)
866    }
867
868    fn mass_properties(&self, _density: Real) -> MassProperties {
869        #[cfg(feature = "dim2")]
870        return MassProperties::from_triangle(_density, self.a, self.b, self.c);
871        #[cfg(feature = "dim3")]
872        return MassProperties::zero();
873    }
874
875    fn is_convex(&self) -> bool {
876        true
877    }
878
879    fn shape_type(&self) -> ShapeType {
880        ShapeType::Triangle
881    }
882
883    fn as_typed_shape(&self) -> TypedShape<'_> {
884        TypedShape::Triangle(self)
885    }
886
887    fn ccd_thickness(&self) -> Real {
888        // TODO: in 2D use the smallest height of the triangle.
889        0.0
890    }
891
892    fn ccd_angular_thickness(&self) -> Real {
893        Real::frac_pi_2()
894    }
895
896    fn as_support_map(&self) -> Option<&dyn SupportMap> {
897        Some(self as &dyn SupportMap)
898    }
899
900    fn as_polygonal_feature_map(&self) -> Option<(&dyn PolygonalFeatureMap, Real)> {
901        Some((self as &dyn PolygonalFeatureMap, 0.0))
902    }
903
904    fn feature_normal_at_point(&self, _feature: FeatureId, _point: Vector) -> Option<Vector> {
905        #[cfg(feature = "dim2")]
906        return None;
907        #[cfg(feature = "dim3")]
908        return self.feature_normal(_feature);
909    }
910}
911
912impl Shape for Segment {
913    #[cfg(feature = "alloc")]
914    fn clone_dyn(&self) -> Box<dyn Shape> {
915        Box::new(*self)
916    }
917
918    #[cfg(feature = "alloc")]
919    fn scale_dyn(&self, scale: Vector, _num_subdivisions: u32) -> Option<Box<dyn Shape>> {
920        Some(Box::new(self.scaled(scale)))
921    }
922
923    fn compute_local_aabb(&self) -> Aabb {
924        self.local_aabb()
925    }
926
927    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
928        self.local_bounding_sphere()
929    }
930
931    fn compute_aabb(&self, position: &Pose) -> Aabb {
932        self.aabb(position)
933    }
934
935    fn mass_properties(&self, _density: Real) -> MassProperties {
936        MassProperties::zero()
937    }
938
939    fn is_convex(&self) -> bool {
940        true
941    }
942
943    fn ccd_thickness(&self) -> Real {
944        0.0
945    }
946
947    fn ccd_angular_thickness(&self) -> Real {
948        Real::frac_pi_2()
949    }
950
951    fn shape_type(&self) -> ShapeType {
952        ShapeType::Segment
953    }
954
955    fn as_typed_shape(&self) -> TypedShape<'_> {
956        TypedShape::Segment(self)
957    }
958
959    fn as_support_map(&self) -> Option<&dyn SupportMap> {
960        Some(self as &dyn SupportMap)
961    }
962
963    fn as_polygonal_feature_map(&self) -> Option<(&dyn PolygonalFeatureMap, Real)> {
964        Some((self as &dyn PolygonalFeatureMap, 0.0))
965    }
966
967    fn feature_normal_at_point(&self, feature: FeatureId, _point: Vector) -> Option<Vector> {
968        self.feature_normal(feature)
969    }
970}
971
972#[cfg(feature = "alloc")]
973impl Shape for Compound {
974    fn clone_dyn(&self) -> Box<dyn Shape> {
975        Box::new(self.clone())
976    }
977
978    fn scale_dyn(&self, scale: Vector, num_subdivisions: u32) -> Option<Box<dyn Shape>> {
979        use super::SharedShape;
980
981        let scaled: Vec<_> = self
982            .shapes()
983            .iter()
984            .map(|(pos, shape)| {
985                let scaled_shape = shape.scale_dyn(scale, num_subdivisions)?;
986                Some((
987                    Pose::from_parts(pos.translation * scale, pos.rotation),
988                    SharedShape(scaled_shape.into()),
989                ))
990            })
991            .collect::<Option<Vec<_>>>()?;
992        Some(Box::new(Compound::new(scaled)))
993    }
994
995    fn compute_local_aabb(&self) -> Aabb {
996        *self.local_aabb()
997    }
998
999    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
1000        self.local_bounding_sphere()
1001    }
1002
1003    fn compute_aabb(&self, position: &Pose) -> Aabb {
1004        self.local_aabb().transform_by(position)
1005    }
1006
1007    fn mass_properties(&self, density: Real) -> MassProperties {
1008        MassProperties::from_compound(density, self.shapes())
1009    }
1010
1011    fn shape_type(&self) -> ShapeType {
1012        ShapeType::Compound
1013    }
1014
1015    fn as_typed_shape(&self) -> TypedShape<'_> {
1016        TypedShape::Compound(self)
1017    }
1018
1019    fn ccd_thickness(&self) -> Real {
1020        self.shapes()
1021            .iter()
1022            .fold(Real::MAX, |curr, (_, s)| curr.min(s.ccd_thickness()))
1023    }
1024
1025    fn ccd_angular_thickness(&self) -> Real {
1026        self.shapes().iter().fold(Real::MAX, |curr, (_, s)| {
1027            curr.max(s.ccd_angular_thickness())
1028        })
1029    }
1030
1031    #[cfg(feature = "alloc")]
1032    fn as_composite_shape(&self) -> Option<&dyn CompositeShape> {
1033        Some(self as &dyn CompositeShape)
1034    }
1035}
1036
1037#[cfg(feature = "alloc")]
1038impl Shape for Polyline {
1039    fn clone_dyn(&self) -> Box<dyn Shape> {
1040        Box::new(self.clone())
1041    }
1042
1043    fn scale_dyn(&self, scale: Vector, _num_subdivisions: u32) -> Option<Box<dyn Shape>> {
1044        Some(Box::new(self.clone().scaled(scale)))
1045    }
1046
1047    fn compute_local_aabb(&self) -> Aabb {
1048        self.local_aabb()
1049    }
1050
1051    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
1052        self.local_bounding_sphere()
1053    }
1054
1055    fn compute_aabb(&self, position: &Pose) -> Aabb {
1056        self.aabb(position)
1057    }
1058
1059    fn mass_properties(&self, _density: Real) -> MassProperties {
1060        MassProperties::zero()
1061    }
1062
1063    fn shape_type(&self) -> ShapeType {
1064        ShapeType::Polyline
1065    }
1066
1067    fn as_typed_shape(&self) -> TypedShape<'_> {
1068        TypedShape::Polyline(self)
1069    }
1070
1071    fn ccd_thickness(&self) -> Real {
1072        0.0
1073    }
1074
1075    fn ccd_angular_thickness(&self) -> Real {
1076        // TODO: the value should depend on the angles between
1077        // adjacent segments of the polyline.
1078        Real::frac_pi_4()
1079    }
1080
1081    #[cfg(feature = "alloc")]
1082    fn as_composite_shape(&self) -> Option<&dyn CompositeShape> {
1083        Some(self as &dyn CompositeShape)
1084    }
1085}
1086
1087#[cfg(feature = "alloc")]
1088impl Shape for TriMesh {
1089    fn clone_dyn(&self) -> Box<dyn Shape> {
1090        Box::new(self.clone())
1091    }
1092
1093    fn scale_dyn(&self, scale: Vector, _num_subdivisions: u32) -> Option<Box<dyn Shape>> {
1094        Some(Box::new(self.clone().scaled(scale)))
1095    }
1096
1097    fn compute_local_aabb(&self) -> Aabb {
1098        self.local_aabb()
1099    }
1100
1101    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
1102        self.local_bounding_sphere()
1103    }
1104
1105    fn compute_aabb(&self, position: &Pose) -> Aabb {
1106        self.aabb(position)
1107    }
1108
1109    fn mass_properties(&self, density: Real) -> MassProperties {
1110        MassProperties::from_trimesh(density, self.vertices(), self.indices())
1111    }
1112
1113    fn shape_type(&self) -> ShapeType {
1114        ShapeType::TriMesh
1115    }
1116
1117    fn as_typed_shape(&self) -> TypedShape<'_> {
1118        TypedShape::TriMesh(self)
1119    }
1120
1121    fn ccd_thickness(&self) -> Real {
1122        // TODO: in 2D, return the smallest CCD thickness among triangles?
1123        0.0
1124    }
1125
1126    fn ccd_angular_thickness(&self) -> Real {
1127        // TODO: the value should depend on the angles between
1128        // adjacent triangles of the trimesh.
1129        Real::frac_pi_4()
1130    }
1131
1132    /// Gets the normal of the triangle represented by `feature`.
1133    fn feature_normal_at_point(&self, _feature: FeatureId, _point: Vector) -> Option<Vector> {
1134        #[cfg(feature = "dim2")]
1135        return None;
1136        #[cfg(feature = "dim3")]
1137        return self.feature_normal(_feature);
1138    }
1139
1140    #[cfg(feature = "alloc")]
1141    fn as_composite_shape(&self) -> Option<&dyn CompositeShape> {
1142        Some(self as &dyn CompositeShape)
1143    }
1144}
1145
1146#[cfg(feature = "alloc")]
1147impl Shape for HeightField {
1148    fn clone_dyn(&self) -> Box<dyn Shape> {
1149        Box::new(self.clone())
1150    }
1151
1152    fn scale_dyn(&self, scale: Vector, _num_subdivisions: u32) -> Option<Box<dyn Shape>> {
1153        Some(Box::new(self.clone().scaled(scale)))
1154    }
1155
1156    fn compute_local_aabb(&self) -> Aabb {
1157        self.local_aabb()
1158    }
1159
1160    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
1161        self.local_bounding_sphere()
1162    }
1163
1164    fn compute_aabb(&self, position: &Pose) -> Aabb {
1165        self.aabb(position)
1166    }
1167
1168    fn mass_properties(&self, _density: Real) -> MassProperties {
1169        MassProperties::zero()
1170    }
1171
1172    fn shape_type(&self) -> ShapeType {
1173        ShapeType::HeightField
1174    }
1175
1176    fn as_typed_shape(&self) -> TypedShape<'_> {
1177        TypedShape::HeightField(self)
1178    }
1179
1180    fn ccd_thickness(&self) -> Real {
1181        0.0
1182    }
1183
1184    fn ccd_angular_thickness(&self) -> Real {
1185        // TODO: the value should depend on the angles between
1186        // adjacent triangles of the heightfield.
1187        Real::frac_pi_4()
1188    }
1189}
1190
1191#[cfg(feature = "dim2")]
1192#[cfg(feature = "alloc")]
1193impl Shape for ConvexPolygon {
1194    fn clone_dyn(&self) -> Box<dyn Shape> {
1195        Box::new(self.clone())
1196    }
1197
1198    fn scale_dyn(&self, scale: Vector, _num_subdivisions: u32) -> Option<Box<dyn Shape>> {
1199        Some(Box::new(self.clone().scaled(scale)?))
1200    }
1201
1202    fn compute_local_aabb(&self) -> Aabb {
1203        self.local_aabb()
1204    }
1205
1206    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
1207        self.local_bounding_sphere()
1208    }
1209
1210    fn compute_aabb(&self, position: &Pose) -> Aabb {
1211        self.aabb(position)
1212    }
1213
1214    fn mass_properties(&self, density: Real) -> MassProperties {
1215        MassProperties::from_convex_polygon(density, self.points())
1216    }
1217
1218    fn is_convex(&self) -> bool {
1219        true
1220    }
1221
1222    fn shape_type(&self) -> ShapeType {
1223        ShapeType::ConvexPolygon
1224    }
1225
1226    fn as_typed_shape(&self) -> TypedShape<'_> {
1227        TypedShape::ConvexPolygon(self)
1228    }
1229
1230    fn ccd_thickness(&self) -> Real {
1231        // TODO: we should use the OBB instead.
1232        self.compute_local_aabb().half_extents().min_element()
1233    }
1234
1235    fn ccd_angular_thickness(&self) -> Real {
1236        // TODO: the value should depend on the angles between
1237        // adjacent segments of the convex polygon.
1238        Real::frac_pi_4()
1239    }
1240
1241    fn as_support_map(&self) -> Option<&dyn SupportMap> {
1242        Some(self as &dyn SupportMap)
1243    }
1244
1245    fn as_polygonal_feature_map(&self) -> Option<(&dyn PolygonalFeatureMap, Real)> {
1246        Some((self as &dyn PolygonalFeatureMap, 0.0))
1247    }
1248
1249    fn feature_normal_at_point(&self, feature: FeatureId, _point: Vector) -> Option<Vector> {
1250        self.feature_normal(feature)
1251    }
1252}
1253
1254#[cfg(feature = "dim3")]
1255#[cfg(feature = "alloc")]
1256impl Shape for ConvexPolyhedron {
1257    fn clone_dyn(&self) -> Box<dyn Shape> {
1258        Box::new(self.clone())
1259    }
1260
1261    fn scale_dyn(&self, scale: Vector, _num_subdivisions: u32) -> Option<Box<dyn Shape>> {
1262        Some(Box::new(self.clone().scaled(scale)?))
1263    }
1264
1265    fn compute_local_aabb(&self) -> Aabb {
1266        self.local_aabb()
1267    }
1268
1269    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
1270        self.local_bounding_sphere()
1271    }
1272
1273    fn compute_aabb(&self, position: &Pose) -> Aabb {
1274        self.aabb(position)
1275    }
1276
1277    fn mass_properties(&self, density: Real) -> MassProperties {
1278        let (vertices, indices) = self.to_trimesh();
1279        MassProperties::from_convex_polyhedron(density, &vertices, &indices)
1280    }
1281
1282    fn is_convex(&self) -> bool {
1283        true
1284    }
1285
1286    fn shape_type(&self) -> ShapeType {
1287        ShapeType::ConvexPolyhedron
1288    }
1289
1290    fn as_typed_shape(&self) -> TypedShape<'_> {
1291        TypedShape::ConvexPolyhedron(self)
1292    }
1293
1294    fn ccd_thickness(&self) -> Real {
1295        // TODO: we should use the OBB instead.
1296        self.compute_local_aabb().half_extents().min_element()
1297    }
1298
1299    fn ccd_angular_thickness(&self) -> Real {
1300        // TODO: the value should depend on the angles between
1301        // adjacent segments of the convex polyhedron.
1302        Real::frac_pi_4()
1303    }
1304
1305    fn as_support_map(&self) -> Option<&dyn SupportMap> {
1306        Some(self as &dyn SupportMap)
1307    }
1308
1309    fn as_polygonal_feature_map(&self) -> Option<(&dyn PolygonalFeatureMap, Real)> {
1310        Some((self as &dyn PolygonalFeatureMap, 0.0))
1311    }
1312
1313    fn feature_normal_at_point(&self, feature: FeatureId, _point: Vector) -> Option<Vector> {
1314        self.feature_normal(feature)
1315    }
1316}
1317
1318#[cfg(feature = "dim3")]
1319impl Shape for Cylinder {
1320    #[cfg(feature = "alloc")]
1321    fn clone_dyn(&self) -> Box<dyn Shape> {
1322        Box::new(*self)
1323    }
1324
1325    #[cfg(feature = "alloc")]
1326    fn scale_dyn(&self, scale: Vector, num_subdivisions: u32) -> Option<Box<dyn Shape>> {
1327        let scaled = self.scaled(scale, num_subdivisions)?;
1328        Some(scaled.either::<_, _, Box<dyn Shape>>(|x| Box::new(x), |x| Box::new(x)))
1329    }
1330
1331    fn compute_local_aabb(&self) -> Aabb {
1332        self.local_aabb()
1333    }
1334
1335    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
1336        self.local_bounding_sphere()
1337    }
1338
1339    fn compute_aabb(&self, position: &Pose) -> Aabb {
1340        self.aabb(position)
1341    }
1342
1343    fn mass_properties(&self, density: Real) -> MassProperties {
1344        MassProperties::from_cylinder(density, self.half_height, self.radius)
1345    }
1346
1347    fn is_convex(&self) -> bool {
1348        true
1349    }
1350
1351    fn shape_type(&self) -> ShapeType {
1352        ShapeType::Cylinder
1353    }
1354
1355    fn as_typed_shape(&self) -> TypedShape<'_> {
1356        TypedShape::Cylinder(self)
1357    }
1358
1359    fn ccd_thickness(&self) -> Real {
1360        self.radius
1361    }
1362
1363    fn ccd_angular_thickness(&self) -> Real {
1364        Real::frac_pi_2()
1365    }
1366
1367    fn as_support_map(&self) -> Option<&dyn SupportMap> {
1368        Some(self as &dyn SupportMap)
1369    }
1370
1371    fn as_polygonal_feature_map(&self) -> Option<(&dyn PolygonalFeatureMap, Real)> {
1372        Some((self as &dyn PolygonalFeatureMap, 0.0))
1373    }
1374}
1375
1376#[cfg(feature = "dim3")]
1377impl Shape for Cone {
1378    #[cfg(feature = "alloc")]
1379    fn clone_dyn(&self) -> Box<dyn Shape> {
1380        Box::new(*self)
1381    }
1382
1383    #[cfg(feature = "alloc")]
1384    fn scale_dyn(&self, scale: Vector, num_subdivisions: u32) -> Option<Box<dyn Shape>> {
1385        let scaled = self.scaled(scale, num_subdivisions)?;
1386        Some(scaled.either::<_, _, Box<dyn Shape>>(|x| Box::new(x), |x| Box::new(x)))
1387    }
1388
1389    fn compute_local_aabb(&self) -> Aabb {
1390        self.local_aabb()
1391    }
1392
1393    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
1394        self.local_bounding_sphere()
1395    }
1396
1397    fn compute_aabb(&self, position: &Pose) -> Aabb {
1398        self.aabb(position)
1399    }
1400
1401    fn mass_properties(&self, density: Real) -> MassProperties {
1402        MassProperties::from_cone(density, self.half_height, self.radius)
1403    }
1404
1405    fn is_convex(&self) -> bool {
1406        true
1407    }
1408
1409    fn shape_type(&self) -> ShapeType {
1410        ShapeType::Cone
1411    }
1412
1413    fn as_typed_shape(&self) -> TypedShape<'_> {
1414        TypedShape::Cone(self)
1415    }
1416
1417    fn ccd_thickness(&self) -> Real {
1418        self.radius
1419    }
1420
1421    fn ccd_angular_thickness(&self) -> Real {
1422        let apex_half_angle = RealField::atan2(self.radius, self.half_height);
1423        assert!(apex_half_angle >= 0.0);
1424        let basis_angle = Real::frac_pi_2() - apex_half_angle;
1425        basis_angle.min(apex_half_angle * 2.0)
1426    }
1427
1428    fn as_support_map(&self) -> Option<&dyn SupportMap> {
1429        Some(self as &dyn SupportMap)
1430    }
1431
1432    fn as_polygonal_feature_map(&self) -> Option<(&dyn PolygonalFeatureMap, Real)> {
1433        Some((self as &dyn PolygonalFeatureMap, 0.0))
1434    }
1435}
1436
1437impl Shape for HalfSpace {
1438    #[cfg(feature = "alloc")]
1439    fn clone_dyn(&self) -> Box<dyn Shape> {
1440        Box::new(*self)
1441    }
1442
1443    #[cfg(feature = "alloc")]
1444    fn scale_dyn(&self, scale: Vector, _num_subdivisions: u32) -> Option<Box<dyn Shape>> {
1445        Some(Box::new(self.scaled(scale)?))
1446    }
1447
1448    fn compute_local_aabb(&self) -> Aabb {
1449        self.local_aabb()
1450    }
1451
1452    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
1453        self.local_bounding_sphere()
1454    }
1455
1456    fn compute_aabb(&self, position: &Pose) -> Aabb {
1457        self.aabb(position)
1458    }
1459
1460    fn is_convex(&self) -> bool {
1461        true
1462    }
1463
1464    fn ccd_thickness(&self) -> Real {
1465        #[cfg_attr(feature = "f32", expect(clippy::unnecessary_cast))]
1466        let result = f32::MAX as Real;
1467        result
1468    }
1469
1470    fn ccd_angular_thickness(&self) -> Real {
1471        Real::pi()
1472    }
1473
1474    fn mass_properties(&self, _: Real) -> MassProperties {
1475        MassProperties::zero()
1476    }
1477
1478    fn shape_type(&self) -> ShapeType {
1479        ShapeType::HalfSpace
1480    }
1481
1482    fn as_typed_shape(&self) -> TypedShape<'_> {
1483        TypedShape::HalfSpace(self)
1484    }
1485}
1486
1487#[cfg(feature = "alloc")]
1488impl Shape for Voxels {
1489    fn compute_local_aabb(&self) -> Aabb {
1490        self.local_aabb()
1491    }
1492
1493    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
1494        self.local_bounding_sphere()
1495    }
1496
1497    fn clone_dyn(&self) -> Box<dyn Shape> {
1498        Box::new(self.clone())
1499    }
1500
1501    fn scale_dyn(&self, scale: Vector, _num_subdivisions: u32) -> Option<Box<dyn Shape>> {
1502        Some(Box::new(self.clone().scaled(scale)))
1503    }
1504
1505    fn mass_properties(&self, density: Real) -> MassProperties {
1506        MassProperties::from_voxels(density, self)
1507    }
1508
1509    fn shape_type(&self) -> ShapeType {
1510        ShapeType::Voxels
1511    }
1512
1513    fn as_typed_shape(&self) -> TypedShape<'_> {
1514        TypedShape::Voxels(self)
1515    }
1516
1517    fn ccd_thickness(&self) -> Real {
1518        self.voxel_size().min_element()
1519    }
1520
1521    fn ccd_angular_thickness(&self) -> Real {
1522        Real::frac_pi_2()
1523    }
1524}
1525
1526macro_rules! impl_shape_for_round_shape(
1527    ($S: ty, $Tag: ident, $t: tt) => {
1528        impl Shape for RoundShape<$S> {
1529            #[cfg(feature = "alloc")]
1530            fn clone_dyn(&self) -> Box<dyn Shape> {
1531                Box::new(self.clone())
1532            }
1533
1534            #[cfg(feature = "alloc")]
1535            fn scale_dyn(&self, scale: Vector, num_subdivisions: u32) -> Option<Box<dyn Shape>> {
1536                $t(self, scale, num_subdivisions)
1537            }
1538
1539            fn compute_local_aabb(&self) -> Aabb {
1540                self.inner_shape.local_aabb().loosened(self.border_radius)
1541            }
1542
1543            fn compute_local_bounding_sphere(&self) -> BoundingSphere {
1544                self.inner_shape.local_bounding_sphere().loosened(self.border_radius)
1545            }
1546
1547            fn compute_aabb(&self, position: &Pose) -> Aabb {
1548                self.inner_shape.aabb(position).loosened(self.border_radius)
1549            }
1550
1551            fn mass_properties(&self, density: Real) -> MassProperties {
1552                self.inner_shape.mass_properties(density)
1553            }
1554
1555            fn is_convex(&self) -> bool {
1556                self.inner_shape.is_convex()
1557            }
1558
1559            fn shape_type(&self) -> ShapeType {
1560                ShapeType::$Tag
1561            }
1562
1563            fn as_typed_shape(&self) -> TypedShape<'_> {
1564                TypedShape::$Tag(self)
1565            }
1566
1567            fn ccd_thickness(&self) -> Real {
1568                self.inner_shape.ccd_thickness() + self.border_radius
1569            }
1570
1571            fn ccd_angular_thickness(&self) -> Real {
1572                // The fact that the shape is round doesn't change anything
1573                // to the CCD angular thickness.
1574                self.inner_shape.ccd_angular_thickness()
1575            }
1576
1577            fn as_support_map(&self) -> Option<&dyn SupportMap> {
1578                Some(self as &dyn SupportMap)
1579            }
1580
1581            fn as_polygonal_feature_map(&self) -> Option<(&dyn PolygonalFeatureMap, Real)> {
1582                Some((&self.inner_shape as &dyn PolygonalFeatureMap, self.border_radius))
1583            }
1584        }
1585    }
1586);
1587
1588impl_shape_for_round_shape!(
1589    Cuboid,
1590    RoundCuboid,
1591    (|this: &Self, scale: Vector, _num_subdivisions: u32| {
1592        let shape = RoundShape {
1593            border_radius: this.border_radius,
1594            inner_shape: this.inner_shape.scaled(scale),
1595        };
1596        Some(Box::new(shape) as Box<dyn Shape>)
1597    })
1598);
1599
1600impl_shape_for_round_shape!(
1601    Triangle,
1602    RoundTriangle,
1603    (|this: &Self, scale: Vector, _num_subdivisions: u32| {
1604        let shape = RoundShape {
1605            border_radius: this.border_radius,
1606            inner_shape: this.inner_shape.scaled(scale),
1607        };
1608        Some(Box::new(shape) as Box<dyn Shape>)
1609    })
1610);
1611
1612#[cfg(feature = "dim2")]
1613#[cfg(feature = "alloc")]
1614impl_shape_for_round_shape!(
1615    ConvexPolygon,
1616    RoundConvexPolygon,
1617    (|this: &Self, scale: Vector, _num_subdivisions: u32| {
1618        let shape = RoundShape {
1619            border_radius: this.border_radius,
1620            inner_shape: this.inner_shape.clone().scaled(scale)?,
1621        };
1622        Some(Box::new(shape) as Box<dyn Shape>)
1623    })
1624);
1625
1626#[cfg(feature = "dim3")]
1627impl_shape_for_round_shape!(
1628    Cylinder,
1629    RoundCylinder,
1630    (|this: &Self, scale: Vector, num_subdivisions: u32| {
1631        Some(
1632            this.inner_shape
1633                .scaled(scale, num_subdivisions)?
1634                .either::<_, _, Box<dyn Shape>>(
1635                    |inner_shape| {
1636                        Box::new(RoundShape {
1637                            border_radius: this.border_radius,
1638                            inner_shape,
1639                        })
1640                    },
1641                    |inner_shape| {
1642                        Box::new(RoundShape {
1643                            border_radius: this.border_radius,
1644                            inner_shape,
1645                        })
1646                    },
1647                ),
1648        )
1649    })
1650);
1651#[cfg(feature = "dim3")]
1652impl_shape_for_round_shape!(
1653    Cone,
1654    RoundCone,
1655    (|this: &Self, scale: Vector, num_subdivisions: u32| {
1656        Some(
1657            this.inner_shape
1658                .scaled(scale, num_subdivisions)?
1659                .either::<_, _, Box<dyn Shape>>(
1660                    |inner_shape| {
1661                        Box::new(RoundShape {
1662                            border_radius: this.border_radius,
1663                            inner_shape,
1664                        })
1665                    },
1666                    |inner_shape| {
1667                        Box::new(RoundShape {
1668                            border_radius: this.border_radius,
1669                            inner_shape,
1670                        })
1671                    },
1672                ),
1673        )
1674    })
1675);
1676
1677#[cfg(feature = "dim3")]
1678#[cfg(feature = "alloc")]
1679impl_shape_for_round_shape!(
1680    ConvexPolyhedron,
1681    RoundConvexPolyhedron,
1682    (|this: &Self, scale: Vector, _num_subdivisions: u32| {
1683        let shape = RoundShape {
1684            border_radius: this.border_radius,
1685            inner_shape: this.inner_shape.clone().scaled(scale)?,
1686        };
1687        Some(Box::new(shape) as Box<dyn Shape>)
1688    })
1689);