cubic_bezier/
lib.rs

1mod tests;
2pub mod control;
3
4use std::ops::{Mul, Range};
5
6use num::{Float, NumCast};
7use vector2d::Vector2D;
8
9pub use control::{Continuity, Direction, Handle, Validity};
10
11#[macro_export]
12macro_rules! point {
13    ($x : expr,$y : expr) => {
14        Vector2D::new($x, $y)
15    };
16}
17
18/// A cubic bezier type controlled by `Handles`.
19/// ```
20/// use cubic_bezier::{point, Bezier, Handle};
21///
22/// let mut bezier = Bezier::new(10,2);
23/// bezier.push(Handle::mirrored(point!(-1.0,1.0),point!(0.0,0.0)));
24/// bezier.push(Handle::mirrored(point!(1.0,1.0),point!(2.0,0.0)));
25/// 
26/// let points = bezier.calculate();
27/// ```
28/// Creating a new bezier is done with the `new` method. The
29/// first parameter determines how many point each segment should
30/// have. The second parameter is an estimation of how many
31/// handles will be added to the bezier. This is used for optimization,
32/// since it will cause the entire `points` vec to be allocated at
33/// once, avoiding unneccecary vector allocations. This value does
34/// not need to be accurate and you can set it to `0` to allocate no
35/// space to begin with.
36/// 
37/// The calculated points are stored internally. You can get a reference
38/// to the points by calling `calculate()`. Calling this function multiple
39/// times (without changing the curve) does not result in additional
40/// calculations. 
41/// If only one segment of the curve changed, only that segment will be
42/// recalculated.
43pub struct Bezier<F: Float> {
44    handles: Vec<Handle<F>>,
45    detail: usize,
46
47    num_ignored: usize,
48    points: Vec<Vector2D<F>>,
49}
50
51fn interpolate<T: Float>(a: &Vector2D<T>, b: &Vector2D<T>, t: T) -> Vector2D<T> {
52    a.mul(T::one() - t) + b.mul(t)
53}
54
55impl<F: Float> Bezier<F> {
56    pub fn new(detail: usize, expected_handle_num: usize) -> Self {
57        Bezier {
58            handles: Vec::with_capacity(expected_handle_num),
59            detail,
60            points: Vec::with_capacity(expected_handle_num * detail),
61            num_ignored: 0,
62        }
63    }
64
65    fn invalidate_handle(&mut self, handle_index: usize) {
66        if handle_index >= self.handles.len() {
67            return;
68        }
69        self.handles[handle_index as usize].validity = Validity::Invalidated;
70    }
71
72    pub fn push(&mut self, handle: Handle<F>) {
73        self.handles.push(handle);
74    }
75    pub fn insert(&mut self, index: usize, handle: Handle<F>) {
76        if index != 0 {
77            self.invalidate_handle(index - 1);
78        }
79        self.handles.insert(index, handle);
80    }
81    pub fn splice(&mut self, range: Range<usize>, handles: Vec<Handle<F>>) {
82        if range.start != 0 {
83            self.invalidate_handle(range.start - 1);
84        }
85        self.handles.splice(range, handles);
86    }
87
88    pub fn remove(&mut self, index: usize) {
89        if index != 0 {        
90            self.invalidate_handle(index - 1);
91        }            
92        self.handles.remove(index);
93    }
94    pub fn drain(&mut self, range: Range<usize>) {
95        if range.start != 0 {
96            self.invalidate_handle(range.start - 1);
97        }
98        self.handles.drain(range);
99    }
100
101    pub fn get_handle(&self, index: usize) -> &Handle<F> {
102        &self.handles[index]
103    }
104    pub fn get_handle_mut(&mut self, index: usize) -> &mut Handle<F> {
105        self.invalidate_handle(index);
106        &mut self.handles[index]
107    }
108
109    ///Inserts a handle without changing the appearance of the curve.
110    ///### Parameters
111    /// * Time: decimal value in which the value before the decimal
112    /// is the part index, and the value after is the progress
113    /// through that part.
114    ///### Example
115    /// ```
116    /// use cubic_bezier::{point, Bezier, Handle};
117    ///
118    /// let mut bezier = Bezier::new(10,3);
119    /// bezier.splice(0..0,vec![
120    ///     Handle::mirrored(point!(0.0,0.0),point!(1.0,1.0)),
121    ///     Handle::mirrored(point!(4.0,1.0),point!(5.0,0.0)),
122    /// ]);
123    /// let points_before = bezier.calculate().to_owned();
124    /// 
125    /// bezier.knot_insert(0.5);
126    /// let points_after = bezier.calculate().to_owned();
127    /// 
128    /// assert_eq!(points_before,points_after);
129    /// ```
130    pub fn knot_insert(&mut self, mut time: F) {
131        let part_index = <usize as NumCast>::from(time).unwrap();
132        if part_index >= self.handles.len() - 1 {
133            panic!("Knot insertion failed because time was out of bounds.")
134        }
135        let points = self.part_points(part_index);
136        time = time - time.floor();
137
138        let center_point = interpolate(points[1], points[2], time);
139
140        let prev_forward = interpolate(points[0], points[1], time);
141        let next_backward = interpolate(points[2], points[3], time);
142        let new_backward = interpolate(&prev_forward, &center_point, time);
143        let new_forward = interpolate(&center_point, &next_backward, time);
144        let new_position = interpolate(&new_backward, &new_forward, time);
145
146        self.handles[part_index].after = prev_forward;
147        self.handles[part_index + 1].before = next_backward;
148
149        let handle = Handle::new(new_backward, new_position, new_forward);
150        self.handles.insert(part_index + 1, handle);
151    }
152
153    /// Return the 4 points of a part.
154    fn part_points(&self, part_index: usize) -> [&Vector2D<F>; 4] {
155        if part_index >= self.handles.len() - 1 {
156            panic!("part_index exceeds part length in part_points");
157        }
158        [
159            &self.handles[part_index].position,
160            &self.handles[part_index].after,
161            &self.handles[part_index + 1].before,
162            &self.handles[part_index + 1].position,
163        ]
164    }
165    /// Helper function to get a vector of all control points.
166    pub fn all_part_point(&self) -> Vec<Vector2D<F>> {
167        let mut result: Vec<Vector2D<F>> = vec![];
168        for part_index in 0..self.handles.len() - 1 {
169            result.push(self.part_points(part_index)[0].to_owned());
170            result.push(self.part_points(part_index)[1].to_owned());
171            result.push(self.part_points(part_index)[2].to_owned());
172            result.push(self.part_points(part_index)[3].to_owned());
173        }
174        result
175    }
176    /// Returns wether a part is empty. This could happen due to a handle being detached.
177    fn part_is_empty(&self, part_index: usize) -> bool {
178        if part_index >= self.handles.len() - 1 {
179            panic!("part_index exceeds part length in part_is_empty");
180        }
181        self.handles[part_index].continuity == Continuity::Detached(Direction::Forward)
182            || self.handles[part_index].continuity == Continuity::Detached(Direction::Both)
183            || self.handles[part_index + 1].continuity == Continuity::Detached(Direction::Backward)
184            || self.handles[part_index + 1].continuity == Continuity::Detached(Direction::Both)
185    }
186    /// Calculate a single part.
187    /// ### Parameters
188    /// * Part_index: index of the handle at the start of a part.
189    fn calculate_part(&mut self, part_index: usize) {
190        if part_index >= self.handles.len() - 1 {
191            panic!("part_index exceeds part length in calculate_part");
192        }
193        let validity = &self.handles[part_index].validity;
194        if self.part_is_empty(part_index) {
195            self.num_ignored += 1;
196            return;
197        }
198        if validity == &Validity::Valid {
199            return;
200        }
201
202        let controls = self.part_points(part_index);
203
204        let f_three = F::from(3.0).unwrap();
205        let f_six = F::from(6.0).unwrap();
206        let coefficients = (
207            *controls[0],
208            controls[0].mul(-f_three) + controls[1].mul(f_three),
209            controls[0].mul(f_three) + controls[1].mul(-f_six) + controls[2].mul(f_three),
210            controls[0].mul(-F::one())
211                + controls[1].mul(f_three)
212                + controls[2].mul(-f_three)
213                + *controls[3],
214        );
215
216        let start_index = (self.detail) * (part_index - self.num_ignored);
217        if validity == &Validity::Uninitialized {
218            self.points.splice(
219                start_index..start_index,
220                vec![Vector2D::new(F::zero(), F::zero()); self.detail],
221            );
222        }
223
224        for point_index in 0..self.detail {
225            let t = F::from(point_index).unwrap() / F::from(self.detail).unwrap();
226            let tpow2 = t * t;
227            let tpow3 = t * tpow2;
228            self.points[start_index + point_index] = coefficients.0
229                + coefficients.1.mul(t)
230                + coefficients.2.mul(tpow2)
231                + coefficients.3.mul(tpow3);
232        }
233        self.handles[part_index].validity = Validity::Valid;
234    }
235
236    /// Calculate all points of the curve. Does not recalculate
237    /// parts that were unchanged. Returns a vector with coordinates.
238    /// of length *detail * num_handles*.
239    /// ```
240    /// use cubic_bezier::{Handle,Bezier};
241    ///
242    /// let bezier = Bezier::new(50,2);
243    /// bezier.push(Handle::mirrored(point!(0.0,0.0),point!(1.0,0.0)));
244    /// bezier.push(Handle::mirrored(point!(2.0,2.0),point!(3.0,3.0)));
245    ///
246    /// let points = bezier.calculate();
247    /// assert_eq!(points.len(),50 * 2);
248    /// ```
249    pub fn calculate(&mut self) -> &Vec<Vector2D<F>> {
250        self.num_ignored = 0;
251        for part_index in 0..self.handles.len() - 1 {
252            self.calculate_part(part_index);
253        }
254        &self.points
255    }
256}