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