Skip to content

Commit 79cb848

Browse files
committed
Keyframe: Move Bezier code into extra function, parameterise
Bezier interpolation code is now in a dedicated function and can be used to either find a Y from a known X or a X from a known Y, with a given allowed error.
1 parent 65cb3df commit 79cb848

File tree

1 file changed

+39
-33
lines changed

1 file changed

+39
-33
lines changed

src/KeyFrame.cpp

Lines changed: 39 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,44 @@ namespace {
3939
bool IsPointBeforeX(Point const & p, double const x) {
4040
return p.co.X < x;
4141
}
42+
43+
double InterpolateBezierCurve(Point const & left, Point const & right, bool const needY, double const target, double const allowed_error) {
44+
double const X_diff = right.co.X - left.co.X;
45+
double const Y_diff = right.co.Y - left.co.Y;
46+
Coordinate const p0 = left.co;
47+
Coordinate const p1 = Coordinate(p0.X + left.handle_right.X * X_diff, p0.Y + left.handle_right.Y * Y_diff);
48+
Coordinate const p2 = Coordinate(p0.X + right.handle_left.X * X_diff, p0.Y + right.handle_left.Y * Y_diff);
49+
Coordinate const p3 = right.co;
50+
51+
double t = 0.5;
52+
double t_step = 0.25;
53+
do {
54+
// Bernstein polynoms
55+
double B[4] = {1, 3, 3, 1};
56+
double oneMinTExp = 1;
57+
double tExp = 1;
58+
for (int i = 0; i < 4; ++i, tExp *= t) {
59+
B[i] *= tExp;
60+
}
61+
for (int i = 0; i < 4; ++i, oneMinTExp *= 1 - t) {
62+
B[4 - i - 1] *= oneMinTExp;
63+
}
64+
double const x = p0.X * B[0] + p1.X * B[1] + p2.X * B[2] + p3.X * B[3];
65+
double const y = p0.Y * B[0] + p1.Y * B[1] + p2.Y * B[2] + p3.Y * B[3];
66+
bool const stop = abs(target - (needY ? x : y)) < allowed_error;
67+
bool const move_left = (needY ? x : y) > target;
68+
if (stop) {
69+
return needY ? y : x;
70+
}
71+
if (move_left) {
72+
t -= t_step;
73+
}
74+
else {
75+
t += t_step;
76+
}
77+
t_step /= 2;
78+
} while (true);
79+
}
4280
}
4381

4482

@@ -231,39 +269,7 @@ double Keyframe::GetValue(int64_t index) const {
231269
// BEZIER curve!
232270
assert(candidate->interpolation == BEZIER);
233271

234-
double const X_diff = candidate->co.X - predecessor->co.X;
235-
double const Y_diff = candidate->co.Y - predecessor->co.Y;
236-
Coordinate const p0 = predecessor->co;
237-
Coordinate const p1 = Coordinate(p0.X + predecessor->handle_right.X * X_diff, p0.Y + predecessor->handle_right.Y * Y_diff);
238-
Coordinate const p2 = Coordinate(p0.X + candidate->handle_left.X * X_diff, p0.Y + candidate->handle_left.Y * Y_diff);
239-
Coordinate const p3 = candidate->co;
240-
241-
double t = 0.5;
242-
double t_step = 0.25;
243-
do {
244-
// Bernstein polynoms
245-
double B[4] = {1, 3, 3, 1};
246-
double oneMinTExp = 1;
247-
double tExp = 1;
248-
for (int i = 0; i < 4; ++i, tExp *= t) {
249-
B[i] *= tExp;
250-
}
251-
for (int i = 0; i < 4; ++i, oneMinTExp *= 1 - t) {
252-
B[4 - i - 1] *= oneMinTExp;
253-
}
254-
double const x = p0.X * B[0] + p1.X * B[1] + p2.X * B[2] + p3.X * B[3];
255-
double const y = p0.Y * B[0] + p1.Y * B[1] + p2.Y * B[2] + p3.Y * B[3];
256-
if (abs(index - x) < 0.01) {
257-
return y;
258-
}
259-
if (x > index) {
260-
t -= t_step;
261-
}
262-
else {
263-
t += t_step;
264-
}
265-
t_step /= 2;
266-
} while (true);
272+
return InterpolateBezierCurve(*predecessor, *candidate, true, index, 0.01);
267273
}
268274

269275
// Get the rounded INT value at a specific index

0 commit comments

Comments
 (0)