37 double const diff_Y = right.
co.
Y - left.
co.
Y;
38 double const diff_X = right.
co.
X - left.
co.
X;
39 double const slope = diff_Y / diff_X;
40 return left.
co.
Y + slope * (target - left.
co.
X);
45 double const X_diff = right.
co.
X - left.
co.
X;
46 double const Y_diff = right.
co.
Y - left.
co.
Y;
56 double B[4] = {1, 3, 3, 1};
57 double oneMinTExp = 1;
59 for (
int i = 0; i < 4; ++i, tExp *= t) {
62 for (
int i = 0; i < 4; ++i, oneMinTExp *= 1 - t) {
63 B[4 - i - 1] *= oneMinTExp;
65 double const x = p0.
X * B[0] + p1.
X * B[1] + p2.
X * B[2] + p3.
X * B[3];
66 double const y = p0.
Y * B[0] + p1.
Y * B[1] + p2.
Y * B[2] + p3.
Y * B[3];
67 if (fabs(target - x) < allowed_error) {
83 if(left.
co.
X > target){
86 if(target > right.
co.
X){
98 template<
typename Check>
100 int64_t start = left.
co.
X;
101 int64_t stop = right.
co.
X;
102 while (start < stop) {
103 int64_t
const mid = (start + stop + 1) / 2;
105 if (check(round(value), current)) {
115 Keyframe::Keyframe(
double value) {
117 AddPoint(
Point(1, value));
121 Keyframe::Keyframe(
const std::vector<openshot::Point>& points) : Points(points) {};
126 Points.shrink_to_fit();
134 std::vector<Point>::iterator candidate =
136 if (candidate == end(Points)) {
140 }
else if ((*candidate).co.X == p.
co.
X) {
148 size_t const candidate_index = candidate - begin(Points);
150 std::move_backward(begin(Points) + candidate_index, end(Points) - 1, end(Points));
151 Points[candidate_index] = p;
159 Point new_point(x, y, interpolate);
168 for (std::vector<Point>::size_type x = 0; x < Points.size(); x++) {
170 Point existing_point = Points[x];
173 if (p.
co.
X == existing_point.
co.
X && p.
co.
Y == existing_point.
co.
Y) {
185 std::vector<Point>::const_iterator i =
187 return i != end(Points) && i->co.X == p.
co.
X;
192 if (Points.size() == 0) {
193 return Point(-1, -1);
198 std::vector<Point>::const_iterator candidate =
201 if (candidate == end(Points)) {
205 return Points.back();
207 if (candidate == begin(Points)) {
211 return Points.front();
214 return *(candidate - 1);
234 return Points[index - 1];
240 return Point(-1, -1);
246 Point maxPoint(-1, -1);
248 for (
Point const & existing_point: Points) {
249 if (existing_point.co.Y >= maxPoint.
co.
Y) {
250 maxPoint = existing_point;
259 if (Points.empty()) {
262 std::vector<Point>::const_iterator candidate =
263 std::lower_bound(begin(Points), end(Points),
static_cast<double>(index),
IsPointBeforeX);
265 if (candidate == end(Points)) {
267 return Points.back().co.Y;
269 if (candidate == begin(Points)) {
271 return Points.front().co.Y;
273 if (candidate->co.X == index) {
275 return candidate->co.Y;
277 std::vector<Point>::const_iterator predecessor = candidate - 1;
288 return long(round(
GetValue(index)));
303 const double current_value =
GetValue(index);
307 while (attempts < 600 && index + attempts <=
GetLength()) {
309 const double next_value =
GetValue(index + attempts);
312 const double diff = next_value - current_value;
313 if (fabs(diff) > 0.0001) {
343 root[
"Points"] = Json::Value(Json::arrayValue);
346 for (
const auto existing_point : Points) {
347 root[
"Points"].append(existing_point.JsonValue());
364 catch (
const std::exception& e)
367 throw InvalidJSON(
"JSON is invalid (missing keys or invalid data types)");
375 Points.shrink_to_fit();
377 if (root.isObject() && !root[
"Points"].isNull()) {
379 for (
const auto existing_point : root[
"Points"]) {
389 }
else if (root.isNumeric()) {
391 Point p(root.asFloat());
400 if (index < 1)
return 0.0;
401 if (index == 1 && !Points.empty())
return Points[0].co.Y;
409 if (index >= 0 && index < (int64_t)Points.size())
410 return Points[index];
418 if (Points.empty())
return 0;
419 if (Points.size() == 1)
return 1;
420 return round(Points.back().co.X);
426 return Points.size();
432 for (std::vector<Point>::size_type x = 0; x < Points.size(); x++) {
434 Point existing_point = Points[x];
437 if (p.
co.
X == existing_point.
co.
X && p.
co.
Y == existing_point.
co.
Y) {
439 Points.erase(Points.begin() + x);
451 if (index >= 0 && index < (int64_t)Points.size())
454 Points.erase(Points.begin() + index);
471 *out << std::right << std::setprecision(4) << std::setfill(
' ');
472 for (
const auto& p : Points) {
473 *out << std::defaultfloat
474 << std::setw(6) << p.co.X
475 << std::setw(14) << std::fixed << p.co.Y
483 std::vector<int> w{10, 12, 8, 11, 19};
485 *out << std::right << std::setfill(
' ') << std::setprecision(4);
488 << std::setw(w[0]) <<
"Frame# (X)" <<
" │"
489 << std::setw(w[1]) <<
"Y Value" <<
" │"
490 << std::setw(w[2]) <<
"Delta Y" <<
" │ "
491 << std::setw(w[3]) <<
"Increasing?" << std::right
494 *out <<
"├───────────"
497 <<
"┼────────────┤\n";
499 for (int64_t i = 1; i <=
GetLength(); ++i) {
501 << std::setw(w[0]-2) << std::defaultfloat << i
503 << std::setw(w[1]) << std::fixed <<
GetValue(i) <<
" │"
504 << std::setw(w[2]) << std::defaultfloat << std::showpos
505 <<
GetDelta(i) <<
" │ " << std::noshowpos
507 << (
IsIncreasing(i) ?
"true" :
"false") << std::right <<
"│\n";
509 *out <<
" * = Keyframe point (non-interpolated)\n";
523 for (std::vector<Point>::size_type point_index = 1; point_index < Points.size(); point_index++) {
525 Points[point_index].co.X = round(Points[point_index].co.X * scale);
531 for (std::vector<Point>::size_type point_index = 0, reverse_index = Points.size() - 1; point_index < reverse_index; point_index++, reverse_index--) {
534 swap(Points[point_index].co.Y, Points[reverse_index].co.Y);