Removed
Link Here
|
1 |
--- src/KeyFrame.cpp.orig 2023-04-19 22:01:02 UTC |
2 |
+++ src/KeyFrame.cpp |
3 |
@@ -15,12 +15,12 @@ |
4 |
|
5 |
#include <algorithm> // For std::lower_bound, std::move_backward |
6 |
#include <functional> // For std::less, std::less_equal, etc… |
7 |
-#include <utility> // For std::swap |
8 |
-#include <numeric> // For std::accumulate |
9 |
-#include <cassert> // For assert() |
10 |
-#include <cmath> // For fabs, round |
11 |
-#include <iostream> // For std::cout |
12 |
-#include <iomanip> // For std::setprecision |
13 |
+#include <utility> // For std::swap |
14 |
+#include <numeric> // For std::accumulate |
15 |
+#include <cassert> // For assert() |
16 |
+#include <cmath> // For fabs, round |
17 |
+#include <iostream> // For std::cout |
18 |
+#include <iomanip> // For std::setprecision |
19 |
|
20 |
using namespace std; |
21 |
using namespace openshot; |
22 |
@@ -122,8 +122,8 @@ Keyframe::Keyframe(const std::vector<openshot::Point>& |
23 |
|
24 |
// Destructor |
25 |
Keyframe::~Keyframe() { |
26 |
- Points.clear(); |
27 |
- Points.shrink_to_fit(); |
28 |
+ Points.clear(); |
29 |
+ Points.shrink_to_fit(); |
30 |
} |
31 |
|
32 |
// Add a new point on the key-frame. Each point has a primary coordinate, |
33 |
@@ -291,41 +291,27 @@ int64_t Keyframe::GetLong(int64_t index) const { |
34 |
// Get the direction of the curve at a specific index (increasing or decreasing) |
35 |
bool Keyframe::IsIncreasing(int index) const |
36 |
{ |
37 |
- if (index <= 1) { |
38 |
- // Determine direction of frame 1 (and assume previous frames have same direction) |
39 |
- index = 1; |
40 |
- } else if (index >= GetLength()) { |
41 |
- // Determine direction of last valid frame # (and assume next frames have same direction) |
42 |
- index = GetLength() - 1; |
43 |
+ if (index < 1 || (index + 1) >= GetLength()) { |
44 |
+ return true; |
45 |
} |
46 |
- |
47 |
- // Get current index value |
48 |
- const double current_value = GetValue(index); |
49 |
- |
50 |
- // Iterate from current index to next significant value change |
51 |
- int attempts = 1; |
52 |
- while (attempts < 600 && index + attempts <= GetLength()) { |
53 |
- // Get next value |
54 |
- const double next_value = GetValue(index + attempts); |
55 |
- |
56 |
- // Is value significantly different |
57 |
- const double diff = next_value - current_value; |
58 |
- if (fabs(diff) > 0.0001) { |
59 |
- if (diff < 0.0) { |
60 |
- // Decreasing value found next |
61 |
- return false; |
62 |
- } else { |
63 |
- // Increasing value found next |
64 |
- return true; |
65 |
- } |
66 |
- } |
67 |
- |
68 |
- // increment attempt |
69 |
- attempts++; |
70 |
+ std::vector<Point>::const_iterator candidate = |
71 |
+ std::lower_bound(begin(Points), end(Points), static_cast<double>(index), IsPointBeforeX); |
72 |
+ if (candidate == end(Points)) { |
73 |
+ return false; // After the last point, thus constant. |
74 |
} |
75 |
- |
76 |
- // If no next value found, assume increasing values |
77 |
- return true; |
78 |
+ if ((candidate->co.X == index) || (candidate == begin(Points))) { |
79 |
+ ++candidate; |
80 |
+ } |
81 |
+ int64_t const value = GetLong(index); |
82 |
+ do { |
83 |
+ if (value < round(candidate->co.Y)) { |
84 |
+ return true; |
85 |
+ } else if (value > round(candidate->co.Y)) { |
86 |
+ return false; |
87 |
+ } |
88 |
+ ++candidate; |
89 |
+ } while (candidate != end(Points)); |
90 |
+ return false; |
91 |
} |
92 |
|
93 |
// Generate JSON string of this object |
94 |
@@ -388,12 +374,116 @@ void Keyframe::SetJsonValue(const Json::Value root) { |
95 |
} |
96 |
} |
97 |
|
98 |
+// Get the fraction that represents how many times this value is repeated in the curve |
99 |
+// This is depreciated and will be removed soon. |
100 |
+Fraction Keyframe::GetRepeatFraction(int64_t index) const { |
101 |
+ // Frame numbers (index) outside of the "defined" range of this |
102 |
+ // keyframe result in a 1/1 default value. |
103 |
+ if (index < 1 || (index + 1) >= GetLength()) { |
104 |
+ return Fraction(1,1); |
105 |
+ } |
106 |
+ assert(Points.size() > 1); // Due to ! ((index + 1) >= GetLength) there are at least two points! |
107 |
+ |
108 |
+ // First, get the value at the given frame and the closest point |
109 |
+ // to the right. |
110 |
+ int64_t const current_value = GetLong(index); |
111 |
+ std::vector<Point>::const_iterator const candidate = |
112 |
+ std::lower_bound(begin(Points), end(Points), static_cast<double>(index), IsPointBeforeX); |
113 |
+ assert(candidate != end(Points)); // Due to the (index + 1) >= GetLength check above! |
114 |
+ |
115 |
+ // Calculate how many of the next values are going to be the same: |
116 |
+ int64_t next_repeats = 0; |
117 |
+ std::vector<Point>::const_iterator i = candidate; |
118 |
+ // If the index (frame number) is the X coordinate of the closest |
119 |
+ // point, then look at the segment to the right; the "current" |
120 |
+ // segement is not interesting because we're already at the last |
121 |
+ // value of it. |
122 |
+ if (i->co.X == index) { |
123 |
+ ++i; |
124 |
+ } |
125 |
+ // Skip over "constant" (when rounded) segments. |
126 |
+ bool all_constant = true; |
127 |
+ for (; i != end(Points); ++i) { |
128 |
+ if (current_value != round(i->co.Y)) { |
129 |
+ all_constant = false; |
130 |
+ break; |
131 |
+ } |
132 |
+ } |
133 |
+ if (! all_constant) { |
134 |
+ // Found a point which defines a segment which will give a |
135 |
+ // different value than the current value. This means we |
136 |
+ // moved at least one segment to the right, thus we cannot be |
137 |
+ // at the first point. |
138 |
+ assert(i != begin(Points)); |
139 |
+ Point const left = *(i - 1); |
140 |
+ Point const right = *i; |
141 |
+ int64_t change_at; |
142 |
+ if (current_value < round(i->co.Y)) { |
143 |
+ change_at = SearchBetweenPoints(left, right, current_value, std::less_equal<double>{}); |
144 |
+ } else { |
145 |
+ assert(current_value > round(i->co.Y)); |
146 |
+ change_at = SearchBetweenPoints(left, right, current_value, std::greater_equal<double>{}); |
147 |
+ } |
148 |
+ next_repeats = change_at - index; |
149 |
+ } else { |
150 |
+ // All values to the right are the same! |
151 |
+ next_repeats = Points.back().co.X - index; |
152 |
+ } |
153 |
+ |
154 |
+ // Now look to the left, to the previous values. |
155 |
+ all_constant = true; |
156 |
+ i = candidate; |
157 |
+ if (i != begin(Points)) { |
158 |
+ // The binary search below assumes i to be the left point; |
159 |
+ // candidate is the right point of the current segment |
160 |
+ // though. So change this if possible. If this branch is NOT |
161 |
+ // taken, then we're at/before the first point and all is |
162 |
+ // constant! |
163 |
+ --i; |
164 |
+ } |
165 |
+ int64_t previous_repeats = 0; |
166 |
+ // Skip over constant (when rounded) segments! |
167 |
+ for (; i != begin(Points); --i) { |
168 |
+ if (current_value != round(i->co.Y)) { |
169 |
+ all_constant = false; |
170 |
+ break; |
171 |
+ } |
172 |
+ } |
173 |
+ // Special case when skipped until the first point, but the first |
174 |
+ // point is actually different. Will not happen if index is |
175 |
+ // before the first point! |
176 |
+ if (current_value != round(i->co.Y)) { |
177 |
+ assert(i != candidate); |
178 |
+ all_constant = false; |
179 |
+ } |
180 |
+ if (! all_constant) { |
181 |
+ // There are at least two points, and we're not at the end, |
182 |
+ // thus the following is safe! |
183 |
+ Point const left = *i; |
184 |
+ Point const right = *(i + 1); |
185 |
+ int64_t change_at; |
186 |
+ if (current_value > round(left.co.Y)) { |
187 |
+ change_at = SearchBetweenPoints(left, right, current_value, std::less<double>{}); |
188 |
+ } else { |
189 |
+ assert(current_value < round(left.co.Y)); |
190 |
+ change_at = SearchBetweenPoints(left, right, current_value, std::greater<double>{}); |
191 |
+ } |
192 |
+ previous_repeats = index - change_at; |
193 |
+ } else { |
194 |
+ // Every previous value is the same (rounded) as the current |
195 |
+ // value. |
196 |
+ previous_repeats = index; |
197 |
+ } |
198 |
+ int64_t total_repeats = previous_repeats + next_repeats; |
199 |
+ return Fraction(previous_repeats, total_repeats); |
200 |
+} |
201 |
+ |
202 |
// Get the change in Y value (from the previous Y value) |
203 |
double Keyframe::GetDelta(int64_t index) const { |
204 |
- if (index < 1) return 0.0; |
205 |
- if (index == 1 && !Points.empty()) return Points[0].co.Y; |
206 |
- if (index >= GetLength()) return 0.0; |
207 |
- return GetValue(index) - GetValue(index - 1); |
208 |
+ if (index < 1) return 0; |
209 |
+ if (index == 1 && ! Points.empty()) return Points[0].co.Y; |
210 |
+ if (index >= GetLength()) return 0; |
211 |
+ return GetLong(index) - GetLong(index - 1); |
212 |
} |
213 |
|
214 |
// Get a point at a specific index |
215 |
@@ -410,7 +500,7 @@ Point const & Keyframe::GetPoint(int64_t index) const |
216 |
int64_t Keyframe::GetLength() const { |
217 |
if (Points.empty()) return 0; |
218 |
if (Points.size() == 1) return 1; |
219 |
- return round(Points.back().co.X); |
220 |
+ return round(Points.back().co.X) + 1; |
221 |
} |
222 |
|
223 |
// Get the number of points (i.e. # of points) |
224 |
@@ -461,46 +551,50 @@ void Keyframe::UpdatePoint(int64_t index, Point p) { |
225 |
} |
226 |
|
227 |
void Keyframe::PrintPoints(std::ostream* out) const { |
228 |
- *out << std::right << std::setprecision(4) << std::setfill(' '); |
229 |
- for (const auto& p : Points) { |
230 |
- *out << std::defaultfloat |
231 |
- << std::setw(6) << p.co.X |
232 |
- << std::setw(14) << std::fixed << p.co.Y |
233 |
- << '\n'; |
234 |
- } |
235 |
- *out << std::flush; |
236 |
+ *out << std::right << std::setprecision(4) << std::setfill(' '); |
237 |
+ for (const auto& p : Points) { |
238 |
+ *out << std::defaultfloat |
239 |
+ << std::setw(6) << p.co.X |
240 |
+ << std::setw(14) << std::fixed << p.co.Y |
241 |
+ << '\n'; |
242 |
+ } |
243 |
+ *out << std::flush; |
244 |
} |
245 |
|
246 |
void Keyframe::PrintValues(std::ostream* out) const { |
247 |
- // Column widths |
248 |
- std::vector<int> w{10, 12, 8, 11, 19}; |
249 |
+ // Column widths |
250 |
+ std::vector<int> w{10, 12, 8, 11, 19}; |
251 |
|
252 |
- *out << std::right << std::setfill(' ') << std::setprecision(4); |
253 |
- // Headings |
254 |
- *out << "│" |
255 |
- << std::setw(w[0]) << "Frame# (X)" << " │" |
256 |
- << std::setw(w[1]) << "Y Value" << " │" |
257 |
- << std::setw(w[2]) << "Delta Y" << " │ " |
258 |
- << std::setw(w[3]) << "Increasing?" << std::right |
259 |
- << "│\n"; |
260 |
- // Divider |
261 |
- *out << "├───────────" |
262 |
- << "┼─────────────" |
263 |
- << "┼─────────" |
264 |
- << "┼────────────┤\n"; |
265 |
+ *out << std::right << std::setfill(' ') << std::setprecision(4); |
266 |
+ // Headings |
267 |
+ *out << "│" |
268 |
+ << std::setw(w[0]) << "Frame# (X)" << " │" |
269 |
+ << std::setw(w[1]) << "Y Value" << " │" |
270 |
+ << std::setw(w[2]) << "Delta Y" << " │ " |
271 |
+ << std::setw(w[3]) << "Increasing?" << " │ " |
272 |
+ << std::setw(w[4]) << std::left << "Repeat Fraction" << std::right |
273 |
+ << "│\n"; |
274 |
+ // Divider |
275 |
+ *out << "├───────────" |
276 |
+ << "┼─────────────" |
277 |
+ << "┼─────────" |
278 |
+ << "┼─────────────" |
279 |
+ << "┼────────────────────┤\n"; |
280 |
|
281 |
- for (int64_t i = 1; i <= GetLength(); ++i) { |
282 |
- *out << "│" |
283 |
- << std::setw(w[0]-2) << std::defaultfloat << i |
284 |
- << (Contains(Point(i, 1)) ? " *" : " ") << " │" |
285 |
- << std::setw(w[1]) << std::fixed << GetValue(i) << " │" |
286 |
- << std::setw(w[2]) << std::defaultfloat << std::showpos |
287 |
- << GetDelta(i) << " │ " << std::noshowpos |
288 |
- << std::setw(w[3]) |
289 |
- << (IsIncreasing(i) ? "true" : "false") << std::right << "│\n"; |
290 |
- } |
291 |
- *out << " * = Keyframe point (non-interpolated)\n"; |
292 |
- *out << std::flush; |
293 |
+ for (int64_t i = 1; i < GetLength(); ++i) { |
294 |
+ *out << "│" |
295 |
+ << std::setw(w[0]-2) << std::defaultfloat << i |
296 |
+ << (Contains(Point(i, 1)) ? " *" : " ") << " │" |
297 |
+ << std::setw(w[1]) << std::fixed << GetValue(i) << " │" |
298 |
+ << std::setw(w[2]) << std::defaultfloat << std::showpos |
299 |
+ << GetDelta(i) << " │ " << std::noshowpos |
300 |
+ << std::setw(w[3]) |
301 |
+ << (IsIncreasing(i) ? "true" : "false") << " │ " |
302 |
+ << std::setw(w[4]) << std::left << GetRepeatFraction(i) |
303 |
+ << std::right << "│\n"; |
304 |
+ } |
305 |
+ *out << " * = Keyframe point (non-interpolated)\n"; |
306 |
+ *out << std::flush; |
307 |
} |
308 |
|
309 |
|