1use either::Either;
2use na::Unit;
3
4use crate::math::{Isometry, Point, Real, Vector};
5use crate::shape::SupportMap;
6
7#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
9#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
10#[cfg_attr(
11 feature = "rkyv",
12 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize),
13 archive(check_bytes)
14)]
15#[derive(PartialEq, Debug, Copy, Clone)]
16#[repr(C)]
17pub struct Ball {
18 pub radius: Real,
20}
21
22impl Ball {
23 #[inline]
25 pub fn new(radius: Real) -> Ball {
26 Ball { radius }
27 }
28
29 #[cfg(all(feature = "dim2", feature = "alloc"))]
36 #[inline]
37 pub fn scaled(
38 self,
39 scale: &Vector<Real>,
40 nsubdivs: u32,
41 ) -> Option<Either<Self, super::ConvexPolygon>> {
42 if scale.x != scale.y {
43 let mut vtx = self.to_polyline(nsubdivs);
45 vtx.iter_mut()
46 .for_each(|pt| pt.coords = pt.coords.component_mul(scale));
47 Some(Either::Right(super::ConvexPolygon::from_convex_polyline(
48 vtx,
49 )?))
50 } else {
51 let uniform_scale = scale.x;
52 Some(Either::Left(Self::new(self.radius * uniform_scale.abs())))
53 }
54 }
55
56 #[cfg(all(feature = "dim3", feature = "alloc"))]
63 #[inline]
64 pub fn scaled(
65 self,
66 scale: &Vector<Real>,
67 nsubdivs: u32,
68 ) -> Option<Either<Self, super::ConvexPolyhedron>> {
69 if scale.x != scale.y || scale.x != scale.z || scale.y != scale.z {
70 let (mut vtx, idx) = self.to_trimesh(nsubdivs, nsubdivs);
72 vtx.iter_mut()
73 .for_each(|pt| pt.coords = pt.coords.component_mul(scale));
74 Some(Either::Right(super::ConvexPolyhedron::from_convex_mesh(
75 vtx, &idx,
76 )?))
77 } else {
78 let uniform_scale = scale.x;
79 Some(Either::Left(Self::new(self.radius * uniform_scale.abs())))
80 }
81 }
82}
83
84impl SupportMap for Ball {
85 #[inline]
86 fn support_point(&self, m: &Isometry<Real>, dir: &Vector<Real>) -> Point<Real> {
87 self.support_point_toward(m, &Unit::new_normalize(*dir))
88 }
89
90 #[inline]
91 fn support_point_toward(&self, m: &Isometry<Real>, dir: &Unit<Vector<Real>>) -> Point<Real> {
92 Point::from(m.translation.vector) + **dir * self.radius
93 }
94
95 #[inline]
96 fn local_support_point(&self, dir: &Vector<Real>) -> Point<Real> {
97 self.local_support_point_toward(&Unit::new_normalize(*dir))
98 }
99
100 #[inline]
101 fn local_support_point_toward(&self, dir: &Unit<Vector<Real>>) -> Point<Real> {
102 Point::from(**dir * self.radius)
103 }
104}