bevy_rapier3d/geometry/shape_views/
collider_view.rs

1use std::fmt;
2
3use super::*;
4use crate::math::Vect;
5use rapier::geometry::{RoundShape, SharedShape};
6use rapier::parry::either::Either;
7use rapier::parry::shape::TypedShape;
8
9#[cfg(doc)]
10use rapier::parry;
11
12/// Read-only access to the properties of a collider.
13#[derive(Copy, Clone)]
14pub enum ColliderView<'a> {
15    /// A ball shape.
16    Ball(BallView<'a>),
17    /// A cuboid shape.
18    Cuboid(CuboidView<'a>),
19    /// A capsule shape.
20    Capsule(CapsuleView<'a>),
21    /// A segment shape.
22    Segment(SegmentView<'a>),
23    /// A triangle shape.
24    Triangle(TriangleView<'a>),
25    /// A Voxels shape.
26    Voxels(VoxelsView<'a>),
27    /// A triangle mesh shape.
28    TriMesh(TriMeshView<'a>),
29    /// A set of segments.
30    Polyline(PolylineView<'a>),
31    /// A shape representing a full half-space.
32    HalfSpace(HalfSpaceView<'a>),
33    /// A heightfield shape.
34    HeightField(HeightFieldView<'a>),
35    /// A Compound shape.
36    Compound(CompoundView<'a>),
37    /// A convex polygon.
38    #[cfg(feature = "dim2")]
39    ConvexPolygon(ConvexPolygonView<'a>),
40    /// A convex polyhedron.
41    #[cfg(feature = "dim3")]
42    ConvexPolyhedron(ConvexPolyhedronView<'a>),
43    #[cfg(feature = "dim3")]
44    /// A cylindrical shape.
45    Cylinder(CylinderView<'a>),
46    #[cfg(feature = "dim3")]
47    /// A cone shape.
48    Cone(ConeView<'a>),
49    /// A cuboid with rounded corners.
50    RoundCuboid(RoundCuboidView<'a>),
51    /// A triangle with rounded corners.
52    RoundTriangle(RoundTriangleView<'a>),
53    // /// A triangle-mesh with rounded corners.
54    // RoundedTriMesh,
55    // /// An heightfield with rounded corners.
56    // RoundedHeightField,
57    /// A cylinder with rounded corners.
58    #[cfg(feature = "dim3")]
59    RoundCylinder(RoundCylinderView<'a>),
60    /// A cone with rounded corners.
61    #[cfg(feature = "dim3")]
62    RoundCone(RoundConeView<'a>),
63    /// A convex polyhedron with rounded corners.
64    #[cfg(feature = "dim3")]
65    RoundConvexPolyhedron(RoundConvexPolyhedronView<'a>),
66    /// A convex polygon with rounded corners.
67    #[cfg(feature = "dim2")]
68    RoundConvexPolygon(RoundConvexPolygonView<'a>),
69}
70impl fmt::Debug for ColliderView<'_> {
71    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72        match self {
73            ColliderView::Ball(view) => write!(f, "{:?}", view.raw),
74            ColliderView::Cuboid(view) => write!(f, "{:?}", view.raw),
75            ColliderView::Capsule(view) => write!(f, "{:?}", view.raw),
76            ColliderView::Segment(view) => write!(f, "{:?}", view.raw),
77            ColliderView::Triangle(view) => write!(f, "{:?}", view.raw),
78            ColliderView::Voxels(view) => write!(f, "{:?}", view.raw),
79            ColliderView::TriMesh(_) => write!(f, "Trimesh (not representable)"),
80            ColliderView::Polyline(_) => write!(f, "Polyline (not representable)"),
81            ColliderView::HalfSpace(view) => write!(f, "{:?}", view.raw),
82            ColliderView::HeightField(view) => write!(f, "{:?}", view.raw),
83            ColliderView::Compound(_) => write!(f, "Compound (not representable)"),
84            #[cfg(feature = "dim2")]
85            ColliderView::ConvexPolygon(view) => write!(f, "{:?}", view.raw),
86            #[cfg(feature = "dim3")]
87            ColliderView::ConvexPolyhedron(view) => write!(f, "{:?}", view.raw),
88            #[cfg(feature = "dim3")]
89            ColliderView::Cylinder(view) => write!(f, "{:?}", view.raw),
90            #[cfg(feature = "dim3")]
91            ColliderView::Cone(view) => write!(f, "{:?}", view.raw),
92            ColliderView::RoundCuboid(view) => write!(f, "{:?}", view.raw),
93            ColliderView::RoundTriangle(view) => write!(f, "{:?}", view.raw),
94            #[cfg(feature = "dim3")]
95            ColliderView::RoundCylinder(view) => write!(f, "{:?}", view.raw),
96            #[cfg(feature = "dim3")]
97            ColliderView::RoundCone(view) => write!(f, "{:?}", view.raw),
98            #[cfg(feature = "dim3")]
99            ColliderView::RoundConvexPolyhedron(view) => write!(f, "{:?}", view.raw),
100            #[cfg(feature = "dim2")]
101            ColliderView::RoundConvexPolygon(view) => write!(f, "{:?}", view.raw),
102        }
103    }
104}
105
106impl<'a> From<TypedShape<'a>> for ColliderView<'a> {
107    fn from(typed_shape: TypedShape<'a>) -> ColliderView<'a> {
108        match typed_shape {
109            TypedShape::Ball(s) => ColliderView::Ball(BallView { raw: s }),
110            TypedShape::Cuboid(s) => ColliderView::Cuboid(CuboidView { raw: s }),
111            TypedShape::Capsule(s) => ColliderView::Capsule(CapsuleView { raw: s }),
112            TypedShape::Segment(s) => ColliderView::Segment(SegmentView { raw: s }),
113            TypedShape::Triangle(s) => ColliderView::Triangle(TriangleView { raw: s }),
114            TypedShape::Voxels(s) => ColliderView::Voxels(VoxelsView { raw: s }),
115            TypedShape::TriMesh(s) => ColliderView::TriMesh(TriMeshView { raw: s }),
116            TypedShape::Polyline(s) => ColliderView::Polyline(PolylineView { raw: s }),
117            TypedShape::HalfSpace(s) => ColliderView::HalfSpace(HalfSpaceView { raw: s }),
118            TypedShape::HeightField(s) => ColliderView::HeightField(HeightFieldView { raw: s }),
119            TypedShape::Compound(s) => ColliderView::Compound(CompoundView { raw: s }),
120            #[cfg(feature = "dim2")]
121            TypedShape::ConvexPolygon(s) => {
122                ColliderView::ConvexPolygon(ConvexPolygonView { raw: s })
123            }
124            #[cfg(feature = "dim3")]
125            TypedShape::ConvexPolyhedron(s) => {
126                ColliderView::ConvexPolyhedron(ConvexPolyhedronView { raw: s })
127            }
128            #[cfg(feature = "dim3")]
129            TypedShape::Cylinder(s) => ColliderView::Cylinder(CylinderView { raw: s }),
130            #[cfg(feature = "dim3")]
131            TypedShape::Cone(s) => ColliderView::Cone(ConeView { raw: s }),
132            TypedShape::RoundCuboid(s) => ColliderView::RoundCuboid(RoundCuboidView { raw: s }),
133            TypedShape::RoundTriangle(s) => {
134                ColliderView::RoundTriangle(RoundTriangleView { raw: s })
135            }
136            #[cfg(feature = "dim2")]
137            TypedShape::RoundConvexPolygon(s) => {
138                ColliderView::RoundConvexPolygon(RoundConvexPolygonView { raw: s })
139            }
140            #[cfg(feature = "dim3")]
141            TypedShape::RoundCylinder(s) => {
142                ColliderView::RoundCylinder(RoundCylinderView { raw: s })
143            }
144            #[cfg(feature = "dim3")]
145            TypedShape::RoundCone(s) => ColliderView::RoundCone(RoundConeView { raw: s }),
146            #[cfg(feature = "dim3")]
147            TypedShape::RoundConvexPolyhedron(s) => {
148                ColliderView::RoundConvexPolyhedron(RoundConvexPolyhedronView { raw: s })
149            }
150            TypedShape::Custom(_) => todo!(),
151        }
152    }
153}
154
155impl<'a> From<ColliderView<'a>> for TypedShape<'a> {
156    fn from(collider_view: ColliderView<'a>) -> TypedShape<'a> {
157        collider_view.as_typed_shape()
158    }
159}
160
161impl<'a> From<ColliderView<'a>> for SharedShape {
162    fn from(collider_view: ColliderView<'a>) -> SharedShape {
163        collider_view.to_shared_shape()
164    }
165}
166
167impl<'a> ColliderView<'a> {
168    /// Convert to [`parry::shape::TypedShape`].
169    pub fn as_typed_shape(self) -> TypedShape<'a> {
170        match self {
171            ColliderView::Ball(BallView { raw: s }) => TypedShape::Ball(s),
172            ColliderView::Cuboid(CuboidView { raw: s }) => TypedShape::Cuboid(s),
173            ColliderView::Capsule(CapsuleView { raw: s }) => TypedShape::Capsule(s),
174            ColliderView::Segment(SegmentView { raw: s }) => TypedShape::Segment(s),
175            ColliderView::Triangle(TriangleView { raw: s }) => TypedShape::Triangle(s),
176            ColliderView::Voxels(VoxelsView { raw: s }) => TypedShape::Voxels(s),
177            ColliderView::TriMesh(TriMeshView { raw: s }) => TypedShape::TriMesh(s),
178            ColliderView::Polyline(PolylineView { raw: s }) => TypedShape::Polyline(s),
179            ColliderView::HalfSpace(HalfSpaceView { raw: s }) => TypedShape::HalfSpace(s),
180            ColliderView::HeightField(HeightFieldView { raw: s }) => TypedShape::HeightField(s),
181            ColliderView::Compound(CompoundView { raw: s }) => TypedShape::Compound(s),
182            #[cfg(feature = "dim2")]
183            ColliderView::ConvexPolygon(ConvexPolygonView { raw: s }) => {
184                TypedShape::ConvexPolygon(s)
185            }
186            #[cfg(feature = "dim3")]
187            ColliderView::ConvexPolyhedron(ConvexPolyhedronView { raw: s }) => {
188                TypedShape::ConvexPolyhedron(s)
189            }
190            #[cfg(feature = "dim3")]
191            ColliderView::Cylinder(CylinderView { raw: s }) => TypedShape::Cylinder(s),
192            #[cfg(feature = "dim3")]
193            ColliderView::Cone(ConeView { raw: s }) => TypedShape::Cone(s),
194            ColliderView::RoundCuboid(RoundCuboidView { raw: s }) => TypedShape::RoundCuboid(s),
195            ColliderView::RoundTriangle(RoundTriangleView { raw: s }) => {
196                TypedShape::RoundTriangle(s)
197            }
198            #[cfg(feature = "dim2")]
199            ColliderView::RoundConvexPolygon(RoundConvexPolygonView { raw: s }) => {
200                TypedShape::RoundConvexPolygon(s)
201            }
202            #[cfg(feature = "dim3")]
203            ColliderView::RoundCylinder(RoundCylinderView { raw: s }) => {
204                TypedShape::RoundCylinder(s)
205            }
206            #[cfg(feature = "dim3")]
207            ColliderView::RoundCone(RoundConeView { raw: s }) => TypedShape::RoundCone(s),
208            #[cfg(feature = "dim3")]
209            ColliderView::RoundConvexPolyhedron(RoundConvexPolyhedronView { raw: s }) => {
210                TypedShape::RoundConvexPolyhedron(s)
211            }
212        }
213    }
214
215    /// Convert to [`parry::shape::SharedShape`].
216    pub fn to_shared_shape(self) -> SharedShape {
217        match self {
218            ColliderView::Ball(BallView { raw }) => SharedShape::new(*raw),
219            ColliderView::Cuboid(CuboidView { raw }) => SharedShape::new(*raw),
220            ColliderView::Capsule(CapsuleView { raw }) => SharedShape::new(*raw),
221            ColliderView::Segment(SegmentView { raw }) => SharedShape::new(*raw),
222            ColliderView::Triangle(TriangleView { raw }) => SharedShape::new(*raw),
223            ColliderView::Voxels(VoxelsView { raw }) => SharedShape::new(raw.clone()),
224            ColliderView::TriMesh(TriMeshView { raw }) => SharedShape::new(raw.clone()),
225            ColliderView::Polyline(PolylineView { raw }) => SharedShape::new(raw.clone()),
226            ColliderView::HalfSpace(HalfSpaceView { raw }) => SharedShape::new(*raw),
227            ColliderView::HeightField(HeightFieldView { raw }) => SharedShape::new(raw.clone()),
228            ColliderView::Compound(CompoundView { raw }) => SharedShape::new(raw.clone()),
229            #[cfg(feature = "dim2")]
230            ColliderView::ConvexPolygon(ConvexPolygonView { raw }) => SharedShape::new(raw.clone()),
231            #[cfg(feature = "dim3")]
232            ColliderView::ConvexPolyhedron(ConvexPolyhedronView { raw }) => {
233                SharedShape::new(raw.clone())
234            }
235            #[cfg(feature = "dim3")]
236            ColliderView::Cylinder(CylinderView { raw }) => SharedShape::new(*raw),
237            #[cfg(feature = "dim3")]
238            ColliderView::Cone(ConeView { raw }) => SharedShape::new(*raw),
239            ColliderView::RoundCuboid(RoundCuboidView { raw }) => SharedShape::new(*raw),
240            ColliderView::RoundTriangle(RoundTriangleView { raw }) => SharedShape::new(*raw),
241            #[cfg(feature = "dim2")]
242            ColliderView::RoundConvexPolygon(RoundConvexPolygonView { raw }) => {
243                SharedShape::new(raw.clone())
244            }
245            #[cfg(feature = "dim3")]
246            ColliderView::RoundCylinder(RoundCylinderView { raw }) => SharedShape::new(*raw),
247            #[cfg(feature = "dim3")]
248            ColliderView::RoundCone(RoundConeView { raw }) => SharedShape::new(*raw),
249            #[cfg(feature = "dim3")]
250            ColliderView::RoundConvexPolyhedron(RoundConvexPolyhedronView { raw }) => {
251                SharedShape::new(raw.clone())
252            }
253        }
254    }
255
256    /// Compute the scaled version of `self.raw`.
257    pub fn raw_scale_by(&self, scale: Vect, num_subdivisions: u32) -> Option<SharedShape> {
258        let result = match self {
259            ColliderView::Cuboid(s) => SharedShape::new(s.raw.scaled(&scale.into())),
260            ColliderView::RoundCuboid(s) => SharedShape::new(RoundShape {
261                border_radius: s.raw.border_radius,
262                inner_shape: s.raw.inner_shape.scaled(&scale.into()),
263            }),
264            ColliderView::Capsule(c) => match c.raw.scaled(&scale.into(), num_subdivisions) {
265                None => {
266                    log::error!("Failed to apply scale {scale} to Capsule shape.");
267                    SharedShape::ball(0.0)
268                }
269                Some(Either::Left(b)) => SharedShape::new(b),
270                Some(Either::Right(b)) => SharedShape::new(b),
271            },
272            ColliderView::Ball(b) => match b.raw.scaled(&scale.into(), num_subdivisions) {
273                None => {
274                    log::error!("Failed to apply scale {scale} to Ball shape.");
275                    SharedShape::ball(0.0)
276                }
277                Some(Either::Left(b)) => SharedShape::new(b),
278                Some(Either::Right(b)) => SharedShape::new(b),
279            },
280            ColliderView::Segment(s) => SharedShape::new(s.raw.scaled(&scale.into())),
281            ColliderView::Triangle(t) => SharedShape::new(t.raw.scaled(&scale.into())),
282            ColliderView::Voxels(cp) => SharedShape::new(cp.raw.clone().scaled(&scale.into())),
283            ColliderView::RoundTriangle(t) => SharedShape::new(RoundShape {
284                border_radius: t.raw.border_radius,
285                inner_shape: t.raw.inner_shape.scaled(&scale.into()),
286            }),
287            ColliderView::TriMesh(t) => SharedShape::new(t.raw.clone().scaled(&scale.into())),
288            ColliderView::Polyline(p) => SharedShape::new(p.raw.clone().scaled(&scale.into())),
289            ColliderView::HalfSpace(h) => match h.raw.scaled(&scale.into()) {
290                None => {
291                    log::error!("Failed to apply scale {scale} to HalfSpace shape.");
292                    SharedShape::ball(0.0)
293                }
294                Some(scaled) => SharedShape::new(scaled),
295            },
296            ColliderView::HeightField(h) => SharedShape::new(h.raw.clone().scaled(&scale.into())),
297            #[cfg(feature = "dim2")]
298            ColliderView::ConvexPolygon(cp) => match cp.raw.clone().scaled(&scale.into()) {
299                None => {
300                    log::error!("Failed to apply scale {scale} to ConvexPolygon shape.");
301                    SharedShape::ball(0.0)
302                }
303                Some(scaled) => SharedShape::new(scaled),
304            },
305            #[cfg(feature = "dim2")]
306            ColliderView::RoundConvexPolygon(cp) => {
307                match cp.raw.inner_shape.clone().scaled(&scale.into()) {
308                    None => {
309                        log::error!("Failed to apply scale {scale} to RoundConvexPolygon shape.");
310                        SharedShape::ball(0.0)
311                    }
312                    Some(scaled) => SharedShape::new(RoundShape {
313                        border_radius: cp.raw.border_radius,
314                        inner_shape: scaled,
315                    }),
316                }
317            }
318            #[cfg(feature = "dim3")]
319            ColliderView::ConvexPolyhedron(cp) => match cp.raw.clone().scaled(&scale.into()) {
320                None => {
321                    log::error!("Failed to apply scale {scale} to ConvexPolyhedron shape.");
322                    SharedShape::ball(0.0)
323                }
324                Some(scaled) => SharedShape::new(scaled),
325            },
326            #[cfg(feature = "dim3")]
327            ColliderView::RoundConvexPolyhedron(cp) => {
328                match cp.raw.clone().inner_shape.scaled(&scale.into()) {
329                    None => {
330                        log::error!(
331                            "Failed to apply scale {scale} to RoundConvexPolyhedron shape."
332                        );
333                        SharedShape::ball(0.0)
334                    }
335                    Some(scaled) => SharedShape::new(RoundShape {
336                        border_radius: cp.raw.border_radius,
337                        inner_shape: scaled,
338                    }),
339                }
340            }
341            #[cfg(feature = "dim3")]
342            ColliderView::Cylinder(c) => match c.raw.scaled(&scale.into(), num_subdivisions) {
343                None => {
344                    log::error!("Failed to apply scale {scale} to Cylinder shape.");
345                    SharedShape::ball(0.0)
346                }
347                Some(Either::Left(b)) => SharedShape::new(b),
348                Some(Either::Right(b)) => SharedShape::new(b),
349            },
350            #[cfg(feature = "dim3")]
351            ColliderView::RoundCylinder(c) => {
352                match c.raw.inner_shape.scaled(&scale.into(), num_subdivisions) {
353                    None => {
354                        log::error!("Failed to apply scale {scale} to RoundCylinder shape.");
355                        SharedShape::ball(0.0)
356                    }
357                    Some(Either::Left(scaled)) => SharedShape::new(RoundShape {
358                        border_radius: c.raw.border_radius,
359                        inner_shape: scaled,
360                    }),
361                    Some(Either::Right(scaled)) => SharedShape::new(RoundShape {
362                        border_radius: c.raw.border_radius,
363                        inner_shape: scaled,
364                    }),
365                }
366            }
367            #[cfg(feature = "dim3")]
368            ColliderView::Cone(c) => match c.raw.scaled(&scale.into(), num_subdivisions) {
369                None => {
370                    log::error!("Failed to apply scale {scale} to Cone shape.");
371                    SharedShape::ball(0.0)
372                }
373                Some(Either::Left(b)) => SharedShape::new(b),
374                Some(Either::Right(b)) => SharedShape::new(b),
375            },
376            #[cfg(feature = "dim3")]
377            ColliderView::RoundCone(c) => {
378                match c.raw.inner_shape.scaled(&scale.into(), num_subdivisions) {
379                    None => {
380                        log::error!("Failed to apply scale {scale} to RoundCone shape.");
381                        SharedShape::ball(0.0)
382                    }
383                    Some(Either::Left(scaled)) => SharedShape::new(RoundShape {
384                        border_radius: c.raw.border_radius,
385                        inner_shape: scaled,
386                    }),
387                    Some(Either::Right(scaled)) => SharedShape::new(RoundShape {
388                        border_radius: c.raw.border_radius,
389                        inner_shape: scaled,
390                    }),
391                }
392            }
393            ColliderView::Compound(c) => {
394                let mut scaled = Vec::with_capacity(c.shapes().len());
395
396                for (tra, rot, shape) in c.shapes() {
397                    scaled.push((
398                        (tra * scale, rot).into(),
399                        shape.raw_scale_by(scale, num_subdivisions)?,
400                    ));
401                }
402                SharedShape::compound(scaled)
403            }
404        };
405
406        Some(result)
407    }
408}