1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use crate::Lerper;
pub fn cubic_bezier(x1: f32, y1: f32, x2: f32, y2: f32) -> Bezier {
Bezier::new(x1, y1, x2, y2)
}
#[derive(Debug)]
pub struct Bezier {
pub(crate) x: (f32, f32, f32),
pub(crate) y: (f32, f32, f32),
}
impl Bezier {
const NEWTON_ITERATIONS: usize = 8;
const EPSILON: f32 = 1.0 / 200.0;
pub fn new(x1: f32, y1: f32, x2: f32, y2: f32) -> Bezier {
let cx = 3.0 * x1;
let bx = 3.0 * (x2 - x1) - cx;
let ax = 1.0 - cx - bx;
let cy = 3.0 * y1;
let by = 3.0 * (y2 - y1) - cy;
let ay = 1.0 - cy - by;
Bezier {
x: (ax, bx, cx),
y: (ay, by, cy),
}
}
fn sample_x(&self, t: f32) -> f32 {
let (a, b, c) = self.x;
((a * t + b) * t + c) * t
}
fn sample_y(&self, t: f32) -> f32 {
let (a, b, c) = self.y;
((a * t + b) * t + c) * t
}
fn sample_derivative_x(&self, t: f32) -> f32 {
let (a, b, c) = self.x;
(3.0 * a * t + 2.0 * b) * t + c
}
fn solve_x(&self, x: f32) -> f32 {
let mut t = x;
for _ in 0..Self::NEWTON_ITERATIONS {
let x2 = self.sample_x(t);
if approx_eq(x2, x, Self::EPSILON) {
return t;
}
let dx = self.sample_derivative_x(t);
if approx_eq(dx, 0.0, 1.0e-6) {
break;
}
t -= (x2 - x) / dx;
}
let (mut low, mut high, mut t) = (0.0, 1.0, x);
if t < low {
return low;
}
if t > high {
return high;
}
while low < high {
let x2 = self.sample_x(t);
if approx_eq(x2, x, Self::EPSILON) {
return t;
}
if x > x2 {
low = t;
} else {
high = t;
}
t = (high - low) / 2.0 + low;
}
t
}
}
impl Lerper for Bezier {
fn calculate(&self, t: f32) -> f32 {
self.sample_y(self.solve_x(t))
}
}
fn approx_eq(a: f32, b: f32, epsilon: f32) -> bool {
(a - b).abs() < epsilon
}