ncollide3d/shape/
capsule.rs1use na::{self, RealField, Unit};
4
5use crate::math::{Point, Vector};
6use crate::query::{Contact, ContactKinematic, ContactPreprocessor};
7use crate::shape::{FeatureId, Segment, SupportMap};
8
9#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
11#[derive(PartialEq, Debug, Copy, Clone)]
12pub struct Capsule<N> {
13 pub half_height: N,
15 pub radius: N,
17}
18
19impl<N: RealField + Copy> Capsule<N> {
20 pub fn new(half_height: N, radius: N) -> Capsule<N> {
26 Capsule {
27 half_height,
28 radius,
29 }
30 }
31
32 #[inline]
34 #[deprecated(note = "use the `self.half_height` public field directly.")]
35 pub fn half_height(&self) -> N {
36 self.half_height
37 }
38
39 #[inline]
41 pub fn height(&self) -> N {
42 self.half_height * na::convert(2.0)
43 }
44
45 #[inline]
47 #[deprecated(note = "use the `self.radius` public field directly.")]
48 pub fn radius(&self) -> N {
49 self.radius
50 }
51
52 #[inline]
54 pub fn segment(&self) -> Segment<N> {
55 let mut a = Point::origin();
56 let mut b = Point::origin();
57 a.y = -self.half_height;
58 b.y = self.half_height;
59
60 Segment::new(a, b)
61 }
62
63 #[inline]
65 pub fn contact_preprocessor(&self) -> impl ContactPreprocessor<N> {
66 CapsuleContactPreprocessor {
67 radius: self.radius,
68 }
69 }
70}
71
72impl<N: RealField + Copy> SupportMap<N> for Capsule<N> {
73 #[inline]
74 fn local_support_point(&self, dir: &Vector<N>) -> Point<N> {
75 self.local_support_point_toward(&Unit::new_normalize(*dir))
76 }
77
78 #[inline]
79 fn local_support_point_toward(&self, dir: &Unit<Vector<N>>) -> Point<N> {
80 let mut res: Vector<N> = na::zero();
81 res[1] = self.half_height.copysign(dir[1]);
82 Point::from(res + **dir * self.radius)
83 }
84}
85
86struct CapsuleContactPreprocessor<N: RealField + Copy> {
87 radius: N,
88}
89
90impl<N: RealField + Copy> CapsuleContactPreprocessor<N> {
91 }
97
98impl<N: RealField + Copy> ContactPreprocessor<N> for CapsuleContactPreprocessor<N> {
99 fn process_contact(
100 &self,
101 c: &mut Contact<N>,
102 kinematic: &mut ContactKinematic<N>,
103 is_first: bool,
104 ) -> bool {
105 let feature = if is_first {
107 kinematic.feature1()
108 } else {
109 kinematic.feature2()
110 };
111
112 let actual_feature = match feature {
113 FeatureId::Vertex(i) => FeatureId::Face(i),
114 #[cfg(feature = "dim3")]
115 FeatureId::Edge(_) => FeatureId::Face(2),
116 FeatureId::Face(i) => FeatureId::Face(2 + i),
117 FeatureId::Unknown => return false,
118 };
119
120 if is_first {
121 kinematic.set_feature1(actual_feature);
122 kinematic.set_dilation1(self.radius);
123 c.world1 += *c.normal * self.radius;
124 c.depth += self.radius;
125 } else {
126 kinematic.set_feature2(actual_feature);
127 kinematic.set_dilation2(self.radius);
128 c.world2 -= *c.normal * self.radius;
129 c.depth += self.radius;
130 }
131
132 true
133 }
134}