Skip to content

Commit c940c1f

Browse files
committed
Keyframe: Cleanup duplicate binary search code
GetRepeatFraction uses two binary searches; reuse that code!
1 parent 1fbdc52 commit c940c1f

File tree

1 file changed

+32
-32
lines changed

1 file changed

+32
-32
lines changed

src/KeyFrame.cpp

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
#include "../include/KeyFrame.h"
3232
#include <algorithm>
33+
#include <functional>
3334
#include <utility>
3435

3536
using namespace std;
@@ -93,6 +94,23 @@ namespace {
9394
case BEZIER: return InterpolateBezierCurve(left, right, target, allowed_error);
9495
}
9596
}
97+
98+
99+
template<typename Check>
100+
int64_t SearchBetweenPoints(Point const & left, Point const & right, int64_t const current, Check check) {
101+
int64_t start = left.co.X;
102+
int64_t stop = right.co.X;
103+
while (start < stop) {
104+
int64_t const mid = (start + stop + 1) / 2;
105+
double const value = InterpolateBetween(left, right, mid, 0.01);
106+
if (check(round(value), current)) {
107+
start = mid;
108+
} else {
109+
stop = mid - 1;
110+
}
111+
}
112+
return start;
113+
}
96114
}
97115

98116

@@ -419,23 +437,14 @@ Fraction Keyframe::GetRepeatFraction(int64_t index) const {
419437
assert(i != begin(Points));
420438
Point const left = *(i - 1);
421439
Point const right = *i;
422-
// Binary search for the first value which is different from
423-
// the current value.
424-
bool const increasing = current_value < round(i->co.Y);
425-
int64_t start = left.co.X;
426-
int64_t stop = right.co.X;
427-
while (start < stop) {
428-
int64_t const mid = (start + stop + 1) / 2;
429-
double const value = InterpolateBetween(left, right, mid, 0.01);
430-
bool const smaller = round(value) <= current_value;
431-
bool const larger = round(value) >= current_value;
432-
if ((increasing && smaller) || (!increasing && larger)) {
433-
start = mid;
434-
} else {
435-
stop = mid - 1;
436-
}
440+
int64_t change_at;
441+
if (current_value < round(i->co.Y)) {
442+
change_at = SearchBetweenPoints(left, right, current_value, std::less_equal<double>{});
443+
} else {
444+
assert(current_value > round(i->co.Y));
445+
change_at = SearchBetweenPoints(left, right, current_value, std::greater_equal<double>{});
437446
}
438-
next_repeats = start - index;
447+
next_repeats = change_at - index;
439448
} else {
440449
// All values to the right are the same!
441450
next_repeats = Points.back().co.X - index;
@@ -472,23 +481,14 @@ Fraction Keyframe::GetRepeatFraction(int64_t index) const {
472481
// thus the following is safe!
473482
Point const left = *i;
474483
Point const right = *(i + 1);
475-
// Binary search for the last value (seen from the left to
476-
// right) to be different than the current value.
477-
bool const increasing = current_value > round(left.co.Y);
478-
int64_t start = left.co.X;
479-
int64_t stop = right.co.X;
480-
while (start < stop) {
481-
int64_t const mid = (start + stop + 1) / 2;
482-
double const value = InterpolateBetween(left, right, mid, 0.01);
483-
bool const smaller = round(value) < current_value;
484-
bool const larger = round(value) > current_value;
485-
if ((increasing && smaller) || (!increasing && larger)) {
486-
start = mid;
487-
} else {
488-
stop = mid - 1;
489-
}
484+
int64_t change_at;
485+
if (current_value > round(left.co.Y)) {
486+
change_at = SearchBetweenPoints(left, right, current_value, std::less<double>{});
487+
} else {
488+
assert(current_value < round(left.co.Y));
489+
change_at = SearchBetweenPoints(left, right, current_value, std::greater<double>{});
490490
}
491-
previous_repeats = index - start;
491+
previous_repeats = index - change_at;
492492
} else {
493493
// Every previous value is the same (rounded) as the current
494494
// value.

0 commit comments

Comments
 (0)