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