Skip to main content

parry2d/shape/
shape.rs

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