rhusics_core/
body_pose.rs

1use cgmath::{BaseFloat, EuclideanSpace, InnerSpace, One, Rotation, Transform, VectorSpace};
2use collision::{Interpolate, TranslationInterpolate};
3
4use Pose;
5
6/// Transform component used throughout the library
7#[derive(Clone, Debug, PartialEq)]
8#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
9pub struct BodyPose<P, R> {
10    dirty: bool,
11    position: P,
12    rotation: R,
13    inverse_rotation: R,
14}
15
16impl<P, R> Pose<P, R> for BodyPose<P, R>
17where
18    P: EuclideanSpace,
19    P::Scalar: BaseFloat,
20    R: Rotation<P>,
21{
22    /// Create a new [`BodyPose`](struct.BodyPose.html) with initial state given by the supplied
23    /// position and rotation.
24    fn new(position: P, rotation: R) -> Self {
25        Self {
26            dirty: true,
27            position,
28            inverse_rotation: rotation.invert(),
29            rotation,
30        }
31    }
32
33    /// Set the rotation. Will also compute the inverse rotation. Sets the dirty flag.
34    fn set_rotation(&mut self, rotation: R) {
35        self.rotation = rotation;
36        self.inverse_rotation = self.rotation.invert();
37        self.dirty = true;
38    }
39
40    /// Set the position. Sets the dirty flag.
41    fn set_position(&mut self, position: P) {
42        self.position = position;
43        self.dirty = true;
44    }
45
46    /// Borrows the rotation attribute
47    fn rotation(&self) -> R {
48        self.rotation
49    }
50
51    /// Borrows the position attribute
52    fn position(&self) -> P {
53        self.position
54    }
55}
56
57impl<P, R> BodyPose<P, R>
58where
59    P: EuclideanSpace,
60    P::Scalar: BaseFloat,
61    R: Rotation<P>,
62{
63    /// Clear the dirty flag
64    pub fn clear(&mut self) {
65        self.dirty = false;
66    }
67}
68
69impl<P, R> Transform<P> for BodyPose<P, R>
70where
71    P: EuclideanSpace,
72    P::Scalar: BaseFloat,
73    R: Rotation<P>,
74{
75    fn one() -> Self {
76        Self::new(P::origin(), R::one())
77    }
78
79    fn look_at(eye: P, center: P, up: P::Diff) -> Self {
80        let rot = R::look_at(center - eye, up);
81        let disp = rot.rotate_vector(P::origin() - eye);
82        Self::new(P::from_vec(disp), rot)
83    }
84
85    fn transform_vector(&self, vec: P::Diff) -> P::Diff {
86        self.rotation.rotate_vector(vec)
87    }
88
89    fn inverse_transform_vector(&self, vec: P::Diff) -> Option<P::Diff> {
90        Some(self.inverse_rotation.rotate_vector(vec))
91    }
92
93    fn transform_point(&self, point: P) -> P {
94        self.rotation.rotate_point(point) + self.position.to_vec()
95    }
96
97    fn concat(&self, other: &Self) -> Self {
98        Self::new(
99            self.position + self.rotation.rotate_point(other.position).to_vec(),
100            self.rotation * other.rotation,
101        )
102    }
103
104    fn inverse_transform(&self) -> Option<Self> {
105        Some(Self::new(
106            self.rotation.rotate_point(self.position) * -P::Scalar::one(),
107            self.inverse_rotation,
108        ))
109    }
110}
111
112impl<P, R> TranslationInterpolate<P::Scalar> for BodyPose<P, R>
113where
114    P: EuclideanSpace,
115    P::Scalar: BaseFloat,
116    P::Diff: VectorSpace + InnerSpace,
117    R: Rotation<P> + Clone,
118{
119    fn translation_interpolate(&self, other: &Self, amount: P::Scalar) -> Self {
120        BodyPose::new(
121            P::from_vec(self.position.to_vec().lerp(other.position.to_vec(), amount)),
122            other.rotation,
123        )
124    }
125}
126
127impl<P, R> Interpolate<P::Scalar> for BodyPose<P, R>
128where
129    P: EuclideanSpace,
130    P::Scalar: BaseFloat,
131    P::Diff: VectorSpace + InnerSpace,
132    R: Rotation<P> + Interpolate<P::Scalar>,
133{
134    fn interpolate(&self, other: &Self, amount: P::Scalar) -> Self {
135        BodyPose::new(
136            P::from_vec(self.position.to_vec().lerp(other.position.to_vec(), amount)),
137            self.rotation.interpolate(&other.rotation, amount),
138        )
139    }
140}