baiser/
curve.rs

1use crate::bezier::{Bezier0, Bezier1, Bezier2, Bezier3};
2use crate::composed_curve::ComposedCurve;
3use crate::curve_iterator::CurveIterator;
4use crate::curve_point::CurvePoint;
5use crate::linear_speed::LinearSpeed;
6use crate::Distance;
7use num_traits::Float;
8
9/// A curve is a parametric function that maps a value `t` in range from 0 to 1 to a point in space.
10pub trait Curve<F: Float, P: CurvePoint<F>> {
11    /// Get the point at a given value `t` in range from 0 to 1.
12    fn value_at(&self, t: F) -> P;
13    /// Get the derivative at a given value `t` in range from 0 to 1.
14    fn tangent_at(&self, t: F) -> P;
15
16    fn start_point(&self) -> P {
17        self.value_at(F::zero())
18    }
19
20    fn end_point(&self) -> P {
21        self.value_at(F::one())
22    }
23
24    /// Estimate the length of the curve as an average between `min` and `max` estimation.
25    /// The precision parameter is the maximum ration of `min` and `max` estimation.
26    ///
27    /// Precision:
28    ///   * **F::infinity()** - means that estimation will be done in one step,
29    ///   * **1.0** - means that `max / min` should be less than `100%`,
30    ///   * **0.5** - the same as above, but the difference is `50%`,
31    ///   * **0.1** - the same as above, but the difference is `10%`,
32    ///   * and so on...
33    fn estimate_length(&self, precision: F) -> F
34    where
35        P: Distance<F>;
36
37    /// Create a dot, at any `t` it will return the same value
38    fn dot(p0: P) -> Bezier0<F, P> {
39        Bezier0::new(p0)
40    }
41
42    /// Create a line
43    fn line(p0: P, p1: P) -> Bezier1<F, P> {
44        Bezier1::new(p0, p1)
45    }
46
47    /// Create a quadratic bezier curve
48    fn quad_bezier(p0: P, p1: P, p2: P) -> Bezier2<F, P> {
49        Bezier2::new(p0, p1, p2)
50    }
51
52    /// Create a cubic bezier curve
53    fn cubic_bezier(p0: P, p1: P, p2: P, p3: P) -> Bezier3<F, P> {
54        Bezier3::new(p0, p1, p2, p3)
55    }
56
57    /// Create an iterator that will generate points on the curve.
58    fn into_iter(self, steps_count: usize) -> CurveIterator<F, P, Self>
59    where
60        Self: Sized,
61    {
62        CurveIterator::new(self, steps_count, false)
63    }
64
65    /// Create an iterator that will generate points on the curve, including the last point.
66    fn into_iter_inclusive(self, steps_count: usize) -> CurveIterator<F, P, Self>
67    where
68        Self: Sized,
69    {
70        CurveIterator::new(self, steps_count, true)
71    }
72
73    /// Create a composed curve that will be a sequence of curves.
74    /// Each segment of the curve will be represented by equal `t` range.
75    /// For example, if you have 3 curves, they will take `t` ranges: `0 - 0.33`, `0.33 - 0.66` and `0.66 - 1.0`.
76    fn composed_curve(start_point: P) -> ComposedCurve<F, P> {
77        ComposedCurve::new(start_point)
78    }
79
80    /// Create a linear speed curve that will allow to move with a constant speed along the curve.
81    /// It's especially useful when you want to animate the movement along a composed curve.
82    ///
83    /// Arguments:
84    /// * `table_size` - the size of the table that will be used to speed up the calculations,
85    ///     the bigger means the better the precision.
86    /// * `steps_count` - the number of steps that will be used to calculate the table,
87    ///     so if you have 3 steps then the curve points will be calculated at 0.0, 0.5 and 1.0.
88    ///     Intermediate points will be interpolated.
89    fn linear_speed(self, table_size: usize, steps_count: usize) -> LinearSpeed<F, P, Self>
90    where
91        P: Distance<F>,
92        Self: Sized,
93    {
94        LinearSpeed::new(self, table_size, steps_count)
95    }
96}