From c940c1f42b65696a8154bb67ea2f3cf11c0c0b61 Mon Sep 17 00:00:00 2001 From: Daniel Jour Date: Fri, 6 Dec 2019 01:21:25 +0100 Subject: [PATCH] Keyframe: Cleanup duplicate binary search code GetRepeatFraction uses two binary searches; reuse that code! --- src/KeyFrame.cpp | 64 ++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/KeyFrame.cpp b/src/KeyFrame.cpp index c59d5bd8..d16348a2 100644 --- a/src/KeyFrame.cpp +++ b/src/KeyFrame.cpp @@ -30,6 +30,7 @@ #include "../include/KeyFrame.h" #include +#include #include using namespace std; @@ -93,6 +94,23 @@ namespace { case BEZIER: return InterpolateBezierCurve(left, right, target, allowed_error); } } + + + template + int64_t SearchBetweenPoints(Point const & left, Point const & right, int64_t const current, Check check) { + int64_t start = left.co.X; + int64_t stop = right.co.X; + while (start < stop) { + int64_t const mid = (start + stop + 1) / 2; + double const value = InterpolateBetween(left, right, mid, 0.01); + if (check(round(value), current)) { + start = mid; + } else { + stop = mid - 1; + } + } + return start; + } } @@ -419,23 +437,14 @@ Fraction Keyframe::GetRepeatFraction(int64_t index) const { assert(i != begin(Points)); Point const left = *(i - 1); Point const right = *i; - // Binary search for the first value which is different from - // the current value. - bool const increasing = current_value < round(i->co.Y); - int64_t start = left.co.X; - int64_t stop = right.co.X; - while (start < stop) { - int64_t const mid = (start + stop + 1) / 2; - double const value = InterpolateBetween(left, right, mid, 0.01); - bool const smaller = round(value) <= current_value; - bool const larger = round(value) >= current_value; - if ((increasing && smaller) || (!increasing && larger)) { - start = mid; - } else { - stop = mid - 1; - } + int64_t change_at; + if (current_value < round(i->co.Y)) { + change_at = SearchBetweenPoints(left, right, current_value, std::less_equal{}); + } else { + assert(current_value > round(i->co.Y)); + change_at = SearchBetweenPoints(left, right, current_value, std::greater_equal{}); } - next_repeats = start - index; + next_repeats = change_at - index; } else { // All values to the right are the same! next_repeats = Points.back().co.X - index; @@ -472,23 +481,14 @@ Fraction Keyframe::GetRepeatFraction(int64_t index) const { // thus the following is safe! Point const left = *i; Point const right = *(i + 1); - // Binary search for the last value (seen from the left to - // right) to be different than the current value. - bool const increasing = current_value > round(left.co.Y); - int64_t start = left.co.X; - int64_t stop = right.co.X; - while (start < stop) { - int64_t const mid = (start + stop + 1) / 2; - double const value = InterpolateBetween(left, right, mid, 0.01); - bool const smaller = round(value) < current_value; - bool const larger = round(value) > current_value; - if ((increasing && smaller) || (!increasing && larger)) { - start = mid; - } else { - stop = mid - 1; - } + int64_t change_at; + if (current_value > round(left.co.Y)) { + change_at = SearchBetweenPoints(left, right, current_value, std::less{}); + } else { + assert(current_value < round(left.co.Y)); + change_at = SearchBetweenPoints(left, right, current_value, std::greater{}); } - previous_repeats = index - start; + previous_repeats = index - change_at; } else { // Every previous value is the same (rounded) as the current // value.