barnsley/
animation.rs

1//! a struct and associated methods for animations
2//! 
3//! An animation sequence takes `n` iterated function systems and `n-1` step counts.
4//! Step counts indicate how many interpolations happen between a pair of IFSes. 
5//! For example, if the `ifs_vec = vec![a, b, c];`
6//! and `step_counts=vec![100, 200];` It would take 100 steps interpolating between `a` and `b` 
7//! and `200` steps between `b` and `c`. 
8//! 
9use crate::{ifs::IFS, image::Image};
10
11/// Representation of animation.
12pub struct AnimationSequence {
13    pub ifs_vec: Vec<IFS>,
14    pub step_counts: Vec<usize>
15}
16
17impl AnimationSequence {
18    fn determine_current_pair_index(&self, current_step: usize) -> usize {
19        let mut pair_index = 0;
20        let mut accumulator = 0;
21        while accumulator < current_step {
22            accumulator += self.step_counts.get(pair_index).expect("current_step exceeds total step count.");
23            pair_index += 1;
24        }
25        pair_index - 1
26    }
27
28    fn determine_current_pct(&self, current_step: usize, pair_index: usize) -> f32{
29        let mut current_pair = 0;
30        let mut accumulator = 0;
31        while current_pair < pair_index {
32            accumulator += self.step_counts.get(current_pair).expect("current_step exceeds total step count.");
33            current_pair += 1;
34        }
35        let this_pair_steps = current_step - accumulator;
36        this_pair_steps as f32 / *self.step_counts.get(pair_index).unwrap() as f32
37    }
38
39    /// Animate to return only one image at a given `current_step`.
40    /// ```rust
41    /// use barnsley::{transform::AffineTransform, ifs::IFS, animation::AnimationSequence};
42    /// 
43    /// let mut start = IFS::new();
44    /// start.add_transform(AffineTransform::random().into());
45    /// 
46    /// let mut middle = IFS::new();
47    /// middle.add_transform(AffineTransform::random().into());
48    /// 
49    /// let mut end = IFS::new();
50    /// end.add_transform(AffineTransform::random().into());
51    /// 
52    /// let animation = AnimationSequence{ifs_vec: vec![start, middle, end], step_counts: vec![10, 20]};
53    /// let result = animation.animate_single_step(100, 100, 100, 100, 11);
54    /// ```
55    pub fn animate_single_step(&self, width: usize, height: usize, 
56        num_iterations: usize, num_points: usize, current_step: usize) -> Image {
57            let pair_index = self.determine_current_pair_index(current_step);
58
59            let start = self.ifs_vec.get(pair_index).unwrap();
60            let end = self.ifs_vec.get(pair_index + 1).unwrap();
61            let pct = self.determine_current_pct(current_step, pair_index); 
62            let this_ifs = start.morph(end, pct);
63
64            let mut this_image = Image::new(width, height);
65            this_ifs.evaluate(&mut this_image, num_points, num_iterations);
66            this_image
67    }
68
69    /// Animate all steps in an IFS to get a `Vec<Image>`.
70    /// ```rust
71    /// use barnsley::{transform::AffineTransform, ifs::IFS, animation::AnimationSequence};
72    /// 
73    /// let mut start = IFS::new();
74    /// start.add_transform(AffineTransform::random().into());
75    /// 
76    /// let mut middle = IFS::new();
77    /// middle.add_transform(AffineTransform::random().into());
78    /// 
79    /// let mut end = IFS::new();
80    /// end.add_transform(AffineTransform::random().into());
81    /// 
82    /// let animation = AnimationSequence{ifs_vec: vec![start, middle, end], step_counts: vec![2, 3]};
83    /// let movie = animation.animate(100, 100, 100, 100);
84    /// ```
85    pub fn animate(&self, width: usize, height: usize, num_iterations: usize, num_points: usize) -> Vec<Image> {
86        let mut images = vec![];
87
88        for pair_index in 0..self.ifs_vec.len()-1 {
89            let num_steps_for_pair = *self.step_counts.get(pair_index).unwrap();
90
91            let start = self.ifs_vec.get(pair_index).unwrap();
92            let end = self.ifs_vec.get(pair_index + 1).unwrap();
93            for step in 0..num_steps_for_pair{
94
95                let this_ifs = start.morph(end, step as f32 / num_steps_for_pair as f32);
96
97                let mut this_image = Image::new(width, height);
98                this_ifs.evaluate(&mut this_image, num_points, num_iterations);
99
100                images.insert(images.len(), this_image);
101            }
102        }
103        images
104    }
105}
106
107#[cfg(test)]
108mod tests {
109    use crate::{ifs::IFS, animation::AnimationSequence};
110
111    #[test]
112    fn test_determine_current_pair_index() {
113        let ifs1: IFS = IFS::new();
114        let ifs2: IFS = IFS::new();
115        let ifs3: IFS = IFS::new();
116        let ifs4: IFS = IFS::new();
117
118        let seq = AnimationSequence{ifs_vec: vec![ifs1, ifs2, ifs3, ifs4], 
119            step_counts: vec![100, 200, 300]};
120
121        assert_eq!(seq.determine_current_pair_index(30), 0);
122        assert_eq!(seq.determine_current_pair_index(100), 0);
123        assert_eq!(seq.determine_current_pair_index(101), 1);
124        assert_eq!(seq.determine_current_pair_index(101), 1);
125        assert_eq!(seq.determine_current_pair_index(305), 2);
126    }
127
128    #[test]
129    fn test_determine_current_pct() {
130        let ifs1: IFS = IFS::new();
131        let ifs2: IFS = IFS::new();
132        let ifs3: IFS = IFS::new();
133        let ifs4: IFS = IFS::new();
134
135        let seq = AnimationSequence{ifs_vec: vec![ifs1, ifs2, ifs3, ifs4], 
136            step_counts: vec![100, 200, 300]};
137
138        assert!((seq.determine_current_pct(30, 0) - 0.3).abs() < 0.01);
139        assert!((seq.determine_current_pct(101, 1) - 1.0/200.0).abs() < 0.01);
140        assert!((seq.determine_current_pct(201, 1) - 101.0/200.0).abs() < 0.01);
141    }
142}