baiser/
linear_speed.rs

1use crate::smooth_array::SmoothArray;
2use crate::{Curve, CurvePoint, Distance};
3use num_traits::Float;
4use std::marker::PhantomData;
5
6/// The same curve as a passed one, but with a linear dependency between the time and the distance.
7pub struct LinearSpeed<F: Float, P: CurvePoint<F> + Distance<F>, C: Curve<F, P>> {
8    curve: C,
9    length: F,
10    table: SmoothArray<F>,
11    phantom_data: PhantomData<P>,
12}
13
14impl<F: Float, P: CurvePoint<F> + Distance<F>, C: Curve<F, P>> LinearSpeed<F, P, C> {
15    pub fn new(curve: C, table_size: usize, steps_count: usize) -> Self {
16        let mut table = SmoothArray::with_steps_count(table_size);
17
18        let mut last_point = curve.value_at(F::zero());
19        let mut total_length = F::zero();
20
21        let mut t_by_offset: Vec<(F, F)> = Vec::with_capacity(steps_count + 1);
22        t_by_offset.push((F::zero(), F::zero()));
23
24        let inverted_steps = F::one() / F::from(steps_count).unwrap();
25
26        for i in 1..=steps_count {
27            let t = F::from(i).unwrap() * inverted_steps;
28            let point = curve.value_at(t);
29            let segment_length = last_point.distance(&point);
30            total_length = total_length + segment_length;
31            t_by_offset.push((total_length, t));
32            last_point = point;
33        }
34
35        let inverted_length = F::one() / total_length;
36        t_by_offset.windows(2).for_each(|window| {
37            let (offset1, t1) = window[0];
38            let (offset2, t2) = window[1];
39            table.line(
40                (offset1 * inverted_length, t1),
41                (offset2 * inverted_length, t2),
42            );
43        });
44
45        Self {
46            curve,
47            length: total_length,
48            table,
49            phantom_data: Default::default(),
50        }
51    }
52}
53
54impl<F: Float, P: CurvePoint<F> + Distance<F>, C: Curve<F, P>> Curve<F, P>
55    for LinearSpeed<F, P, C>
56{
57    fn value_at(&self, t: F) -> P {
58        self.curve.value_at(t)
59    }
60
61    fn tangent_at(&self, t: F) -> P {
62        let t = t.clamp(F::zero(), F::one());
63        let t = self.table.value_at(t);
64        self.curve.tangent_at(t).scale(self.table.tangent_at(t))
65    }
66
67    fn start_point(&self) -> P {
68        self.curve.start_point()
69    }
70
71    fn end_point(&self) -> P {
72        self.curve.end_point()
73    }
74
75    fn estimate_length(&self, _precision: F) -> F {
76        self.length
77    }
78}