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, 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> {
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    fn feature_normal_at_point(&self, _feature: FeatureId, _point: Vector) -> Option<Vector> {
422        None
423    }
424
425    /// Computes the swept [`Aabb`] of this shape, i.e., the space it would occupy by moving from
426    /// the given start position to the given end position.
427    fn compute_swept_aabb(&self, start_pos: &Pose, end_pos: &Pose) -> Aabb {
428        let aabb1 = self.compute_aabb(start_pos);
429        let aabb2 = self.compute_aabb(end_pos);
430        aabb1.merged(&aabb2)
431    }
432}
433
434impl dyn Shape {
435    /// Converts this abstract shape to the given shape, if it is one.
436    pub fn as_shape<T: Shape>(&self) -> Option<&T> {
437        (self as &dyn Any).downcast_ref()
438    }
439    /// Converts this abstract shape to the given mutable shape, if it is one.
440    pub fn as_shape_mut<T: Shape>(&mut self) -> Option<&mut T> {
441        (self as &mut dyn Any).downcast_mut()
442    }
443
444    /// Converts this abstract shape to a ball, if it is one.
445    pub fn as_ball(&self) -> Option<&Ball> {
446        self.as_shape()
447    }
448    /// Converts this abstract shape to a mutable ball, if it is one.
449    pub fn as_ball_mut(&mut self) -> Option<&mut Ball> {
450        self.as_shape_mut()
451    }
452
453    /// Converts this abstract shape to a cuboid, if it is one.
454    pub fn as_cuboid(&self) -> Option<&Cuboid> {
455        self.as_shape()
456    }
457    /// Converts this abstract shape to a mutable cuboid, if it is one.
458    pub fn as_cuboid_mut(&mut self) -> Option<&mut Cuboid> {
459        self.as_shape_mut()
460    }
461
462    /// Converts this abstract shape to a halfspace, if it is one.
463    pub fn as_halfspace(&self) -> Option<&HalfSpace> {
464        self.as_shape()
465    }
466    /// Converts this abstract shape to a halfspace, if it is one.
467    pub fn as_halfspace_mut(&mut self) -> Option<&mut HalfSpace> {
468        self.as_shape_mut()
469    }
470
471    /// Converts this abstract shape to a segment, if it is one.
472    pub fn as_segment(&self) -> Option<&Segment> {
473        self.as_shape()
474    }
475    /// Converts this abstract shape to a mutable segment, if it is one.
476    pub fn as_segment_mut(&mut self) -> Option<&mut Segment> {
477        self.as_shape_mut()
478    }
479
480    /// Converts this abstract shape to a capsule, if it is one.
481    pub fn as_capsule(&self) -> Option<&Capsule> {
482        self.as_shape()
483    }
484    /// Converts this abstract shape to a mutable capsule, if it is one.
485    pub fn as_capsule_mut(&mut self) -> Option<&mut Capsule> {
486        self.as_shape_mut()
487    }
488
489    /// Converts this abstract shape to a triangle, if it is one.
490    pub fn as_triangle(&self) -> Option<&Triangle> {
491        self.as_shape()
492    }
493    /// Converts this abstract shape to a mutable triangle, if it is one.
494    pub fn as_triangle_mut(&mut self) -> Option<&mut Triangle> {
495        self.as_shape_mut()
496    }
497
498    /// Converts this abstract shape to voxels, if it is one.
499    #[cfg(feature = "alloc")]
500    pub fn as_voxels(&self) -> Option<&Voxels> {
501        self.as_shape()
502    }
503    /// Converts this abstract shape to mutable voxels, if it is one.
504    #[cfg(feature = "alloc")]
505    pub fn as_voxels_mut(&mut self) -> Option<&mut Voxels> {
506        self.as_shape_mut()
507    }
508
509    /// Converts this abstract shape to a compound shape, if it is one.
510    #[cfg(feature = "alloc")]
511    pub fn as_compound(&self) -> Option<&Compound> {
512        self.as_shape()
513    }
514    /// Converts this abstract shape to a mutable compound shape, if it is one.
515    #[cfg(feature = "alloc")]
516    pub fn as_compound_mut(&mut self) -> Option<&mut Compound> {
517        self.as_shape_mut()
518    }
519
520    /// Converts this abstract shape to a triangle mesh, if it is one.
521    #[cfg(feature = "alloc")]
522    pub fn as_trimesh(&self) -> Option<&TriMesh> {
523        self.as_shape()
524    }
525    /// Converts this abstract shape to a mutable triangle mesh, if it is one.
526    #[cfg(feature = "alloc")]
527    pub fn as_trimesh_mut(&mut self) -> Option<&mut TriMesh> {
528        self.as_shape_mut()
529    }
530
531    /// Converts this abstract shape to a polyline, if it is one.
532    #[cfg(feature = "alloc")]
533    pub fn as_polyline(&self) -> Option<&Polyline> {
534        self.as_shape()
535    }
536    /// Converts this abstract shape to a mutable polyline, if it is one.
537    #[cfg(feature = "alloc")]
538    pub fn as_polyline_mut(&mut self) -> Option<&mut Polyline> {
539        self.as_shape_mut()
540    }
541
542    /// Converts this abstract shape to a heightfield, if it is one.
543    #[cfg(feature = "alloc")]
544    pub fn as_heightfield(&self) -> Option<&HeightField> {
545        self.as_shape()
546    }
547    /// Converts this abstract shape to a mutable heightfield, if it is one.
548    #[cfg(feature = "alloc")]
549    pub fn as_heightfield_mut(&mut self) -> Option<&mut HeightField> {
550        self.as_shape_mut()
551    }
552
553    /// Converts this abstract shape to a round cuboid, if it is one.
554    pub fn as_round_cuboid(&self) -> Option<&RoundCuboid> {
555        self.as_shape()
556    }
557    /// Converts this abstract shape to a mutable round cuboid, if it is one.
558    pub fn as_round_cuboid_mut(&mut self) -> Option<&mut RoundCuboid> {
559        self.as_shape_mut()
560    }
561
562    /// Converts this abstract shape to a round triangle, if it is one.
563    pub fn as_round_triangle(&self) -> Option<&RoundTriangle> {
564        self.as_shape()
565    }
566    /// Converts this abstract shape to a round triangle, if it is one.
567    pub fn as_round_triangle_mut(&mut self) -> Option<&mut RoundTriangle> {
568        self.as_shape_mut()
569    }
570
571    /// Converts this abstract shape to a convex polygon, if it is one.
572    #[cfg(feature = "dim2")]
573    #[cfg(feature = "alloc")]
574    pub fn as_convex_polygon(&self) -> Option<&ConvexPolygon> {
575        self.as_shape()
576    }
577    /// Converts this abstract shape to a mutable convex polygon, if it is one.
578    #[cfg(feature = "dim2")]
579    #[cfg(feature = "alloc")]
580    pub fn as_convex_polygon_mut(&mut self) -> Option<&mut ConvexPolygon> {
581        self.as_shape_mut()
582    }
583
584    /// Converts this abstract shape to a round convex polygon, if it is one.
585    #[cfg(feature = "dim2")]
586    #[cfg(feature = "alloc")]
587    pub fn as_round_convex_polygon(&self) -> Option<&RoundConvexPolygon> {
588        self.as_shape()
589    }
590    /// Converts this abstract shape to a mutable round convex polygon, if it is one.
591    #[cfg(feature = "dim2")]
592    #[cfg(feature = "alloc")]
593    pub fn as_round_convex_polygon_mut(&mut self) -> Option<&mut RoundConvexPolygon> {
594        self.as_shape_mut()
595    }
596
597    #[cfg(feature = "dim3")]
598    #[cfg(feature = "alloc")]
599    pub fn as_convex_polyhedron(&self) -> Option<&ConvexPolyhedron> {
600        self.as_shape()
601    }
602    #[cfg(feature = "dim3")]
603    #[cfg(feature = "alloc")]
604    pub fn as_convex_polyhedron_mut(&mut self) -> Option<&mut ConvexPolyhedron> {
605        self.as_shape_mut()
606    }
607
608    /// Converts this abstract shape to a cylinder, if it is one.
609    #[cfg(feature = "dim3")]
610    pub fn as_cylinder(&self) -> Option<&Cylinder> {
611        self.as_shape()
612    }
613    /// Converts this abstract shape to a mutable cylinder, if it is one.
614    #[cfg(feature = "dim3")]
615    pub fn as_cylinder_mut(&mut self) -> Option<&mut Cylinder> {
616        self.as_shape_mut()
617    }
618
619    /// Converts this abstract shape to a cone, if it is one.
620    #[cfg(feature = "dim3")]
621    pub fn as_cone(&self) -> Option<&Cone> {
622        self.as_shape()
623    }
624    /// Converts this abstract shape to a mutable cone, if it is one.
625    #[cfg(feature = "dim3")]
626    pub fn as_cone_mut(&mut self) -> Option<&mut Cone> {
627        self.as_shape_mut()
628    }
629
630    /// Converts this abstract shape to a round cylinder, if it is one.
631    #[cfg(feature = "dim3")]
632    pub fn as_round_cylinder(&self) -> Option<&RoundCylinder> {
633        self.as_shape()
634    }
635    /// Converts this abstract shape to a mutable round cylinder, if it is one.
636    #[cfg(feature = "dim3")]
637    pub fn as_round_cylinder_mut(&mut self) -> Option<&mut RoundCylinder> {
638        self.as_shape_mut()
639    }
640
641    /// Converts this abstract shape to a round cone, if it is one.
642    #[cfg(feature = "dim3")]
643    pub fn as_round_cone(&self) -> Option<&RoundCone> {
644        self.as_shape()
645    }
646    /// Converts this abstract shape to a mutable round cone, if it is one.
647    #[cfg(feature = "dim3")]
648    pub fn as_round_cone_mut(&mut self) -> Option<&mut RoundCone> {
649        self.as_shape_mut()
650    }
651
652    /// Converts this abstract shape to a round convex polyhedron, if it is one.
653    #[cfg(feature = "dim3")]
654    #[cfg(feature = "alloc")]
655    pub fn as_round_convex_polyhedron(&self) -> Option<&RoundConvexPolyhedron> {
656        self.as_shape()
657    }
658    /// Converts this abstract shape to a mutable round convex polyhedron, if it is one.
659    #[cfg(feature = "dim3")]
660    #[cfg(feature = "alloc")]
661    pub fn as_round_convex_polyhedron_mut(&mut self) -> Option<&mut RoundConvexPolyhedron> {
662        self.as_shape_mut()
663    }
664}
665
666impl Shape for Ball {
667    #[cfg(feature = "alloc")]
668    fn clone_dyn(&self) -> Box<dyn Shape> {
669        Box::new(*self)
670    }
671
672    #[cfg(feature = "alloc")]
673    fn scale_dyn(&self, scale: Vector, num_subdivisions: u32) -> Option<Box<dyn Shape>> {
674        let scaled = self.scaled(scale, num_subdivisions)?;
675        Some(scaled.either::<_, _, Box<dyn Shape>>(|x| Box::new(x), |x| Box::new(x)))
676    }
677
678    fn compute_local_aabb(&self) -> Aabb {
679        self.local_aabb()
680    }
681
682    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
683        self.local_bounding_sphere()
684    }
685
686    fn compute_aabb(&self, position: &Pose) -> Aabb {
687        self.aabb(position)
688    }
689
690    fn mass_properties(&self, density: Real) -> MassProperties {
691        MassProperties::from_ball(density, self.radius)
692    }
693
694    fn ccd_thickness(&self) -> Real {
695        self.radius
696    }
697
698    fn ccd_angular_thickness(&self) -> Real {
699        Real::pi()
700    }
701
702    fn is_convex(&self) -> bool {
703        true
704    }
705
706    fn shape_type(&self) -> ShapeType {
707        ShapeType::Ball
708    }
709
710    fn as_typed_shape(&self) -> TypedShape<'_> {
711        TypedShape::Ball(self)
712    }
713
714    fn as_support_map(&self) -> Option<&dyn SupportMap> {
715        Some(self as &dyn SupportMap)
716    }
717
718    /// The shape's normal at the given point located on a specific feature.
719    #[inline]
720    fn feature_normal_at_point(&self, _: FeatureId, point: Vector) -> Option<Vector> {
721        (point).try_normalize()
722    }
723}
724
725impl Shape for Cuboid {
726    #[cfg(feature = "alloc")]
727    fn clone_dyn(&self) -> Box<dyn Shape> {
728        Box::new(*self)
729    }
730
731    #[cfg(feature = "alloc")]
732    fn scale_dyn(&self, scale: Vector, _num_subdivisions: u32) -> Option<Box<dyn Shape>> {
733        Some(Box::new(self.scaled(scale)))
734    }
735
736    fn compute_local_aabb(&self) -> Aabb {
737        self.local_aabb()
738    }
739
740    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
741        self.local_bounding_sphere()
742    }
743
744    fn compute_aabb(&self, position: &Pose) -> Aabb {
745        self.aabb(position)
746    }
747
748    fn mass_properties(&self, density: Real) -> MassProperties {
749        MassProperties::from_cuboid(density, self.half_extents)
750    }
751
752    fn is_convex(&self) -> bool {
753        true
754    }
755
756    fn shape_type(&self) -> ShapeType {
757        ShapeType::Cuboid
758    }
759
760    fn as_typed_shape(&self) -> TypedShape<'_> {
761        TypedShape::Cuboid(self)
762    }
763
764    fn ccd_thickness(&self) -> Real {
765        self.half_extents.min_element()
766    }
767
768    fn ccd_angular_thickness(&self) -> Real {
769        Real::frac_pi_2()
770    }
771
772    fn as_support_map(&self) -> Option<&dyn SupportMap> {
773        Some(self as &dyn SupportMap)
774    }
775
776    fn as_polygonal_feature_map(&self) -> Option<(&dyn PolygonalFeatureMap, Real)> {
777        Some((self as &dyn PolygonalFeatureMap, 0.0))
778    }
779
780    fn feature_normal_at_point(&self, feature: FeatureId, _point: Vector) -> Option<Vector> {
781        self.feature_normal(feature)
782    }
783}
784
785impl Shape for Capsule {
786    #[cfg(feature = "alloc")]
787    fn clone_dyn(&self) -> Box<dyn Shape> {
788        Box::new(*self)
789    }
790
791    #[cfg(feature = "alloc")]
792    fn scale_dyn(&self, scale: Vector, num_subdivisions: u32) -> Option<Box<dyn Shape>> {
793        let scaled = self.scaled(scale, num_subdivisions)?;
794        Some(scaled.either::<_, _, Box<dyn Shape>>(|x| Box::new(x), |x| Box::new(x)))
795    }
796
797    fn compute_local_aabb(&self) -> Aabb {
798        self.local_aabb()
799    }
800
801    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
802        self.local_bounding_sphere()
803    }
804
805    fn compute_aabb(&self, position: &Pose) -> Aabb {
806        self.aabb(position)
807    }
808
809    fn mass_properties(&self, density: Real) -> MassProperties {
810        MassProperties::from_capsule(density, self.segment.a, self.segment.b, self.radius)
811    }
812
813    fn is_convex(&self) -> bool {
814        true
815    }
816
817    fn shape_type(&self) -> ShapeType {
818        ShapeType::Capsule
819    }
820
821    fn as_typed_shape(&self) -> TypedShape<'_> {
822        TypedShape::Capsule(self)
823    }
824
825    fn ccd_thickness(&self) -> Real {
826        self.radius
827    }
828
829    fn ccd_angular_thickness(&self) -> Real {
830        Real::frac_pi_2()
831    }
832
833    fn as_support_map(&self) -> Option<&dyn SupportMap> {
834        Some(self as &dyn SupportMap)
835    }
836
837    fn as_polygonal_feature_map(&self) -> Option<(&dyn PolygonalFeatureMap, Real)> {
838        Some((&self.segment as &dyn PolygonalFeatureMap, self.radius))
839    }
840}
841
842impl Shape for Triangle {
843    #[cfg(feature = "alloc")]
844    fn clone_dyn(&self) -> Box<dyn Shape> {
845        Box::new(*self)
846    }
847
848    #[cfg(feature = "alloc")]
849    fn scale_dyn(&self, scale: Vector, _num_subdivisions: u32) -> Option<Box<dyn Shape>> {
850        Some(Box::new(self.scaled(scale)))
851    }
852
853    fn compute_local_aabb(&self) -> Aabb {
854        self.local_aabb()
855    }
856
857    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
858        self.local_bounding_sphere()
859    }
860
861    fn compute_aabb(&self, position: &Pose) -> Aabb {
862        self.aabb(position)
863    }
864
865    fn mass_properties(&self, _density: Real) -> MassProperties {
866        #[cfg(feature = "dim2")]
867        return MassProperties::from_triangle(_density, self.a, self.b, self.c);
868        #[cfg(feature = "dim3")]
869        return MassProperties::zero();
870    }
871
872    fn is_convex(&self) -> bool {
873        true
874    }
875
876    fn shape_type(&self) -> ShapeType {
877        ShapeType::Triangle
878    }
879
880    fn as_typed_shape(&self) -> TypedShape<'_> {
881        TypedShape::Triangle(self)
882    }
883
884    fn ccd_thickness(&self) -> Real {
885        // TODO: in 2D use the smallest height of the triangle.
886        0.0
887    }
888
889    fn ccd_angular_thickness(&self) -> Real {
890        Real::frac_pi_2()
891    }
892
893    fn as_support_map(&self) -> Option<&dyn SupportMap> {
894        Some(self as &dyn SupportMap)
895    }
896
897    fn as_polygonal_feature_map(&self) -> Option<(&dyn PolygonalFeatureMap, Real)> {
898        Some((self as &dyn PolygonalFeatureMap, 0.0))
899    }
900
901    fn feature_normal_at_point(&self, _feature: FeatureId, _point: Vector) -> Option<Vector> {
902        #[cfg(feature = "dim2")]
903        return None;
904        #[cfg(feature = "dim3")]
905        return self.feature_normal(_feature);
906    }
907}
908
909impl Shape for Segment {
910    #[cfg(feature = "alloc")]
911    fn clone_dyn(&self) -> Box<dyn Shape> {
912        Box::new(*self)
913    }
914
915    #[cfg(feature = "alloc")]
916    fn scale_dyn(&self, scale: Vector, _num_subdivisions: u32) -> Option<Box<dyn Shape>> {
917        Some(Box::new(self.scaled(scale)))
918    }
919
920    fn compute_local_aabb(&self) -> Aabb {
921        self.local_aabb()
922    }
923
924    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
925        self.local_bounding_sphere()
926    }
927
928    fn compute_aabb(&self, position: &Pose) -> Aabb {
929        self.aabb(position)
930    }
931
932    fn mass_properties(&self, _density: Real) -> MassProperties {
933        MassProperties::zero()
934    }
935
936    fn is_convex(&self) -> bool {
937        true
938    }
939
940    fn ccd_thickness(&self) -> Real {
941        0.0
942    }
943
944    fn ccd_angular_thickness(&self) -> Real {
945        Real::frac_pi_2()
946    }
947
948    fn shape_type(&self) -> ShapeType {
949        ShapeType::Segment
950    }
951
952    fn as_typed_shape(&self) -> TypedShape<'_> {
953        TypedShape::Segment(self)
954    }
955
956    fn as_support_map(&self) -> Option<&dyn SupportMap> {
957        Some(self as &dyn SupportMap)
958    }
959
960    fn as_polygonal_feature_map(&self) -> Option<(&dyn PolygonalFeatureMap, Real)> {
961        Some((self as &dyn PolygonalFeatureMap, 0.0))
962    }
963
964    fn feature_normal_at_point(&self, feature: FeatureId, _point: Vector) -> Option<Vector> {
965        self.feature_normal(feature)
966    }
967}
968
969#[cfg(feature = "alloc")]
970impl Shape for Compound {
971    fn clone_dyn(&self) -> Box<dyn Shape> {
972        Box::new(self.clone())
973    }
974
975    fn scale_dyn(&self, scale: Vector, num_subdivisions: u32) -> Option<Box<dyn Shape>> {
976        use super::SharedShape;
977
978        let scaled: Vec<_> = self
979            .shapes()
980            .iter()
981            .map(|(pos, shape)| {
982                let scaled_shape = shape.scale_dyn(scale, num_subdivisions)?;
983                Some((
984                    Pose::from_parts(pos.translation * scale, pos.rotation),
985                    SharedShape(scaled_shape.into()),
986                ))
987            })
988            .collect::<Option<Vec<_>>>()?;
989        Some(Box::new(Compound::new(scaled)))
990    }
991
992    fn compute_local_aabb(&self) -> Aabb {
993        *self.local_aabb()
994    }
995
996    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
997        self.local_bounding_sphere()
998    }
999
1000    fn compute_aabb(&self, position: &Pose) -> Aabb {
1001        self.local_aabb().transform_by(position)
1002    }
1003
1004    fn mass_properties(&self, density: Real) -> MassProperties {
1005        MassProperties::from_compound(density, self.shapes())
1006    }
1007
1008    fn shape_type(&self) -> ShapeType {
1009        ShapeType::Compound
1010    }
1011
1012    fn as_typed_shape(&self) -> TypedShape<'_> {
1013        TypedShape::Compound(self)
1014    }
1015
1016    fn ccd_thickness(&self) -> Real {
1017        self.shapes()
1018            .iter()
1019            .fold(Real::MAX, |curr, (_, s)| curr.min(s.ccd_thickness()))
1020    }
1021
1022    fn ccd_angular_thickness(&self) -> Real {
1023        self.shapes().iter().fold(Real::MAX, |curr, (_, s)| {
1024            curr.max(s.ccd_angular_thickness())
1025        })
1026    }
1027
1028    #[cfg(feature = "alloc")]
1029    fn as_composite_shape(&self) -> Option<&dyn CompositeShape> {
1030        Some(self as &dyn CompositeShape)
1031    }
1032}
1033
1034#[cfg(feature = "alloc")]
1035impl Shape for Polyline {
1036    fn clone_dyn(&self) -> Box<dyn Shape> {
1037        Box::new(self.clone())
1038    }
1039
1040    fn scale_dyn(&self, scale: Vector, _num_subdivisions: u32) -> Option<Box<dyn Shape>> {
1041        Some(Box::new(self.clone().scaled(scale)))
1042    }
1043
1044    fn compute_local_aabb(&self) -> Aabb {
1045        self.local_aabb()
1046    }
1047
1048    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
1049        self.local_bounding_sphere()
1050    }
1051
1052    fn compute_aabb(&self, position: &Pose) -> Aabb {
1053        self.aabb(position)
1054    }
1055
1056    fn mass_properties(&self, _density: Real) -> MassProperties {
1057        MassProperties::zero()
1058    }
1059
1060    fn shape_type(&self) -> ShapeType {
1061        ShapeType::Polyline
1062    }
1063
1064    fn as_typed_shape(&self) -> TypedShape<'_> {
1065        TypedShape::Polyline(self)
1066    }
1067
1068    fn ccd_thickness(&self) -> Real {
1069        0.0
1070    }
1071
1072    fn ccd_angular_thickness(&self) -> Real {
1073        // TODO: the value should depend on the angles between
1074        // adjacent segments of the polyline.
1075        Real::frac_pi_4()
1076    }
1077
1078    #[cfg(feature = "alloc")]
1079    fn as_composite_shape(&self) -> Option<&dyn CompositeShape> {
1080        Some(self as &dyn CompositeShape)
1081    }
1082}
1083
1084#[cfg(feature = "alloc")]
1085impl Shape for TriMesh {
1086    fn clone_dyn(&self) -> Box<dyn Shape> {
1087        Box::new(self.clone())
1088    }
1089
1090    fn scale_dyn(&self, scale: Vector, _num_subdivisions: u32) -> Option<Box<dyn Shape>> {
1091        Some(Box::new(self.clone().scaled(scale)))
1092    }
1093
1094    fn compute_local_aabb(&self) -> Aabb {
1095        self.local_aabb()
1096    }
1097
1098    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
1099        self.local_bounding_sphere()
1100    }
1101
1102    fn compute_aabb(&self, position: &Pose) -> Aabb {
1103        self.aabb(position)
1104    }
1105
1106    fn mass_properties(&self, density: Real) -> MassProperties {
1107        MassProperties::from_trimesh(density, self.vertices(), self.indices())
1108    }
1109
1110    fn shape_type(&self) -> ShapeType {
1111        ShapeType::TriMesh
1112    }
1113
1114    fn as_typed_shape(&self) -> TypedShape<'_> {
1115        TypedShape::TriMesh(self)
1116    }
1117
1118    fn ccd_thickness(&self) -> Real {
1119        // TODO: in 2D, return the smallest CCD thickness among triangles?
1120        0.0
1121    }
1122
1123    fn ccd_angular_thickness(&self) -> Real {
1124        // TODO: the value should depend on the angles between
1125        // adjacent triangles of the trimesh.
1126        Real::frac_pi_4()
1127    }
1128
1129    /// Gets the normal of the triangle represented by `feature`.
1130    fn feature_normal_at_point(&self, _feature: FeatureId, _point: Vector) -> Option<Vector> {
1131        #[cfg(feature = "dim2")]
1132        return None;
1133        #[cfg(feature = "dim3")]
1134        return self.feature_normal(_feature);
1135    }
1136
1137    #[cfg(feature = "alloc")]
1138    fn as_composite_shape(&self) -> Option<&dyn CompositeShape> {
1139        Some(self as &dyn CompositeShape)
1140    }
1141}
1142
1143#[cfg(feature = "alloc")]
1144impl Shape for HeightField {
1145    fn clone_dyn(&self) -> Box<dyn Shape> {
1146        Box::new(self.clone())
1147    }
1148
1149    fn scale_dyn(&self, scale: Vector, _num_subdivisions: u32) -> Option<Box<dyn Shape>> {
1150        Some(Box::new(self.clone().scaled(scale)))
1151    }
1152
1153    fn compute_local_aabb(&self) -> Aabb {
1154        self.local_aabb()
1155    }
1156
1157    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
1158        self.local_bounding_sphere()
1159    }
1160
1161    fn compute_aabb(&self, position: &Pose) -> Aabb {
1162        self.aabb(position)
1163    }
1164
1165    fn mass_properties(&self, _density: Real) -> MassProperties {
1166        MassProperties::zero()
1167    }
1168
1169    fn shape_type(&self) -> ShapeType {
1170        ShapeType::HeightField
1171    }
1172
1173    fn as_typed_shape(&self) -> TypedShape<'_> {
1174        TypedShape::HeightField(self)
1175    }
1176
1177    fn ccd_thickness(&self) -> Real {
1178        0.0
1179    }
1180
1181    fn ccd_angular_thickness(&self) -> Real {
1182        // TODO: the value should depend on the angles between
1183        // adjacent triangles of the heightfield.
1184        Real::frac_pi_4()
1185    }
1186}
1187
1188#[cfg(feature = "dim2")]
1189#[cfg(feature = "alloc")]
1190impl Shape for ConvexPolygon {
1191    fn clone_dyn(&self) -> Box<dyn Shape> {
1192        Box::new(self.clone())
1193    }
1194
1195    fn scale_dyn(&self, scale: Vector, _num_subdivisions: u32) -> Option<Box<dyn Shape>> {
1196        Some(Box::new(self.clone().scaled(scale)?))
1197    }
1198
1199    fn compute_local_aabb(&self) -> Aabb {
1200        self.local_aabb()
1201    }
1202
1203    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
1204        self.local_bounding_sphere()
1205    }
1206
1207    fn compute_aabb(&self, position: &Pose) -> Aabb {
1208        self.aabb(position)
1209    }
1210
1211    fn mass_properties(&self, density: Real) -> MassProperties {
1212        MassProperties::from_convex_polygon(density, self.points())
1213    }
1214
1215    fn is_convex(&self) -> bool {
1216        true
1217    }
1218
1219    fn shape_type(&self) -> ShapeType {
1220        ShapeType::ConvexPolygon
1221    }
1222
1223    fn as_typed_shape(&self) -> TypedShape<'_> {
1224        TypedShape::ConvexPolygon(self)
1225    }
1226
1227    fn ccd_thickness(&self) -> Real {
1228        // TODO: we should use the OBB instead.
1229        self.compute_local_aabb().half_extents().min_element()
1230    }
1231
1232    fn ccd_angular_thickness(&self) -> Real {
1233        // TODO: the value should depend on the angles between
1234        // adjacent segments of the convex polygon.
1235        Real::frac_pi_4()
1236    }
1237
1238    fn as_support_map(&self) -> Option<&dyn SupportMap> {
1239        Some(self as &dyn SupportMap)
1240    }
1241
1242    fn as_polygonal_feature_map(&self) -> Option<(&dyn PolygonalFeatureMap, Real)> {
1243        Some((self as &dyn PolygonalFeatureMap, 0.0))
1244    }
1245
1246    fn feature_normal_at_point(&self, feature: FeatureId, _point: Vector) -> Option<Vector> {
1247        self.feature_normal(feature)
1248    }
1249}
1250
1251#[cfg(feature = "dim3")]
1252#[cfg(feature = "alloc")]
1253impl Shape for ConvexPolyhedron {
1254    fn clone_dyn(&self) -> Box<dyn Shape> {
1255        Box::new(self.clone())
1256    }
1257
1258    fn scale_dyn(&self, scale: Vector, _num_subdivisions: u32) -> Option<Box<dyn Shape>> {
1259        Some(Box::new(self.clone().scaled(scale)?))
1260    }
1261
1262    fn compute_local_aabb(&self) -> Aabb {
1263        self.local_aabb()
1264    }
1265
1266    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
1267        self.local_bounding_sphere()
1268    }
1269
1270    fn compute_aabb(&self, position: &Pose) -> Aabb {
1271        self.aabb(position)
1272    }
1273
1274    fn mass_properties(&self, density: Real) -> MassProperties {
1275        let (vertices, indices) = self.to_trimesh();
1276        MassProperties::from_convex_polyhedron(density, &vertices, &indices)
1277    }
1278
1279    fn is_convex(&self) -> bool {
1280        true
1281    }
1282
1283    fn shape_type(&self) -> ShapeType {
1284        ShapeType::ConvexPolyhedron
1285    }
1286
1287    fn as_typed_shape(&self) -> TypedShape<'_> {
1288        TypedShape::ConvexPolyhedron(self)
1289    }
1290
1291    fn ccd_thickness(&self) -> Real {
1292        // TODO: we should use the OBB instead.
1293        self.compute_local_aabb().half_extents().min_element()
1294    }
1295
1296    fn ccd_angular_thickness(&self) -> Real {
1297        // TODO: the value should depend on the angles between
1298        // adjacent segments of the convex polyhedron.
1299        Real::frac_pi_4()
1300    }
1301
1302    fn as_support_map(&self) -> Option<&dyn SupportMap> {
1303        Some(self as &dyn SupportMap)
1304    }
1305
1306    fn as_polygonal_feature_map(&self) -> Option<(&dyn PolygonalFeatureMap, Real)> {
1307        Some((self as &dyn PolygonalFeatureMap, 0.0))
1308    }
1309
1310    fn feature_normal_at_point(&self, feature: FeatureId, _point: Vector) -> Option<Vector> {
1311        self.feature_normal(feature)
1312    }
1313}
1314
1315#[cfg(feature = "dim3")]
1316impl Shape for Cylinder {
1317    #[cfg(feature = "alloc")]
1318    fn clone_dyn(&self) -> Box<dyn Shape> {
1319        Box::new(*self)
1320    }
1321
1322    #[cfg(feature = "alloc")]
1323    fn scale_dyn(&self, scale: Vector, num_subdivisions: u32) -> Option<Box<dyn Shape>> {
1324        let scaled = self.scaled(scale, num_subdivisions)?;
1325        Some(scaled.either::<_, _, Box<dyn Shape>>(|x| Box::new(x), |x| Box::new(x)))
1326    }
1327
1328    fn compute_local_aabb(&self) -> Aabb {
1329        self.local_aabb()
1330    }
1331
1332    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
1333        self.local_bounding_sphere()
1334    }
1335
1336    fn compute_aabb(&self, position: &Pose) -> Aabb {
1337        self.aabb(position)
1338    }
1339
1340    fn mass_properties(&self, density: Real) -> MassProperties {
1341        MassProperties::from_cylinder(density, self.half_height, self.radius)
1342    }
1343
1344    fn is_convex(&self) -> bool {
1345        true
1346    }
1347
1348    fn shape_type(&self) -> ShapeType {
1349        ShapeType::Cylinder
1350    }
1351
1352    fn as_typed_shape(&self) -> TypedShape<'_> {
1353        TypedShape::Cylinder(self)
1354    }
1355
1356    fn ccd_thickness(&self) -> Real {
1357        self.radius
1358    }
1359
1360    fn ccd_angular_thickness(&self) -> Real {
1361        Real::frac_pi_2()
1362    }
1363
1364    fn as_support_map(&self) -> Option<&dyn SupportMap> {
1365        Some(self as &dyn SupportMap)
1366    }
1367
1368    fn as_polygonal_feature_map(&self) -> Option<(&dyn PolygonalFeatureMap, Real)> {
1369        Some((self as &dyn PolygonalFeatureMap, 0.0))
1370    }
1371}
1372
1373#[cfg(feature = "dim3")]
1374impl Shape for Cone {
1375    #[cfg(feature = "alloc")]
1376    fn clone_dyn(&self) -> Box<dyn Shape> {
1377        Box::new(*self)
1378    }
1379
1380    #[cfg(feature = "alloc")]
1381    fn scale_dyn(&self, scale: Vector, num_subdivisions: u32) -> Option<Box<dyn Shape>> {
1382        let scaled = self.scaled(scale, num_subdivisions)?;
1383        Some(scaled.either::<_, _, Box<dyn Shape>>(|x| Box::new(x), |x| Box::new(x)))
1384    }
1385
1386    fn compute_local_aabb(&self) -> Aabb {
1387        self.local_aabb()
1388    }
1389
1390    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
1391        self.local_bounding_sphere()
1392    }
1393
1394    fn compute_aabb(&self, position: &Pose) -> Aabb {
1395        self.aabb(position)
1396    }
1397
1398    fn mass_properties(&self, density: Real) -> MassProperties {
1399        MassProperties::from_cone(density, self.half_height, self.radius)
1400    }
1401
1402    fn is_convex(&self) -> bool {
1403        true
1404    }
1405
1406    fn shape_type(&self) -> ShapeType {
1407        ShapeType::Cone
1408    }
1409
1410    fn as_typed_shape(&self) -> TypedShape<'_> {
1411        TypedShape::Cone(self)
1412    }
1413
1414    fn ccd_thickness(&self) -> Real {
1415        self.radius
1416    }
1417
1418    fn ccd_angular_thickness(&self) -> Real {
1419        let apex_half_angle = RealField::atan2(self.radius, self.half_height);
1420        assert!(apex_half_angle >= 0.0);
1421        let basis_angle = Real::frac_pi_2() - apex_half_angle;
1422        basis_angle.min(apex_half_angle * 2.0)
1423    }
1424
1425    fn as_support_map(&self) -> Option<&dyn SupportMap> {
1426        Some(self as &dyn SupportMap)
1427    }
1428
1429    fn as_polygonal_feature_map(&self) -> Option<(&dyn PolygonalFeatureMap, Real)> {
1430        Some((self as &dyn PolygonalFeatureMap, 0.0))
1431    }
1432}
1433
1434impl Shape for HalfSpace {
1435    #[cfg(feature = "alloc")]
1436    fn clone_dyn(&self) -> Box<dyn Shape> {
1437        Box::new(*self)
1438    }
1439
1440    #[cfg(feature = "alloc")]
1441    fn scale_dyn(&self, scale: Vector, _num_subdivisions: u32) -> Option<Box<dyn Shape>> {
1442        Some(Box::new(self.scaled(scale)?))
1443    }
1444
1445    fn compute_local_aabb(&self) -> Aabb {
1446        self.local_aabb()
1447    }
1448
1449    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
1450        self.local_bounding_sphere()
1451    }
1452
1453    fn compute_aabb(&self, position: &Pose) -> Aabb {
1454        self.aabb(position)
1455    }
1456
1457    fn is_convex(&self) -> bool {
1458        true
1459    }
1460
1461    fn ccd_thickness(&self) -> Real {
1462        #[cfg_attr(feature = "f32", expect(clippy::unnecessary_cast))]
1463        let result = f32::MAX as Real;
1464        result
1465    }
1466
1467    fn ccd_angular_thickness(&self) -> Real {
1468        Real::pi()
1469    }
1470
1471    fn mass_properties(&self, _: Real) -> MassProperties {
1472        MassProperties::zero()
1473    }
1474
1475    fn shape_type(&self) -> ShapeType {
1476        ShapeType::HalfSpace
1477    }
1478
1479    fn as_typed_shape(&self) -> TypedShape<'_> {
1480        TypedShape::HalfSpace(self)
1481    }
1482}
1483
1484#[cfg(feature = "alloc")]
1485impl Shape for Voxels {
1486    fn compute_local_aabb(&self) -> Aabb {
1487        self.local_aabb()
1488    }
1489
1490    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
1491        self.local_bounding_sphere()
1492    }
1493
1494    fn clone_dyn(&self) -> Box<dyn Shape> {
1495        Box::new(self.clone())
1496    }
1497
1498    fn scale_dyn(&self, scale: Vector, _num_subdivisions: u32) -> Option<Box<dyn Shape>> {
1499        Some(Box::new(self.clone().scaled(scale)))
1500    }
1501
1502    fn mass_properties(&self, density: Real) -> MassProperties {
1503        MassProperties::from_voxels(density, self)
1504    }
1505
1506    fn shape_type(&self) -> ShapeType {
1507        ShapeType::Voxels
1508    }
1509
1510    fn as_typed_shape(&self) -> TypedShape<'_> {
1511        TypedShape::Voxels(self)
1512    }
1513
1514    fn ccd_thickness(&self) -> Real {
1515        self.voxel_size().min_element()
1516    }
1517
1518    fn ccd_angular_thickness(&self) -> Real {
1519        Real::frac_pi_2()
1520    }
1521}
1522
1523macro_rules! impl_shape_for_round_shape(
1524    ($S: ty, $Tag: ident, $t: tt) => {
1525        impl Shape for RoundShape<$S> {
1526            #[cfg(feature = "alloc")]
1527            fn clone_dyn(&self) -> Box<dyn Shape> {
1528                Box::new(self.clone())
1529            }
1530
1531            #[cfg(feature = "alloc")]
1532            fn scale_dyn(&self, scale: Vector, num_subdivisions: u32) -> Option<Box<dyn Shape>> {
1533                $t(self, scale, num_subdivisions)
1534            }
1535
1536            fn compute_local_aabb(&self) -> Aabb {
1537                self.inner_shape.local_aabb().loosened(self.border_radius)
1538            }
1539
1540            fn compute_local_bounding_sphere(&self) -> BoundingSphere {
1541                self.inner_shape.local_bounding_sphere().loosened(self.border_radius)
1542            }
1543
1544            fn compute_aabb(&self, position: &Pose) -> Aabb {
1545                self.inner_shape.aabb(position).loosened(self.border_radius)
1546            }
1547
1548            fn mass_properties(&self, density: Real) -> MassProperties {
1549                self.inner_shape.mass_properties(density)
1550            }
1551
1552            fn is_convex(&self) -> bool {
1553                self.inner_shape.is_convex()
1554            }
1555
1556            fn shape_type(&self) -> ShapeType {
1557                ShapeType::$Tag
1558            }
1559
1560            fn as_typed_shape(&self) -> TypedShape<'_> {
1561                TypedShape::$Tag(self)
1562            }
1563
1564            fn ccd_thickness(&self) -> Real {
1565                self.inner_shape.ccd_thickness() + self.border_radius
1566            }
1567
1568            fn ccd_angular_thickness(&self) -> Real {
1569                // The fact that the shape is round doesn't change anything
1570                // to the CCD angular thickness.
1571                self.inner_shape.ccd_angular_thickness()
1572            }
1573
1574            fn as_support_map(&self) -> Option<&dyn SupportMap> {
1575                Some(self as &dyn SupportMap)
1576            }
1577
1578            fn as_polygonal_feature_map(&self) -> Option<(&dyn PolygonalFeatureMap, Real)> {
1579                Some((&self.inner_shape as &dyn PolygonalFeatureMap, self.border_radius))
1580            }
1581        }
1582    }
1583);
1584
1585impl_shape_for_round_shape!(
1586    Cuboid,
1587    RoundCuboid,
1588    (|this: &Self, scale: Vector, _num_subdivisions: u32| {
1589        let shape = RoundShape {
1590            border_radius: this.border_radius,
1591            inner_shape: this.inner_shape.scaled(scale),
1592        };
1593        Some(Box::new(shape) as Box<dyn Shape>)
1594    })
1595);
1596
1597impl_shape_for_round_shape!(
1598    Triangle,
1599    RoundTriangle,
1600    (|this: &Self, scale: Vector, _num_subdivisions: u32| {
1601        let shape = RoundShape {
1602            border_radius: this.border_radius,
1603            inner_shape: this.inner_shape.scaled(scale),
1604        };
1605        Some(Box::new(shape) as Box<dyn Shape>)
1606    })
1607);
1608
1609#[cfg(feature = "dim2")]
1610#[cfg(feature = "alloc")]
1611impl_shape_for_round_shape!(
1612    ConvexPolygon,
1613    RoundConvexPolygon,
1614    (|this: &Self, scale: Vector, _num_subdivisions: u32| {
1615        let shape = RoundShape {
1616            border_radius: this.border_radius,
1617            inner_shape: this.inner_shape.clone().scaled(scale)?,
1618        };
1619        Some(Box::new(shape) as Box<dyn Shape>)
1620    })
1621);
1622
1623#[cfg(feature = "dim3")]
1624impl_shape_for_round_shape!(
1625    Cylinder,
1626    RoundCylinder,
1627    (|this: &Self, scale: Vector, num_subdivisions: u32| {
1628        Some(
1629            this.inner_shape
1630                .scaled(scale, num_subdivisions)?
1631                .either::<_, _, Box<dyn Shape>>(
1632                    |inner_shape| {
1633                        Box::new(RoundShape {
1634                            border_radius: this.border_radius,
1635                            inner_shape,
1636                        })
1637                    },
1638                    |inner_shape| {
1639                        Box::new(RoundShape {
1640                            border_radius: this.border_radius,
1641                            inner_shape,
1642                        })
1643                    },
1644                ),
1645        )
1646    })
1647);
1648#[cfg(feature = "dim3")]
1649impl_shape_for_round_shape!(
1650    Cone,
1651    RoundCone,
1652    (|this: &Self, scale: Vector, num_subdivisions: u32| {
1653        Some(
1654            this.inner_shape
1655                .scaled(scale, num_subdivisions)?
1656                .either::<_, _, Box<dyn Shape>>(
1657                    |inner_shape| {
1658                        Box::new(RoundShape {
1659                            border_radius: this.border_radius,
1660                            inner_shape,
1661                        })
1662                    },
1663                    |inner_shape| {
1664                        Box::new(RoundShape {
1665                            border_radius: this.border_radius,
1666                            inner_shape,
1667                        })
1668                    },
1669                ),
1670        )
1671    })
1672);
1673
1674#[cfg(feature = "dim3")]
1675#[cfg(feature = "alloc")]
1676impl_shape_for_round_shape!(
1677    ConvexPolyhedron,
1678    RoundConvexPolyhedron,
1679    (|this: &Self, scale: Vector, _num_subdivisions: u32| {
1680        let shape = RoundShape {
1681            border_radius: this.border_radius,
1682            inner_shape: this.inner_shape.clone().scaled(scale)?,
1683        };
1684        Some(Box::new(shape) as Box<dyn Shape>)
1685    })
1686);