OpenShot Library | libopenshot  0.3.0
KeyFrame.cpp
Go to the documentation of this file.
1 
9 // Copyright (c) 2008-2019 OpenShot Studios, LLC
10 //
11 // SPDX-License-Identifier: LGPL-3.0-or-later
12 
13 #include "KeyFrame.h"
14 #include "Exceptions.h"
15 
16 #include <algorithm> // For std::lower_bound, std::move_backward
17 #include <functional> // For std::less, std::less_equal, etc…
18 #include <utility> // For std::swap
19 #include <numeric> // For std::accumulate
20 #include <cassert> // For assert()
21 #include <cmath> // For fabs, round
22 #include <iostream> // For std::cout
23 #include <iomanip> // For std::setprecision
24 
25 using namespace std;
26 using namespace openshot;
27 
28 namespace openshot{
29 
30  // Check if the X coordinate of a given Point is lower than a given value
31  bool IsPointBeforeX(Point const & p, double const x) {
32  return p.co.X < x;
33  }
34 
35  // Linear interpolation between two points
36  double InterpolateLinearCurve(Point const & left, Point const & right, double const target) {
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);
41  }
42 
43  // Bezier interpolation between two points
44  double InterpolateBezierCurve(Point const & left, Point const & right, double const target, double const allowed_error) {
45  double const X_diff = right.co.X - left.co.X;
46  double const Y_diff = right.co.Y - left.co.Y;
47  Coordinate const p0 = left.co;
48  Coordinate const p1 = Coordinate(p0.X + left.handle_right.X * X_diff, p0.Y + left.handle_right.Y * Y_diff);
49  Coordinate const p2 = Coordinate(p0.X + right.handle_left.X * X_diff, p0.Y + right.handle_left.Y * Y_diff);
50  Coordinate const p3 = right.co;
51 
52  double t = 0.5;
53  double t_step = 0.25;
54  do {
55  // Bernstein polynoms
56  double B[4] = {1, 3, 3, 1};
57  double oneMinTExp = 1;
58  double tExp = 1;
59  for (int i = 0; i < 4; ++i, tExp *= t) {
60  B[i] *= tExp;
61  }
62  for (int i = 0; i < 4; ++i, oneMinTExp *= 1 - t) {
63  B[4 - i - 1] *= oneMinTExp;
64  }
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) {
68  return y;
69  }
70  if (x > target) {
71  t -= t_step;
72  }
73  else {
74  t += t_step;
75  }
76  t_step /= 2;
77  } while (true);
78  }
79  // Interpolate two points using the right Point's interpolation method
80  double InterpolateBetween(Point const & left, Point const & right, double target, double allowed_error) {
81  // check if target is outside of the extremities poits
82  // This can occur when moving fast the play head
83  if(left.co.X > target){
84  return left.co.Y;
85  }
86  if(target > right.co.X){
87  return right.co.Y;
88  }
89  switch (right.interpolation) {
90  case CONSTANT: return left.co.Y;
91  case LINEAR: return InterpolateLinearCurve(left, right, target);
92  case BEZIER: return InterpolateBezierCurve(left, right, target, allowed_error);
93  default: return InterpolateLinearCurve(left, right, target);
94  }
95  }
96 }
97 
98 template<typename Check>
99 int64_t SearchBetweenPoints(Point const & left, Point const & right, int64_t const current, Check 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;
104  double const value = InterpolateBetween(left, right, mid, 0.01);
105  if (check(round(value), current)) {
106  start = mid;
107  } else {
108  stop = mid - 1;
109  }
110  }
111  return start;
112 }
113 
114 // Constructor which sets the default point & coordinate at X=1
115 Keyframe::Keyframe(double value) {
116  // Add initial point
117  AddPoint(Point(1, value));
118 }
119 
120 // Constructor which takes a vector of Points
121 Keyframe::Keyframe(const std::vector<openshot::Point>& points) : Points(points) {};
122 
123 // Destructor
125  Points.clear();
126  Points.shrink_to_fit();
127 }
128 
129 // Add a new point on the key-frame. Each point has a primary coordinate,
130 // a left handle, and a right handle.
132  // candidate is not less (greater or equal) than the new point in
133  // the X coordinate.
134  std::vector<Point>::iterator candidate =
135  std::lower_bound(begin(Points), end(Points), p.co.X, IsPointBeforeX);
136  if (candidate == end(Points)) {
137  // New point X is greater than all other points' X, add to
138  // back.
139  Points.push_back(p);
140  } else if ((*candidate).co.X == p.co.X) {
141  // New point is at same X coordinate as some point, overwrite
142  // point.
143  *candidate = p;
144  } else {
145  // New point needs to be inserted before candidate; thus move
146  // candidate and all following one to the right and insert new
147  // point then where candidate was.
148  size_t const candidate_index = candidate - begin(Points);
149  Points.push_back(p); // Make space; could also be a dummy point. INVALIDATES candidate!
150  std::move_backward(begin(Points) + candidate_index, end(Points) - 1, end(Points));
151  Points[candidate_index] = p;
152  }
153 }
154 
155 // Add a new point on the key-frame, interpolate is optional (default: BEZIER)
156 void Keyframe::AddPoint(double x, double y, InterpolationType interpolate)
157 {
158  // Create a point
159  Point new_point(x, y, interpolate);
160 
161  // Add the point
162  AddPoint(new_point);
163 }
164 
165 // Get the index of a point by matching a coordinate
166 int64_t Keyframe::FindIndex(Point p) const {
167  // loop through points, and find a matching coordinate
168  for (std::vector<Point>::size_type x = 0; x < Points.size(); x++) {
169  // Get each point
170  Point existing_point = Points[x];
171 
172  // find a match
173  if (p.co.X == existing_point.co.X && p.co.Y == existing_point.co.Y) {
174  // Remove the matching point, and break out of loop
175  return x;
176  }
177  }
178 
179  // no matching point found
180  throw OutOfBoundsPoint("Invalid point requested", -1, Points.size());
181 }
182 
183 // Determine if point already exists
184 bool Keyframe::Contains(Point p) const {
185  std::vector<Point>::const_iterator i =
186  std::lower_bound(begin(Points), end(Points), p.co.X, IsPointBeforeX);
187  return i != end(Points) && i->co.X == p.co.X;
188 }
189 
190 // Get current point (or closest point) from the X coordinate (i.e. the frame number)
191 Point Keyframe::GetClosestPoint(Point p, bool useLeft) const {
192  if (Points.size() == 0) {
193  return Point(-1, -1);
194  }
195 
196  // Finds a point with an X coordinate which is "not less" (greater
197  // or equal) than the queried X coordinate.
198  std::vector<Point>::const_iterator candidate =
199  std::lower_bound(begin(Points), end(Points), p.co.X, IsPointBeforeX);
200 
201  if (candidate == end(Points)) {
202  // All points are before the queried point.
203  //
204  // Note: Behavior the same regardless of useLeft!
205  return Points.back();
206  }
207  if (candidate == begin(Points)) {
208  // First point is greater or equal to the queried point.
209  //
210  // Note: Behavior the same regardless of useLeft!
211  return Points.front();
212  }
213  if (useLeft) {
214  return *(candidate - 1);
215  } else {
216  return *candidate;
217  }
218 }
219 
220 // Get current point (or closest point to the right) from the X coordinate (i.e. the frame number)
222  return GetClosestPoint(p, false);
223 }
224 
225 // Get previous point (if any)
227 
228  // Lookup the index of this point
229  try {
230  int64_t index = FindIndex(p);
231 
232  // If not the 1st point
233  if (index > 0)
234  return Points[index - 1];
235  else
236  return Points[0];
237 
238  } catch (const OutOfBoundsPoint& e) {
239  // No previous point
240  return Point(-1, -1);
241  }
242 }
243 
244 // Get max point (by Y coordinate)
246  Point maxPoint(-1, -1);
247 
248  for (Point const & existing_point: Points) {
249  if (existing_point.co.Y >= maxPoint.co.Y) {
250  maxPoint = existing_point;
251  }
252  }
253 
254  return maxPoint;
255 }
256 
257 // Get the value at a specific index
258 double Keyframe::GetValue(int64_t index) const {
259  if (Points.empty()) {
260  return 0;
261  }
262  std::vector<Point>::const_iterator candidate =
263  std::lower_bound(begin(Points), end(Points), static_cast<double>(index), IsPointBeforeX);
264 
265  if (candidate == end(Points)) {
266  // index is behind last point
267  return Points.back().co.Y;
268  }
269  if (candidate == begin(Points)) {
270  // index is at or before first point
271  return Points.front().co.Y;
272  }
273  if (candidate->co.X == index) {
274  // index is directly on a point
275  return candidate->co.Y;
276  }
277  std::vector<Point>::const_iterator predecessor = candidate - 1;
278  return InterpolateBetween(*predecessor, *candidate, index, 0.01);
279 }
280 
281 // Get the rounded INT value at a specific index
282 int Keyframe::GetInt(int64_t index) const {
283  return int(round(GetValue(index)));
284 }
285 
286 // Get the rounded INT value at a specific index
287 int64_t Keyframe::GetLong(int64_t index) const {
288  return long(round(GetValue(index)));
289 }
290 
291 // Get the direction of the curve at a specific index (increasing or decreasing)
292 bool Keyframe::IsIncreasing(int index) const
293 {
294  if (index < 1 || (index + 1) >= GetLength()) {
295  return true;
296  }
297  std::vector<Point>::const_iterator candidate =
298  std::lower_bound(begin(Points), end(Points), static_cast<double>(index), IsPointBeforeX);
299  if (candidate == end(Points)) {
300  return false; // After the last point, thus constant.
301  }
302  if ((candidate->co.X == index) || (candidate == begin(Points))) {
303  ++candidate;
304  }
305  int64_t const value = GetLong(index);
306  do {
307  if (value < round(candidate->co.Y)) {
308  return true;
309  } else if (value > round(candidate->co.Y)) {
310  return false;
311  }
312  ++candidate;
313  } while (candidate != end(Points));
314  return false;
315 }
316 
317 // Generate JSON string of this object
318 std::string Keyframe::Json() const {
319 
320  // Return formatted string
321  return JsonValue().toStyledString();
322 }
323 
324 // Generate Json::Value for this object
325 Json::Value Keyframe::JsonValue() const {
326 
327  // Create root json object
328  Json::Value root;
329  root["Points"] = Json::Value(Json::arrayValue);
330 
331  // loop through points
332  for (const auto existing_point : Points) {
333  root["Points"].append(existing_point.JsonValue());
334  }
335 
336  // return JsonValue
337  return root;
338 }
339 
340 // Load JSON string into this object
341 void Keyframe::SetJson(const std::string value) {
342 
343  // Parse JSON string into JSON objects
344  try
345  {
346  const Json::Value root = openshot::stringToJson(value);
347  // Set all values that match
348  SetJsonValue(root);
349  }
350  catch (const std::exception& e)
351  {
352  // Error parsing JSON (or missing keys)
353  throw InvalidJSON("JSON is invalid (missing keys or invalid data types)");
354  }
355 }
356 
357 // Load Json::Value into this object
358 void Keyframe::SetJsonValue(const Json::Value root) {
359  // Clear existing points
360  Points.clear();
361  Points.shrink_to_fit();
362 
363  if (!root["Points"].isNull())
364  // loop through points
365  for (const auto existing_point : root["Points"]) {
366  // Create Point
367  Point p;
368 
369  // Load Json into Point
370  p.SetJsonValue(existing_point);
371 
372  // Add Point to Keyframe
373  AddPoint(p);
374  }
375 }
376 
377 // Get the fraction that represents how many times this value is repeated in the curve
378 // This is depreciated and will be removed soon.
379 Fraction Keyframe::GetRepeatFraction(int64_t index) const {
380  // Frame numbers (index) outside of the "defined" range of this
381  // keyframe result in a 1/1 default value.
382  if (index < 1 || (index + 1) >= GetLength()) {
383  return Fraction(1,1);
384  }
385  assert(Points.size() > 1); // Due to ! ((index + 1) >= GetLength) there are at least two points!
386 
387  // First, get the value at the given frame and the closest point
388  // to the right.
389  int64_t const current_value = GetLong(index);
390  std::vector<Point>::const_iterator const candidate =
391  std::lower_bound(begin(Points), end(Points), static_cast<double>(index), IsPointBeforeX);
392  assert(candidate != end(Points)); // Due to the (index + 1) >= GetLength check above!
393 
394  // Calculate how many of the next values are going to be the same:
395  int64_t next_repeats = 0;
396  std::vector<Point>::const_iterator i = candidate;
397  // If the index (frame number) is the X coordinate of the closest
398  // point, then look at the segment to the right; the "current"
399  // segement is not interesting because we're already at the last
400  // value of it.
401  if (i->co.X == index) {
402  ++i;
403  }
404  // Skip over "constant" (when rounded) segments.
405  bool all_constant = true;
406  for (; i != end(Points); ++i) {
407  if (current_value != round(i->co.Y)) {
408  all_constant = false;
409  break;
410  }
411  }
412  if (! all_constant) {
413  // Found a point which defines a segment which will give a
414  // different value than the current value. This means we
415  // moved at least one segment to the right, thus we cannot be
416  // at the first point.
417  assert(i != begin(Points));
418  Point const left = *(i - 1);
419  Point const right = *i;
420  int64_t change_at;
421  if (current_value < round(i->co.Y)) {
422  change_at = SearchBetweenPoints(left, right, current_value, std::less_equal<double>{});
423  } else {
424  assert(current_value > round(i->co.Y));
425  change_at = SearchBetweenPoints(left, right, current_value, std::greater_equal<double>{});
426  }
427  next_repeats = change_at - index;
428  } else {
429  // All values to the right are the same!
430  next_repeats = Points.back().co.X - index;
431  }
432 
433  // Now look to the left, to the previous values.
434  all_constant = true;
435  i = candidate;
436  if (i != begin(Points)) {
437  // The binary search below assumes i to be the left point;
438  // candidate is the right point of the current segment
439  // though. So change this if possible. If this branch is NOT
440  // taken, then we're at/before the first point and all is
441  // constant!
442  --i;
443  }
444  int64_t previous_repeats = 0;
445  // Skip over constant (when rounded) segments!
446  for (; i != begin(Points); --i) {
447  if (current_value != round(i->co.Y)) {
448  all_constant = false;
449  break;
450  }
451  }
452  // Special case when skipped until the first point, but the first
453  // point is actually different. Will not happen if index is
454  // before the first point!
455  if (current_value != round(i->co.Y)) {
456  assert(i != candidate);
457  all_constant = false;
458  }
459  if (! all_constant) {
460  // There are at least two points, and we're not at the end,
461  // thus the following is safe!
462  Point const left = *i;
463  Point const right = *(i + 1);
464  int64_t change_at;
465  if (current_value > round(left.co.Y)) {
466  change_at = SearchBetweenPoints(left, right, current_value, std::less<double>{});
467  } else {
468  assert(current_value < round(left.co.Y));
469  change_at = SearchBetweenPoints(left, right, current_value, std::greater<double>{});
470  }
471  previous_repeats = index - change_at;
472  } else {
473  // Every previous value is the same (rounded) as the current
474  // value.
475  previous_repeats = index;
476  }
477  int64_t total_repeats = previous_repeats + next_repeats;
478  return Fraction(previous_repeats, total_repeats);
479 }
480 
481 // Get the change in Y value (from the previous Y value)
482 double Keyframe::GetDelta(int64_t index) const {
483  if (index < 1) return 0;
484  if (index == 1 && ! Points.empty()) return Points[0].co.Y;
485  if (index >= GetLength()) return 0;
486  return GetLong(index) - GetLong(index - 1);
487 }
488 
489 // Get a point at a specific index
490 Point const & Keyframe::GetPoint(int64_t index) const {
491  // Is index a valid point?
492  if (index >= 0 && index < (int64_t)Points.size())
493  return Points[index];
494  else
495  // Invalid index
496  throw OutOfBoundsPoint("Invalid point requested", index, Points.size());
497 }
498 
499 // Get the number of values (i.e. coordinates on the X axis)
500 int64_t Keyframe::GetLength() const {
501  if (Points.empty()) return 0;
502  if (Points.size() == 1) return 1;
503  return round(Points.back().co.X) + 1;
504 }
505 
506 // Get the number of points (i.e. # of points)
507 int64_t Keyframe::GetCount() const {
508 
509  return Points.size();
510 }
511 
512 // Remove a point by matching a coordinate
514  // loop through points, and find a matching coordinate
515  for (std::vector<Point>::size_type x = 0; x < Points.size(); x++) {
516  // Get each point
517  Point existing_point = Points[x];
518 
519  // find a match
520  if (p.co.X == existing_point.co.X && p.co.Y == existing_point.co.Y) {
521  // Remove the matching point, and break out of loop
522  Points.erase(Points.begin() + x);
523  return;
524  }
525  }
526 
527  // no matching point found
528  throw OutOfBoundsPoint("Invalid point requested", -1, Points.size());
529 }
530 
531 // Remove a point by index
532 void Keyframe::RemovePoint(int64_t index) {
533  // Is index a valid point?
534  if (index >= 0 && index < (int64_t)Points.size())
535  {
536  // Remove a specific point by index
537  Points.erase(Points.begin() + index);
538  }
539  else
540  // Invalid index
541  throw OutOfBoundsPoint("Invalid point requested", index, Points.size());
542 }
543 
544 // Replace an existing point with a new point
545 void Keyframe::UpdatePoint(int64_t index, Point p) {
546  // Remove matching point
547  RemovePoint(index);
548 
549  // Add new point
550  AddPoint(p);
551 }
552 
553 void Keyframe::PrintPoints(std::ostream* out) const {
554  *out << std::right << std::setprecision(4) << std::setfill(' ');
555  for (const auto& p : Points) {
556  *out << std::defaultfloat
557  << std::setw(6) << p.co.X
558  << std::setw(14) << std::fixed << p.co.Y
559  << '\n';
560  }
561  *out << std::flush;
562 }
563 
564 void Keyframe::PrintValues(std::ostream* out) const {
565  // Column widths
566  std::vector<int> w{10, 12, 8, 11, 19};
567 
568  *out << std::right << std::setfill(' ') << std::setprecision(4);
569  // Headings
570  *out << "│"
571  << std::setw(w[0]) << "Frame# (X)" << " │"
572  << std::setw(w[1]) << "Y Value" << " │"
573  << std::setw(w[2]) << "Delta Y" << " │ "
574  << std::setw(w[3]) << "Increasing?" << " │ "
575  << std::setw(w[4]) << std::left << "Repeat Fraction" << std::right
576  << "│\n";
577  // Divider
578  *out << "├───────────"
579  << "┼─────────────"
580  << "┼─────────"
581  << "┼─────────────"
582  << "┼────────────────────┤\n";
583 
584  for (int64_t i = 1; i < GetLength(); ++i) {
585  *out << "│"
586  << std::setw(w[0]-2) << std::defaultfloat << i
587  << (Contains(Point(i, 1)) ? " *" : " ") << " │"
588  << std::setw(w[1]) << std::fixed << GetValue(i) << " │"
589  << std::setw(w[2]) << std::defaultfloat << std::showpos
590  << GetDelta(i) << " │ " << std::noshowpos
591  << std::setw(w[3])
592  << (IsIncreasing(i) ? "true" : "false") << " │ "
593  << std::setw(w[4]) << std::left << GetRepeatFraction(i)
594  << std::right << "│\n";
595  }
596  *out << " * = Keyframe point (non-interpolated)\n";
597  *out << std::flush;
598 }
599 
600 
601 // Scale all points by a percentage (good for evenly lengthening or shortening an openshot::Keyframe)
602 // 1.0 = same size, 1.05 = 5% increase, etc...
603 void Keyframe::ScalePoints(double scale)
604 {
605  // TODO: What if scale is small so that two points land on the
606  // same X coordinate?
607  // TODO: What if scale < 0?
608 
609  // Loop through each point (skipping the 1st point)
610  for (std::vector<Point>::size_type point_index = 1; point_index < Points.size(); point_index++) {
611  // Scale X value
612  Points[point_index].co.X = round(Points[point_index].co.X * scale);
613  }
614 }
615 
616 // Flip all the points in this openshot::Keyframe (useful for reversing an effect or transition, etc...)
618  for (std::vector<Point>::size_type point_index = 0, reverse_index = Points.size() - 1; point_index < reverse_index; point_index++, reverse_index--) {
619  // Flip the points
620  using std::swap;
621  swap(Points[point_index].co.Y, Points[reverse_index].co.Y);
622  // TODO: check that this has the desired effect even with
623  // regards to handles!
624  }
625 }
double GetDelta(int64_t index) const
Get the change in Y value (from the previous Y value)
Definition: KeyFrame.cpp:482
A Cartesian coordinate (X, Y) used in the Keyframe animation system.
Definition: Coordinate.h:38
void PrintValues(std::ostream *out=&std::cout) const
Print just the Y value of the point&#39;s primary coordinate.
Definition: KeyFrame.cpp:564
Point GetMaxPoint() const
Get max point (by Y coordinate)
Definition: KeyFrame.cpp:245
void FlipPoints()
Flip all the points in this openshot::Keyframe (useful for reversing an effect or transition...
Definition: KeyFrame.cpp:617
Point const & GetPoint(int64_t index) const
Get a point at a specific index.
Definition: KeyFrame.cpp:490
void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
Definition: Point.cpp:104
int64_t GetLong(int64_t index) const
Get the rounded LONG value at a specific index.
Definition: KeyFrame.cpp:287
void PrintPoints(std::ostream *out=&std::cout) const
Print a list of points.
Definition: KeyFrame.cpp:553
Bezier curves are quadratic curves, which create a smooth curve.
Definition: Point.h:29
InterpolationType interpolation
This is the interpolation mode.
Definition: Point.h:69
Coordinate handle_right
This is the right handle coordinate (in percentages from 0 to 1)
Definition: Point.h:68
Coordinate handle_left
This is the left handle coordinate (in percentages from 0 to 1)
Definition: Point.h:67
void ScalePoints(double scale)
Definition: KeyFrame.cpp:603
A Point is the basic building block of a key-frame curve.
Definition: Point.h:64
Point GetPreviousPoint(Point p) const
Get previous point (.
Definition: KeyFrame.cpp:226
const Json::Value stringToJson(const std::string value)
Definition: Json.cpp:16
bool IsIncreasing(int index) const
Get the direction of the curve at a specific index (increasing or decreasing)
Definition: KeyFrame.cpp:292
Header file for the Keyframe class.
bool Contains(Point p) const
Does this keyframe contain a specific point.
Definition: KeyFrame.cpp:184
double InterpolateBezierCurve(Point const &left, Point const &right, double const target, double const allowed_error)
Bezier interpolation between two points.
Definition: KeyFrame.cpp:44
void UpdatePoint(int64_t index, Point p)
Replace an existing point with a new point.
Definition: KeyFrame.cpp:545
int GetInt(int64_t index) const
Get the rounded INT value at a specific index.
Definition: KeyFrame.cpp:282
double InterpolateLinearCurve(Point const &left, Point const &right, double const target)
Linear interpolation between two points.
Definition: KeyFrame.cpp:36
void AddPoint(Point p)
Add a new point on the key-frame. Each point has a primary coordinate, a left handle, and a right handle.
Definition: KeyFrame.cpp:131
Header file for all Exception classes.
double Y
The Y value of the coordinate (usually representing the value of the property being animated) ...
Definition: Coordinate.h:41
Point GetClosestPoint(Point p) const
Get current point (or closest point to the right) from the X coordinate (i.e. the frame number) ...
Definition: KeyFrame.cpp:221
void RemovePoint(Point p)
Remove a point by matching a coordinate.
Definition: KeyFrame.cpp:513
This class represents a fraction.
Definition: Fraction.h:30
double InterpolateBetween(Point const &left, Point const &right, double target, double allowed_error)
Interpolate two points using the right Point&#39;s interpolation method.
Definition: KeyFrame.cpp:80
double X
The X value of the coordinate (usually representing the frame #)
Definition: Coordinate.h:40
int64_t SearchBetweenPoints(Point const &left, Point const &right, int64_t const current, Check check)
Definition: KeyFrame.cpp:99
InterpolationType
This controls how a Keyframe uses this point to interpolate between two points.
Definition: Point.h:28
bool IsPointBeforeX(Point const &p, double const x)
Check if the X coordinate of a given Point is lower than a given value.
Definition: KeyFrame.cpp:31
void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
Definition: KeyFrame.cpp:358
if(!codec) codec
This namespace is the default namespace for all code in the openshot library.
Definition: Compressor.h:28
Json::Value JsonValue() const
Generate Json::Value for this object.
Definition: KeyFrame.cpp:325
Linear curves are angular, straight lines between two points.
Definition: Point.h:30
Coordinate co
This is the primary coordinate.
Definition: Point.h:66
int64_t FindIndex(Point p) const
Get the index of a point by matching a coordinate.
Definition: KeyFrame.cpp:166
Exception for invalid JSON.
Definition: Exceptions.h:217
int64_t GetCount() const
Get the number of points (i.e. # of points)
Definition: KeyFrame.cpp:507
double GetValue(int64_t index) const
Get the value at a specific index.
Definition: KeyFrame.cpp:258
~Keyframe()
Destructor.
Definition: KeyFrame.cpp:124
Exception for an out of bounds key-frame point.
Definition: Exceptions.h:324
void SetJson(const std::string value)
Load JSON string into this object.
Definition: KeyFrame.cpp:341
Fraction GetRepeatFraction(int64_t index) const
Get the fraction that represents how many times this value is repeated in the curve.
Definition: KeyFrame.cpp:379
int64_t GetLength() const
Definition: KeyFrame.cpp:500
Constant curves jump from their previous position to a new one (with no interpolation).
Definition: Point.h:31
std::string Json() const
Generate JSON string of this object.
Definition: KeyFrame.cpp:318