|
30 | 30 |
|
31 | 31 | #include "../include/KeyFrame.h" |
32 | 32 | #include <algorithm> |
| 33 | +#include <functional> |
33 | 34 | #include <utility> |
34 | 35 |
|
35 | 36 | using namespace std; |
@@ -93,6 +94,23 @@ namespace { |
93 | 94 | case BEZIER: return InterpolateBezierCurve(left, right, target, allowed_error); |
94 | 95 | } |
95 | 96 | } |
| 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 | + } |
96 | 114 | } |
97 | 115 |
|
98 | 116 |
|
@@ -419,23 +437,14 @@ Fraction Keyframe::GetRepeatFraction(int64_t index) const { |
419 | 437 | assert(i != begin(Points)); |
420 | 438 | Point const left = *(i - 1); |
421 | 439 | 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>{}); |
437 | 446 | } |
438 | | - next_repeats = start - index; |
| 447 | + next_repeats = change_at - index; |
439 | 448 | } else { |
440 | 449 | // All values to the right are the same! |
441 | 450 | next_repeats = Points.back().co.X - index; |
@@ -472,23 +481,14 @@ Fraction Keyframe::GetRepeatFraction(int64_t index) const { |
472 | 481 | // thus the following is safe! |
473 | 482 | Point const left = *i; |
474 | 483 | 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>{}); |
490 | 490 | } |
491 | | - previous_repeats = index - start; |
| 491 | + previous_repeats = index - change_at; |
492 | 492 | } else { |
493 | 493 | // Every previous value is the same (rounded) as the current |
494 | 494 | // value. |
|
0 commit comments