28 #include "../include/KeyFrame.h"
31 using namespace openshot;
36 void Keyframe::ReorderPoints() {
38 for (int64_t x = 0; x < Points.size(); x++) {
39 int64_t compare_index = x;
40 int64_t smallest_index = x;
42 for (int64_t compare_index = x + 1; compare_index < Points.size(); compare_index++) {
43 if (Points[compare_index].co.X < Points[smallest_index].co.X) {
44 smallest_index = compare_index;
49 if (smallest_index != compare_index) {
50 swap(Points[compare_index], Points[smallest_index]);
56 Keyframe::Keyframe(
double value) : needs_update(true) {
58 CreateFactorialTable();
67 CreateFactorialTable();
78 if (closest.
co.
X == p.
co.
X)
103 Point new_point(x, y, interpolate);
112 for (int64_t x = 0; x <
Points.size(); x++) {
117 if (p.
co.
X == existing_point.
co.
X && p.
co.
Y == existing_point.
co.
Y) {
130 for (int64_t x = 0; x <
Points.size(); x++) {
135 if (p.
co.
X == existing_point.
co.
X) {
147 Point closest(-1, -1);
150 for (int64_t x = 0; x <
Points.size(); x++) {
155 if (existing_point.
co.
X >= p.
co.
X && !useLeft) {
157 closest = existing_point;
159 }
else if (existing_point.
co.
X < p.
co.
X && useLeft) {
161 closest = existing_point;
162 }
else if (existing_point.
co.
X >= p.
co.
X && useLeft) {
169 if (closest.
co.
X == -1) {
173 else if (
Points.size() > 0)
202 return Point(-1, -1);
208 Point maxPoint(-1, -1);
211 for (int64_t x = 0; x <
Points.size(); x++) {
216 if (existing_point.
co.
Y >= maxPoint.
co.
Y) {
218 maxPoint = existing_point;
233 if (index >= 0 && index <
Values.size())
236 else if (index < 0 &&
Values.size() > 0)
255 if (index >= 0 && index <
Values.size())
257 return int(round(
Values[index].Y));
258 else if (index < 0 &&
Values.size() > 0)
260 return int(round(
Values[0].Y));
277 if (index >= 0 && index <
Values.size())
279 return long(round(
Values[index].Y));
280 else if (index < 0 &&
Values.size() > 0)
282 return long(round(
Values[0].Y));
299 if (index >= 1 && (index + 1) <
Values.size()) {
300 int64_t current_value =
GetLong(index);
301 int64_t previous_value = 0;
302 int64_t next_value = 0;
303 int64_t previous_repeats = 0;
304 int64_t next_repeats = 0;
307 for (vector<Coordinate>::iterator backwards_it =
Values.begin() + index; backwards_it !=
Values.begin(); backwards_it--) {
308 previous_value = long(round((*backwards_it).Y));
309 if (previous_value == current_value) {
319 for (vector<Coordinate>::iterator forwards_it =
Values.begin() + (index + 1); forwards_it !=
Values.end(); forwards_it++) {
320 next_value = long(round((*forwards_it).Y));
321 if (next_value == current_value) {
330 if (current_value < next_value) {
334 else if (current_value >= next_value) {
356 root[
"Points"] = Json::Value(Json::arrayValue);
359 for (
int x = 0; x <
Points.size(); x++) {
362 root[
"Points"].append(existing_point.
JsonValue());
375 bool success = reader.parse( value, root );
378 throw InvalidJSON(
"JSON could not be parsed (or is invalid)",
"");
388 throw InvalidJSON(
"JSON is invalid (missing keys or invalid data types)",
"");
401 if (!root[
"Points"].isNull())
403 for (int64_t x = 0; x < root[
"Points"].size(); x++) {
405 Json::Value existing_point = root[
"Points"][(Json::UInt) x];
427 if (index >= 1 && (index + 1) <
Values.size()) {
428 int64_t current_value =
GetLong(index);
429 int64_t previous_value = 0;
430 int64_t next_value = 0;
431 int64_t previous_repeats = 0;
432 int64_t next_repeats = 0;
435 for (vector<Coordinate>::iterator backwards_it =
Values.begin() + index; backwards_it !=
Values.begin(); backwards_it--) {
436 previous_value = long(round((*backwards_it).Y));
437 if (previous_value == current_value) {
447 for (vector<Coordinate>::iterator forwards_it =
Values.begin() + (index + 1); forwards_it !=
Values.end(); forwards_it++) {
448 next_value = long(round((*forwards_it).Y));
449 if (next_value == current_value) {
458 int64_t total_repeats = previous_repeats + next_repeats;
459 return Fraction(previous_repeats, total_repeats);
474 if (index >= 1 && (index + 1) <
Values.size()) {
475 int64_t current_value =
GetLong(index);
476 int64_t previous_value = 0;
477 int64_t next_value = 0;
478 int64_t previous_repeats = 0;
479 int64_t next_repeats = 0;
482 for (vector<Coordinate>::iterator backwards_it =
Values.begin() + index; backwards_it !=
Values.begin(); backwards_it--) {
483 previous_value = long(round((*backwards_it).Y));
484 if (previous_value == current_value) {
494 for (vector<Coordinate>::iterator forwards_it =
Values.begin() + (index + 1); forwards_it !=
Values.end(); forwards_it++) {
495 next_value = long(round((*forwards_it).Y));
496 if (next_value == current_value) {
506 if (current_value == previous_value)
509 if (previous_repeats == 1)
510 return current_value - previous_value;
522 if (index >= 0 && index <
Points.size())
552 for (int64_t x = 0; x <
Points.size(); x++) {
557 if (p.
co.
X == existing_point.
co.
X && p.
co.
Y == existing_point.
co.
Y) {
574 if (index >= 0 && index <
Points.size())
603 cout << fixed << setprecision(4);
604 for (vector<Point>::iterator it =
Points.begin(); it !=
Points.end(); it++) {
606 cout << p.
co.
X <<
"\t" << p.
co.
Y << endl;
615 cout << fixed << setprecision(4);
616 cout <<
"Frame Number (X)\tValue (Y)\tIs Increasing\tRepeat Numerator\tRepeat Denominator\tDelta (Y Difference)" << endl;
618 for (vector<Coordinate>::iterator it =
Values.begin() + 1; it !=
Values.end(); it++) {
626 #pragma omp critical (keyframe_process)
629 if (needs_update &&
Points.size() == 0) {
633 else if (needs_update &&
Points.size() > 0)
642 for (int64_t x = 0; x < p1.
co.
X; x++)
651 for (int64_t x = 0; x <
Points.size() - 1; x++) {
656 ProcessSegment(x, p1, p2);
661 needs_update =
false;
665 void Keyframe::ProcessSegment(
int Segment,
Point p1,
Point p2) {
667 int64_t number_of_values = round(p2.
co.
X) - round(p1.
co.
X);
670 if (number_of_values == 0)
681 double current_value = p1.
co.
Y;
682 double value_difference = p2.
co.
Y - p1.
co.
Y;
683 double value_increment = 0.0f;
687 value_increment = value_difference / (double) (number_of_values);
694 current_value += value_increment;
697 for (int64_t x = 0; x < number_of_values; x++) {
702 current_value += value_increment;
715 number_of_values *= 4;
718 double X_diff = p2.
co.
X - p1.
co.
X;
719 double Y_diff = p2.
co.
Y - p1.
co.
Y;
721 vector<Coordinate> segment_coordinates;
722 segment_coordinates.push_back(p1.
co);
725 segment_coordinates.push_back(p2.
co);
727 vector<Coordinate> raw_coordinates;
728 int64_t npts = segment_coordinates.size();
729 int64_t icount, jcount;
737 step = (double) 1.0 / (number_of_values - 1);
739 for (int64_t i1 = 0; i1 < number_of_values; i1++) {
740 if ((1.0 - t) < 5
e-6)
748 for (int64_t i = 0; i < npts; i++) {
750 double basis = Bernstein(npts - 1, i, t);
751 new_x += basis * co.
X;
752 new_y += basis * co.
Y;
759 raw_coordinates.push_back(current_value);
768 int64_t current_frame = p1.
co.
X;
769 double current_value = p1.
co.
Y;
770 for (int64_t i = 0; i < raw_coordinates.size(); i++)
775 if (current_frame == round(raw.
X))
777 current_value = raw.
Y;
781 int64_t number_of_missing = round(raw.
X) - current_frame;
782 for (int64_t missing = 0; missing < number_of_missing; missing++)
785 Coordinate new_coord(current_frame, current_value);
787 if (Segment == 0 || Segment > 0 && current_frame > p1.
co.
X)
789 Values.push_back(new_coord);
796 current_value = raw.
Y;
801 Coordinate new_coord(current_frame, current_value);
802 Values.push_back(new_coord);
817 for (int64_t x = 0; x < number_of_values; x++) {
818 if (x < (number_of_values - 1)) {
835 void Keyframe::CreateFactorialTable() {
837 FactorialLookup[0] = 1.0;
838 FactorialLookup[1] = 1.0;
839 FactorialLookup[2] = 2.0;
840 FactorialLookup[3] = 6.0;
844 double Keyframe::Factorial(int64_t n) {
845 assert(n >= 0 && n <= 3);
846 return FactorialLookup[n];
850 double Keyframe::Ni(int64_t n, int64_t i) {
852 double a1 = Factorial(n);
853 double a2 = Factorial(i);
854 double a3 = Factorial(n - i);
860 double Keyframe::Bernstein(int64_t n, int64_t i,
double t) {
866 if (t == 0.0 && i == 0)
871 if (n == i && t == 1.0)
874 tni = pow((1 - t), (n - i));
877 basis = Ni(n, i) * ti * tni;
886 for (int64_t point_index = 0; point_index <
Points.size(); point_index++) {
888 if (point_index == 0)
892 Points[point_index].co.X = round(
Points[point_index].co.X * scale);
903 vector<Point> FlippedPoints;
904 for (int64_t point_index = 0, reverse_index =
Points.size() - 1; point_index <
Points.size(); point_index++, reverse_index--) {
908 FlippedPoints.push_back(p);
912 Points.swap(FlippedPoints);
vector< Coordinate > Values
Vector of all Values (i.e. the processed coordinates from the curve)
Point GetMaxPoint()
Get max point (by Y coordinate)
Json::Value JsonValue()
Generate Json::JsonValue for this object.
This class represents a Cartesian coordinate (X, Y) used in the Keyframe animation system...
int64_t GetCount()
Get the number of points (i.e. # of points)
int num
Numerator for the fraction.
Keyframe()
Default constructor for the Keyframe class.
void FlipPoints()
Flip all the points in this openshot::Keyframe (useful for reversing an effect or transition...
Json::Value JsonValue()
Generate Json::JsonValue for this object.
Bezier curves are quadratic curves, which create a smooth curve.
Point & GetPoint(int64_t index)
Get a point at a specific index.
InterpolationType interpolation
This is the interpolation mode.
Coordinate handle_right
This is the right handle coordinate (in percentages from 0 to 1)
bool Contains(Point p)
Does this keyframe contain a specific point.
Coordinate handle_left
This is the left handle coordinate (in percentages from 0 to 1)
void ScalePoints(double scale)
A Point is the basic building block of a key-frame curve.
Point GetPreviousPoint(Point p)
Get previous point (.
void UpdatePoint(int64_t index, Point p)
Replace an existing point with a new point.
void SetJsonValue(Json::Value root)
Load Json::JsonValue into this object.
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.
double Y
The Y value of the coordinate (usually representing the value of the property being animated) ...
void PrintValues()
Print just the Y value of the point's primary coordinate.
void RemovePoint(Point p)
Remove a point by matching a coordinate.
bool IsIncreasing(int index)
Get the direction of the curve at a specific index (increasing or decreasing)
This class represents a fraction.
int GetInt(int64_t index)
Get the rounded INT value at a specific index.
int64_t FindIndex(Point p)
Get the index of a point by matching a coordinate.
void Process()
Calculate all of the values for this keyframe.
Fraction GetRepeatFraction(int64_t index)
Get the fraction that represents how many times this value is repeated in the curve.
vector< Point > Points
Vector of all Points.
double X
The X value of the coordinate (usually representing the frame #)
double GetDelta(int64_t index)
Get the change in Y value (from the previous Y value)
Point GetClosestPoint(Point p)
Get current point (or closest point to the right) from the X coordinate (i.e. the frame number) ...
InterpolationType
This controls how a Keyframe uses this point to interpolate between two points.
double GetValue(int64_t index)
Get the value at a specific index.
string Json()
Get and Set JSON methods.
Linear curves are angular, straight lines between two points.
Coordinate co
This is the primary coordinate.
Exception for invalid JSON.
int64_t GetLong(int64_t index)
Get the rounded LONG value at a specific index.
Exception for an out of bounds key-frame point.
void PrintPoints()
Print a list of points.
void SetJsonValue(Json::Value root)
Load Json::JsonValue into this object.
void SetJson(string value)
Load JSON string into this object.
int den
Denominator for the fraction.
Constant curves jump from their previous position to a new one (with no interpolation).