Skip to main content

ranim_anims/
rotating.rs

1use ranim_core::{
2    animation::Eval,
3    glam::DVec3,
4    traits::{Aabb, AabbPoint, Locate, RotateTransform, ShiftTransformExt},
5};
6
7// MARK: Require Trait
8/// The requirement of [`RotatingAnimation`]
9pub trait RotatingRequirement: RotateTransform + ShiftTransformExt + Clone {}
10impl<T: RotateTransform + ShiftTransformExt + Clone> RotatingRequirement for T {}
11
12// MARK: Anim Trait
13/// The methods to create rotation animations for `T` that satisfies [`RotatingRequirement`]
14pub trait RotatingAnim: RotatingRequirement + Sized + 'static {
15    /// Rotate by a given angle about a given axis at center.
16    fn rotating(&mut self, angle: f64, axis: DVec3) -> RotatingAnimation<Self>
17    where
18        Self: Aabb,
19    {
20        self.rotating_at(angle, axis, AabbPoint::CENTER)
21    }
22
23    /// Rotate by a given angle about a given axis at the given anchor.
24    fn rotating_at<A: Locate<Self>>(
25        &mut self,
26        angle: f64,
27        axis: DVec3,
28        anchor: A,
29    ) -> RotatingAnimation<Self> {
30        RotatingAnimation::new(self.clone(), angle, axis, anchor.locate(self)).apply_to(self)
31    }
32}
33
34impl<T: RotatingRequirement + 'static> RotatingAnim for T {}
35
36// MARK: Impl
37
38/// Rotation animation.
39///
40/// Unlike [`Morph`](crate::morph::Morph) which linearly interpolates between
41/// start and end states, this animation applies incremental rotation at each frame,
42/// producing a true circular arc motion.
43pub struct RotatingAnimation<T: RotatingRequirement> {
44    src: T,
45    angle: f64,
46    axis: DVec3,
47    point: DVec3,
48}
49
50impl<T: RotatingRequirement> RotatingAnimation<T> {
51    /// Constructor
52    pub fn new(src: T, angle: f64, axis: DVec3, point: DVec3) -> Self {
53        Self {
54            src,
55            angle,
56            axis,
57            point,
58        }
59    }
60}
61
62impl<T: RotatingRequirement> Eval for RotatingAnimation<T> {
63    type Output = T;
64
65    fn eval_alpha(&self, alpha: f64) -> Self::Output {
66        let mut result = self.src.clone();
67        result.with_origin(self.point, |x| {
68            x.rotate_on_axis(self.axis, self.angle * alpha);
69        });
70        result
71    }
72}