ranim_anims/
rotating.rs

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