ramp_maker/
iter.rs

1//! Iterators used in conjunction with [`MotionProfile`]
2
3use core::{marker::PhantomData, ops};
4
5use num_traits::{Inv as _, One as _};
6
7use crate::MotionProfile;
8
9/// An iterator over delay values
10///
11/// Can be created by calling [`MotionProfile::delays`].
12pub struct Delays<'r, Profile>(pub &'r mut Profile);
13
14impl<'r, Profile> Iterator for Delays<'r, Profile>
15where
16    Profile: MotionProfile,
17{
18    type Item = Profile::Delay;
19
20    fn next(&mut self) -> Option<Self::Item> {
21        self.0.next_delay()
22    }
23}
24
25/// An iterator over velocity values
26///
27/// Can be created by calling [`MotionProfile::velocities`].
28pub struct Velocities<'r, Profile>(pub &'r mut Profile);
29
30impl<'r, Profile> Iterator for Velocities<'r, Profile>
31where
32    Profile: MotionProfile,
33    Profile::Delay: num_traits::Inv<Output = Profile::Velocity>,
34{
35    type Item = Profile::Velocity;
36
37    fn next(&mut self) -> Option<Self::Item> {
38        self.0.next_delay().map(|delay| delay.inv())
39    }
40}
41
42/// An iterator over acceleration values
43///
44/// Can be created by calling [`MotionProfile::accelerations`].
45pub struct Accelerations<'r, Profile: MotionProfile, Accel> {
46    /// The motion profile
47    pub profile: &'r mut Profile,
48
49    /// The previous delay value
50    pub delay_prev: Option<Profile::Delay>,
51
52    _accel: PhantomData<Accel>,
53}
54
55impl<'r, Profile, Accel> Accelerations<'r, Profile, Accel>
56where
57    Profile: MotionProfile,
58{
59    /// Create a new instance of `Accelerations`
60    ///
61    /// You can call [`MotionProfile::accelerations`] instead.
62    pub fn new(profile: &'r mut Profile) -> Self {
63        let delay_prev = profile.next_delay();
64
65        Self {
66            profile,
67            delay_prev,
68            _accel: PhantomData,
69        }
70    }
71}
72
73impl<'r, Profile, Accel> Iterator for Accelerations<'r, Profile, Accel>
74where
75    Profile: MotionProfile,
76    Profile::Delay: Copy
77        + num_traits::One
78        + num_traits::Inv<Output = Profile::Velocity>
79        + ops::Add<Output = Profile::Delay>
80        + ops::Div<Output = Profile::Delay>,
81    Profile::Velocity: ops::Sub<Output = Profile::Velocity>
82        + ops::Div<Profile::Delay, Output = Accel>,
83{
84    type Item = Accel;
85
86    fn next(&mut self) -> Option<Self::Item> {
87        let delay_next = self.profile.next_delay()?;
88
89        let mut accel = None;
90        if let Some(delay_prev) = self.delay_prev {
91            let velocity_prev = delay_prev.inv();
92            let velocity_next = delay_next.inv();
93
94            let velocity_diff = velocity_next - velocity_prev;
95
96            let two = Profile::Delay::one() + Profile::Delay::one();
97
98            // - Assumes the velocity defined by a given delay to be reached at
99            //   the mid-point between the two steps that the delay separates.
100            // - Because of this, the interval between the time of the velocity
101            //   being reached and the time of a neighboring step being
102            //   initiated, is half the delay (the delay measures the interval
103            //   between two steps).
104            // - Therefore, the formula below computes the difference between
105            //   the points in time at which the two velocities are reached.
106            let time_diff = delay_prev / two + delay_next / two;
107
108            accel = Some(velocity_diff / time_diff);
109        }
110
111        self.delay_prev = Some(delay_next);
112
113        accel
114    }
115}