parry3d/shape/
shape.rs

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