flo_curves/bezier/
deform.rs

1use super::curve::*;
2
3///
4/// Moves the point at 't' on the curve by the offset vector
5/// 
6/// This recomputes the control points such that the point at t on the original curve
7/// is moved by the vector specified by `offset`.
8/// 
9pub fn move_point<CurveOut: BezierCurveFactory>(curve: &impl BezierCurve<Point=CurveOut::Point>, t: f64, offset: &CurveOut::Point) -> CurveOut {
10    // Fetch the points from the curve
11    let w1          = curve.start_point();
12    let w4          = curve.end_point();
13    let (w2, w3)    = curve.control_points();
14
15    let one_minus_t         = 1.0-t;
16    let one_minus_t_cubed   = one_minus_t*one_minus_t*one_minus_t;
17    let t_cubed             = t*t*t;
18
19    // Point 'C' is fixed for the transformation and is along the line w1-w4
20    let u = one_minus_t_cubed / (t_cubed + one_minus_t_cubed);
21    let c = w1*u + w4*(1.0-u);
22
23    // Construct the de Casteljau points for the point we're moving
24    let wn1 = w1*(1.0-t) + w2*t;
25    let wn2 = w2*(1.0-t) + w3*t;
26    let wn3 = w3*(1.0-t) + w4*t;
27
28    let wnn1 = wn1*(1.0-t) + wn2*t;
29    let wnn2 = wn2*(1.0-t) + wn3*t;
30
31    let p = wnn1*(1.0-t) + wnn2*t;
32
33    // Translating wnn1 and wnn2 by the offset will give us a new p that is also translated by the offset
34    let pb = p + *offset;
35
36    let wnn1b = wnn1 + *offset;
37    let wnn2b = wnn2 + *offset;
38
39    // The line c->pb->wn2b has the same ratios as the line c->p->wn2, so we can compute wn2b
40    // There's a trick to calculating this for cubic curves (which is handy as it means this will work with straight lines as well as curves)
41    let ratio   = ((t_cubed+one_minus_t_cubed)/(t_cubed + one_minus_t_cubed-1.0)).abs();
42    let wn2b    = ((pb-c)*ratio) + pb;
43
44    // We can now calculate wn1b and wn3b
45    let inverse_t       = 1.0/t;
46    let inverse_tminus1 = 1.0/(t-1.0);
47    
48    let wn1b = (wn2b*t - wnn1b)*inverse_tminus1;
49    let wn3b = (wn2b*-1.0 + wn2b*t + wnn2b)*inverse_t;
50
51    // ... and the new control points
52    let w2b = (w1*-1.0 + w1*t + wn1b)*inverse_t;
53    let w3b = (w4*t-wn3b)*inverse_tminus1;
54
55    // Use the values to construct the curve with the moved point
56    CurveOut::from_points(w1, (w2b, w3b), w4)
57}