Skip to main content

bevy_rapier2d/geometry/shape_views/
collider_view.rs

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