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}