1use crate::math::{Point, Real, Vector};
4use crate::shape::SupportMap;
5use na;
6use num::Zero;
7
8#[cfg(feature = "alloc")]
9use either::Either;
10
11#[cfg(not(feature = "alloc"))]
12use na::RealField; #[cfg(feature = "rkyv")]
15use rkyv::{bytecheck, CheckBytes};
16
17#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
19#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
20#[cfg_attr(
21 feature = "rkyv",
22 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes),
23 archive(as = "Self")
24)]
25#[derive(PartialEq, Debug, Copy, Clone)]
26#[repr(C)]
27pub struct Cone {
28 pub half_height: Real,
30 pub radius: Real,
32}
33
34impl Cone {
35 pub fn new(half_height: Real, radius: Real) -> Cone {
41 Cone {
42 half_height,
43 radius,
44 }
45 }
46
47 #[cfg(feature = "alloc")]
54 #[inline]
55 pub fn scaled(
56 self,
57 scale: &Vector<Real>,
58 nsubdivs: u32,
59 ) -> Option<Either<Self, super::ConvexPolyhedron>> {
60 if scale.x != scale.z || scale.y < 0.0 {
63 let (mut vtx, idx) = self.to_trimesh(nsubdivs);
65 vtx.iter_mut()
66 .for_each(|pt| pt.coords = pt.coords.component_mul(scale));
67 Some(Either::Right(super::ConvexPolyhedron::from_convex_mesh(
68 vtx, &idx,
69 )?))
70 } else {
71 Some(Either::Left(Self::new(
72 self.half_height * scale.y,
73 self.radius * scale.x,
74 )))
75 }
76 }
77}
78
79impl SupportMap for Cone {
80 #[inline]
81 fn local_support_point(&self, dir: &Vector<Real>) -> Point<Real> {
82 let mut vres = *dir;
83
84 vres[1] = 0.0;
85
86 if vres.normalize_mut().is_zero() {
87 vres = na::zero();
88 vres[1] = self.half_height.copysign(dir[1]);
89 } else {
90 vres *= self.radius;
91 vres[1] = -self.half_height;
92
93 if dir.dot(&vres) < dir[1] * self.half_height {
94 vres = na::zero();
95 vres[1] = self.half_height
96 }
97 }
98
99 Point::from(vres)
100 }
101}