OpenShot Library | libopenshot 0.3.2
Loading...
Searching...
No Matches
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
25using namespace std;
26using namespace openshot;
27
28namespace 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
98template<typename Check>
99int64_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
115Keyframe::Keyframe(double value) {
116 // Add initial point
117 AddPoint(Point(1, value));
118}
119
120// Constructor which takes a vector of Points
121Keyframe::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)
156void 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
166int64_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
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)
191Point 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
258double 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
282int Keyframe::GetInt(int64_t index) const {
283 return int(round(GetValue(index)));
284}
285
286// Get the rounded INT value at a specific index
287int64_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)
292bool 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
318std::string Keyframe::Json() const {
319
320 // Return formatted string
321 return JsonValue().toStyledString();
322}
323
324// Generate Json::Value for this object
325Json::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
341void 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
358void 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.
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)
482double 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
490Point 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)
500int64_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)
507int64_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
532void 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
545void Keyframe::UpdatePoint(int64_t index, Point p) {
546 // Remove matching point
547 RemovePoint(index);
548
549 // Add new point
550 AddPoint(p);
551}
552
553void 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
564void 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...
603void 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}
Header file for all Exception classes.
int64_t SearchBetweenPoints(Point const &left, Point const &right, int64_t const current, Check check)
Definition: KeyFrame.cpp:99
Header file for the Keyframe class.
A Cartesian coordinate (X, Y) used in the Keyframe animation system.
Definition: Coordinate.h:38
double X
The X value of the coordinate (usually representing the frame #)
Definition: Coordinate.h:40
double Y
The Y value of the coordinate (usually representing the value of the property being animated)
Definition: Coordinate.h:41
This class represents a fraction.
Definition: Fraction.h:30
Exception for invalid JSON.
Definition: Exceptions.h:218
int64_t FindIndex(Point p) const
Get the index of a point by matching a coordinate.
Definition: KeyFrame.cpp:166
void RemovePoint(Point p)
Remove a point by matching a coordinate.
Definition: KeyFrame.cpp:513
void SetJson(const std::string value)
Load JSON string into this object.
Definition: KeyFrame.cpp:341
bool Contains(Point p) const
Does this keyframe contain a specific point.
Definition: KeyFrame.cpp:184
~Keyframe()
Destructor.
Definition: KeyFrame.cpp:124
void PrintValues(std::ostream *out=&std::cout) const
Print just the Y value of the point's primary coordinate.
Definition: KeyFrame.cpp:564
Point GetMaxPoint() const
Get max point (by Y coordinate)
Definition: KeyFrame.cpp:245
int GetInt(int64_t index) const
Get the rounded INT value at a specific index.
Definition: KeyFrame.cpp:282
void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
Definition: KeyFrame.cpp:358
void AddPoint(Point p)
Add a new point on the key-frame. Each point has a primary coordinate, a left handle,...
Definition: KeyFrame.cpp:131
double GetDelta(int64_t index) const
Get the change in Y value (from the previous Y value)
Definition: KeyFrame.cpp:482
Point const & GetPoint(int64_t index) const
Get a point at a specific index.
Definition: KeyFrame.cpp:490
int64_t GetLength() const
Definition: KeyFrame.cpp:500
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
void PrintPoints(std::ostream *out=&std::cout) const
Print a list of points.
Definition: KeyFrame.cpp:553
Point GetPreviousPoint(Point p) const
Get previous point (.
Definition: KeyFrame.cpp:226
int64_t GetLong(int64_t index) const
Get the rounded LONG value at a specific index.
Definition: KeyFrame.cpp:287
void UpdatePoint(int64_t index, Point p)
Replace an existing point with a new point.
Definition: KeyFrame.cpp:545
void ScalePoints(double scale)
Definition: KeyFrame.cpp:603
std::string Json() const
Generate JSON string of this object.
Definition: KeyFrame.cpp:318
double GetValue(int64_t index) const
Get the value at a specific index.
Definition: KeyFrame.cpp:258
Json::Value JsonValue() const
Generate Json::Value for this object.
Definition: KeyFrame.cpp:325
void FlipPoints()
Flip all the points in this openshot::Keyframe (useful for reversing an effect or transition,...
Definition: KeyFrame.cpp:617
Keyframe()=default
Default constructor for the Keyframe class.
bool IsIncreasing(int index) const
Get the direction of the curve at a specific index (increasing or decreasing)
Definition: KeyFrame.cpp:292
int64_t GetCount() const
Get the number of points (i.e. # of points)
Definition: KeyFrame.cpp:507
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
Exception for an out of bounds key-frame point.
Definition: Exceptions.h:325
A Point is the basic building block of a key-frame curve.
Definition: Point.h:64
Coordinate handle_left
This is the left handle coordinate (in percentages from 0 to 1)
Definition: Point.h:67
Coordinate co
This is the primary coordinate.
Definition: Point.h:66
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
void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
Definition: Point.cpp:104
This namespace is the default namespace for all code in the openshot library.
Definition: Compressor.h:29
double InterpolateLinearCurve(Point const &left, Point const &right, double const target)
Linear interpolation between two points.
Definition: KeyFrame.cpp:36
double InterpolateBezierCurve(Point const &left, Point const &right, double const target, double const allowed_error)
Bezier interpolation between two points.
Definition: KeyFrame.cpp:44
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
double InterpolateBetween(Point const &left, Point const &right, double target, double allowed_error)
Interpolate two points using the right Point's interpolation method.
Definition: KeyFrame.cpp:80
const Json::Value stringToJson(const std::string value)
Definition: Json.cpp:16
InterpolationType
This controls how a Keyframe uses this point to interpolate between two points.
Definition: Point.h:28
@ CONSTANT
Constant curves jump from their previous position to a new one (with no interpolation).
Definition: Point.h:31
@ BEZIER
Bezier curves are quadratic curves, which create a smooth curve.
Definition: Point.h:29
@ LINEAR
Linear curves are angular, straight lines between two points.
Definition: Point.h:30