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