Skip to main content

ranim_anims/
rotating.rs

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