Skip to content

Commit 481fdc8

Browse files
committed
Add intersects predicate, constexpr functions to compare time and reformatting
1 parent 66024bb commit 481fdc8

File tree

5 files changed

+153
-69
lines changed

5 files changed

+153
-69
lines changed

src/opentime/timeRange.h

Lines changed: 70 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ namespace opentime {
1818
*/
1919

2020
/**
21-
* This default epsilon value is used in comparison between floating numbers.
21+
* This default epsilon_s value is used in comparison between floating numbers.
2222
* It is computed to be twice 192khz, the fastest commonly used audio rate.
2323
* It can be changed in the future if necessary due to higher sampling rates
2424
* or some other kind of numeric tolerance detected in the library.
@@ -92,8 +92,9 @@ class TimeRange {
9292
*/
9393

9494
/**
95-
* In the relations that follow, epsilon indicates the tolerance,in the sense that if abs(a-b) < epsilon,
96-
* we consider a and b to be equal
95+
* In the relations that follow, epsilon_s indicates the tolerance,in the sense that if abs(a-b) < epsilon_s,
96+
* we consider a and b to be equal.
97+
* The time comparison is done in double seconds.
9798
*/
9899

99100
/**
@@ -117,12 +118,12 @@ class TimeRange {
117118
* The converse would be <em>other.contains(this)</em>
118119
* @param other
119120
*/
120-
bool contains(TimeRange other, double epsilon = DEFAULT_EPSILON_s) const {
121-
double thisStart = _start_time.to_seconds();
122-
double thisEnd = end_time_exclusive().to_seconds();
123-
double otherStart = other._start_time.to_seconds();
124-
double otherEnd = other.end_time_exclusive().to_seconds();
125-
return otherStart - thisStart >= epsilon && thisEnd - otherEnd >=epsilon;
121+
bool contains(TimeRange other, double epsilon_s = DEFAULT_EPSILON_s) const {
122+
double thisStart = _start_time.to_seconds();
123+
double thisEnd = end_time_exclusive().to_seconds();
124+
double otherStart = other._start_time.to_seconds();
125+
double otherEnd = other.end_time_exclusive().to_seconds();
126+
return greater_than(otherStart, thisStart, epsilon_s) && lesser_than(otherEnd, thisEnd, epsilon_s);
126127
}
127128

128129
/**
@@ -138,49 +139,49 @@ class TimeRange {
138139
}
139140

140141
/**
141-
* The start of <b>this</b> strictly precedes end of <b>other</b> by a value >= <b>epsilon</b>.
142-
* The end of <b>this</b> strictly antecedes start of <b>other</b> by a value >= <b>epsilon</b>.
142+
* The start of <b>this</b> strictly precedes end of <b>other</b> by a value >= <b>epsilon_s</b>.
143+
* The end of <b>this</b> strictly antecedes start of <b>other</b> by a value >= <b>epsilon_s</b>.
143144
* [ this ]
144145
* [ other ]
145146
* The converse would be <em>other.overlaps(this)</em>
146147
* @param other
147-
* @param epsilon
148+
* @param epsilon_s
148149
*/
149-
bool overlaps(TimeRange other, double epsilon = DEFAULT_EPSILON_s) const {
150-
double thisStart = _start_time.to_seconds();
151-
double thisEnd = end_time_exclusive().to_seconds();
152-
double otherStart = other._start_time.to_seconds();
153-
double otherEnd = other.end_time_exclusive().to_seconds();
154-
return (otherEnd - thisEnd >= epsilon) &&
155-
(otherStart - thisStart >= epsilon) &&
156-
(thisEnd - otherStart >= epsilon);
150+
bool overlaps(TimeRange other, double epsilon_s = DEFAULT_EPSILON_s) const {
151+
double thisStart = _start_time.to_seconds();
152+
double thisEnd = end_time_exclusive().to_seconds();
153+
double otherStart = other._start_time.to_seconds();
154+
double otherEnd = other.end_time_exclusive().to_seconds();
155+
return lesser_than(thisStart, otherStart, epsilon_s) &&
156+
greater_than(thisEnd, otherStart, epsilon_s) &&
157+
greater_than(otherEnd, thisEnd, epsilon_s);
157158
}
158159

159160
/**
160-
* The end of <b>this</b> strictly precedes the start of <b>other</b> by a value >= <b>epsilon</b>.
161+
* The end of <b>this</b> strictly precedes the start of <b>other</b> by a value >= <b>epsilon_s</b>.
161162
* [ this ] [ other ]
162163
* The converse would be <em>other.before(this)</em>
163164
* @param other
164-
* @param epsilon
165+
* @param epsilon_s
165166
*/
166-
bool before(TimeRange other, double epsilon = DEFAULT_EPSILON_s) const {
167+
bool before(TimeRange other, double epsilon_s = DEFAULT_EPSILON_s) const {
167168
double thisEnd = end_time_exclusive().to_seconds();
168169
double otherStart = other._start_time.to_seconds();
169-
return otherStart - thisEnd >= epsilon;
170+
return greater_than(otherStart, thisEnd, epsilon_s);
170171
}
171172

172173
/**
173-
* The end of <b>this</b> strictly precedes <b>other</b> by a value >= <b>epsilon</b>.
174+
* The end of <b>this</b> strictly precedes <b>other</b> by a value >= <b>epsilon_s</b>.
174175
* other
175176
* ↓
176177
* [ this ] *
177178
* @param other
178-
* @param epsilon
179+
* @param epsilon_s
179180
*/
180-
bool before(RationalTime other, double epsilon = DEFAULT_EPSILON_s) const {
181+
bool before(RationalTime other, double epsilon_s = DEFAULT_EPSILON_s) const {
181182
double thisEnd = end_time_exclusive().to_seconds();
182183
double otherTime = other.to_seconds();
183-
return otherTime - thisEnd >= epsilon;
184+
return lesser_than(thisEnd, otherTime, epsilon_s);
184185
}
185186

186187
/**
@@ -189,29 +190,29 @@ class TimeRange {
189190
* [this][other]
190191
* The converse would be <em>other.meets(this)</em>
191192
* @param other
192-
* @param epsilon
193+
* @param epsilon_s
193194
*/
194-
bool meets(TimeRange other, double epsilon = DEFAULT_EPSILON_s) const {
195+
bool meets(TimeRange other, double epsilon_s = DEFAULT_EPSILON_s) const {
195196
double thisEnd = end_time_exclusive().to_seconds();
196197
double otherStart = other._start_time.to_seconds();
197-
return otherStart - thisEnd <= epsilon && otherStart - thisEnd >= 0;
198+
return otherStart - thisEnd <= epsilon_s && otherStart - thisEnd >= 0;
198199
}
199200

200201
/**
201202
* The start of <b>this</b> strictly equals the start of <b>other</b>.
202-
* The end of <b>this</b> strictly precedes the end of <b>other</b> by a value >= <b>epsilon</b>.
203+
* The end of <b>this</b> strictly precedes the end of <b>other</b> by a value >= <b>epsilon_s</b>.
203204
* [ this ]
204205
* [ other ]
205206
* The converse would be <em>other.begins(this)</em>
206207
* @param other
207-
* @param epsilon
208+
* @param epsilon_s
208209
*/
209-
bool begins(TimeRange other, double epsilon = DEFAULT_EPSILON_s) const {
210+
bool begins(TimeRange other, double epsilon_s = DEFAULT_EPSILON_s) const {
210211
double thisStart = _start_time.to_seconds();
211212
double thisEnd = end_time_exclusive().to_seconds();
212213
double otherStart = other._start_time.to_seconds();
213214
double otherEnd = other.end_time_exclusive().to_seconds();
214-
return fabs(otherStart - thisStart) <= epsilon && otherEnd - thisEnd >= epsilon;
215+
return fabs(otherStart - thisStart) <= epsilon_s && lesser_than(thisEnd, otherEnd, epsilon_s);
215216
}
216217

217218
/**
@@ -222,27 +223,27 @@ class TimeRange {
222223
* [ this ]
223224
* @param other
224225
*/
225-
bool begins(RationalTime other, double epsilon = DEFAULT_EPSILON_s) const {
226+
bool begins(RationalTime other, double epsilon_s = DEFAULT_EPSILON_s) const {
226227
double thisStart = _start_time.to_seconds();
227228
double otherStart = other.to_seconds();
228-
return fabs(otherStart - thisStart) <= epsilon;
229+
return fabs(otherStart - thisStart) <= epsilon_s;
229230
}
230231

231232
/**
232-
* The start of <b>this</b> strictly antecedes the start of <b>other</b> by a value >= <b>epsilon</b>.
233+
* The start of <b>this</b> strictly antecedes the start of <b>other</b> by a value >= <b>epsilon_s</b>.
233234
* The end of <b>this</b> strictly equals the end of <b>other</b>.
234235
* [ this ]
235236
* [ other ]
236237
* The converse would be <em>other.finishes(this)</em>
237238
* @param other
238-
* @param epsilon
239+
* @param epsilon_s
239240
*/
240-
bool finishes(TimeRange other, double epsilon = DEFAULT_EPSILON_s) const {
241+
bool finishes(TimeRange other, double epsilon_s = DEFAULT_EPSILON_s) const {
241242
double thisStart = _start_time.to_seconds();
242243
double thisEnd = end_time_exclusive().to_seconds();
243244
double otherStart = other._start_time.to_seconds();
244245
double otherEnd = other.end_time_exclusive().to_seconds();
245-
return fabs(thisEnd - otherEnd) <= epsilon && thisStart - otherStart >= epsilon;
246+
return fabs(thisEnd - otherEnd) <= epsilon_s && greater_than(thisStart, otherStart, epsilon_s);
246247
}
247248

248249
/**
@@ -252,12 +253,29 @@ class TimeRange {
252253
* *
253254
* [ this ]
254255
* @param other
255-
* @param epsilon
256+
* @param epsilon_s
256257
*/
257-
bool finishes(RationalTime other, double epsilon = DEFAULT_EPSILON_s) const {
258+
bool finishes(RationalTime other, double epsilon_s = DEFAULT_EPSILON_s) const {
258259
double thisEnd = end_time_exclusive().to_seconds();
259260
double otherEnd = other.to_seconds();
260-
return fabs(thisEnd - otherEnd) <= epsilon;
261+
return fabs(thisEnd - otherEnd) <= epsilon_s;
262+
}
263+
264+
/**
265+
* The start of <b>this</b> precedes or equals the end of <b>other</b> by a value >= <b>epsilon_s</b>.
266+
* The end of <b>this</b> antecedes or equals the start of <b>other</b> by a value >= <b>epsilon_s</b>.
267+
* [ this ] OR [ other ]
268+
* [ other ] [ this ]
269+
* The converse would be <em>other.finishes(this)</em>
270+
* @param other
271+
* @param epsilon_s
272+
*/
273+
bool intersects(TimeRange other, double epsilon_s = DEFAULT_EPSILON_s) const {
274+
double thisStart = _start_time.to_seconds();
275+
double thisEnd = end_time_exclusive().to_seconds();
276+
double otherStart = other._start_time.to_seconds();
277+
double otherEnd = other.end_time_exclusive().to_seconds();
278+
return lesser_than(thisStart, otherEnd, epsilon_s) && greater_than(thisEnd, otherStart, epsilon_s);
261279
}
262280

263281

@@ -293,6 +311,14 @@ class TimeRange {
293311
private:
294312
RationalTime _start_time, _duration;
295313
friend class TimeTransform;
314+
315+
inline constexpr bool greater_than(double lhs, double rhs, double epsilon) const{
316+
return lhs - rhs >= epsilon;
317+
}
318+
319+
inline constexpr bool lesser_than(double lhs, double rhs, double epsilon) const{
320+
return rhs - lhs >= epsilon;
321+
}
296322
};
297323

298324
} }

src/opentimelineio/trackAlgorithm.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,7 @@ Track* track_trimmed_to_range(Track* in_track, TimeRange trim_range, ErrorStatus
2727
}
2828

2929
auto child_range = child_range_it->second;
30-
if ((trim_range.duration().value() == 0) ||
31-
(!trim_range.overlaps(child_range) && !child_range.overlaps(trim_range) &&
32-
!trim_range.begins(child_range) && !child_range.begins(trim_range) &&
33-
!trim_range.finishes(child_range) && !child_range.finishes(trim_range) &&
34-
!trim_range.contains(child_range) && !child_range.contains(trim_range) &&
35-
!(trim_range == child_range))) {
30+
if (!trim_range.intersects(child_range)) {
3631
new_track->remove_child(static_cast<int>(i), error_status);
3732
if (*error_status) {
3833
return nullptr;

src/py-opentimelineio/opentime-bindings/opentime_timeRange.cpp

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,17 @@ void opentime_timeRange_bindings(py::module m) {
4343
.def("clamped", (RationalTime (TimeRange::*)(RationalTime) const) &TimeRange::clamped, "other"_a)
4444
.def("clamped", (TimeRange (TimeRange::*)(TimeRange) const) &TimeRange::clamped, "other"_a)
4545
.def("contains", (bool (TimeRange::*)(RationalTime) const) &TimeRange::contains, "other"_a)
46-
.def("contains", (bool (TimeRange::*)(TimeRange, double) const) &TimeRange::contains, "other"_a, "epsilon"_a=opentime::DEFAULT_EPSILON_s)
46+
.def("contains", (bool (TimeRange::*)(TimeRange, double) const) &TimeRange::contains, "other"_a, "epsilon_s"_a=opentime::DEFAULT_EPSILON_s)
4747
.def("overlaps", (bool (TimeRange::*)(RationalTime) const) &TimeRange::overlaps, "other"_a)
48-
.def("overlaps", (bool (TimeRange::*)(TimeRange, double) const) &TimeRange::overlaps, "other"_a, "epsilon"_a=opentime::DEFAULT_EPSILON_s)
49-
.def("before", (bool (TimeRange::*)(TimeRange, double) const) &TimeRange::before, "other"_a, "epsilon"_a=opentime::DEFAULT_EPSILON_s)
50-
.def("before", (bool (TimeRange::*)(RationalTime, double ) const) &TimeRange::before, "other"_a, "epsilon"_a=opentime::DEFAULT_EPSILON_s)
51-
.def("meets", (bool (TimeRange::*)(TimeRange, double) const) &TimeRange::meets, "other"_a, "epsilon"_a=opentime::DEFAULT_EPSILON_s)
52-
.def("begins", (bool (TimeRange::*)(TimeRange, double) const) &TimeRange::begins, "other"_a, "epsilon"_a=opentime::DEFAULT_EPSILON_s)
53-
.def("begins", (bool (TimeRange::*)(RationalTime, double) const) &TimeRange::begins, "other"_a, "epsilon"_a=opentime::DEFAULT_EPSILON_s)
54-
.def("finishes", (bool (TimeRange::*)(TimeRange, double) const) &TimeRange::finishes, "other"_a, "epsilon"_a=opentime::DEFAULT_EPSILON_s)
55-
.def("finishes", (bool (TimeRange::*)(RationalTime, double) const) &TimeRange::finishes, "other"_a, "epsilon"_a=opentime::DEFAULT_EPSILON_s)
48+
.def("overlaps", (bool (TimeRange::*)(TimeRange, double) const) &TimeRange::overlaps, "other"_a, "epsilon_s"_a=opentime::DEFAULT_EPSILON_s)
49+
.def("before", (bool (TimeRange::*)(TimeRange, double) const) &TimeRange::before, "other"_a, "epsilon_s"_a=opentime::DEFAULT_EPSILON_s)
50+
.def("before", (bool (TimeRange::*)(RationalTime, double ) const) &TimeRange::before, "other"_a, "epsilon_s"_a=opentime::DEFAULT_EPSILON_s)
51+
.def("meets", (bool (TimeRange::*)(TimeRange, double) const) &TimeRange::meets, "other"_a, "epsilon_s"_a=opentime::DEFAULT_EPSILON_s)
52+
.def("begins", (bool (TimeRange::*)(TimeRange, double) const) &TimeRange::begins, "other"_a, "epsilon_s"_a=opentime::DEFAULT_EPSILON_s)
53+
.def("begins", (bool (TimeRange::*)(RationalTime, double) const) &TimeRange::begins, "other"_a, "epsilon_s"_a=opentime::DEFAULT_EPSILON_s)
54+
.def("finishes", (bool (TimeRange::*)(TimeRange, double) const) &TimeRange::finishes, "other"_a, "epsilon_s"_a=opentime::DEFAULT_EPSILON_s)
55+
.def("finishes", (bool (TimeRange::*)(RationalTime, double) const) &TimeRange::finishes, "other"_a, "epsilon_s"_a=opentime::DEFAULT_EPSILON_s)
56+
.def("intersects", (bool (TimeRange::*)(TimeRange, double) const) &TimeRange::intersects, "other"_a, "epsilon_s"_a=opentime::DEFAULT_EPSILON_s)
5657
.def("__copy__", [](TimeRange tr) {
5758
return tr;
5859
})

src/py-opentimelineio/opentimelineio/algorithms/track_algo.py

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,7 @@ def track_trimmed_to_range(in_track, trim_range):
4747
# iterate backwards so we can delete items
4848
for c, child in reversed(list(enumerate(new_track))):
4949
child_range = track_map[child]
50-
if (trim_range.duration.value == 0) \
51-
or (not trim_range.overlaps(child_range) and
52-
not child_range.overlaps(trim_range) and
53-
not trim_range.begins(child_range) and
54-
not child_range.begins(trim_range) and
55-
not trim_range.finishes(child_range) and
56-
not child_range.finishes(trim_range) and
57-
not trim_range.contains(child_range) and
58-
not child_range.contains(trim_range) and
59-
not trim_range == child_range):
50+
if not trim_range.intersects(child_range):
6051
# completely outside the trim range, so we discard it
6152
del new_track[c]
6253
elif trim_range.contains(child_range):

tests/test_opentime.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -955,6 +955,77 @@ def test_overlaps_timerange(self):
955955

956956
self.assertFalse(tr.overlaps(tr_t))
957957

958+
def test_intersects_timerange(self):
959+
tstart = otio.opentime.RationalTime(12, 25)
960+
tdur = otio.opentime.RationalTime(3, 25)
961+
tr = otio.opentime.TimeRange(tstart, tdur)
962+
963+
tstart = otio.opentime.RationalTime(0, 25)
964+
tdur = otio.opentime.RationalTime(3, 25)
965+
tr_t = otio.opentime.TimeRange(tstart, tdur)
966+
967+
self.assertFalse(tr.intersects(tr_t))
968+
969+
tstart = otio.opentime.RationalTime(10, 25)
970+
tdur = otio.opentime.RationalTime(3, 25)
971+
tr_t = otio.opentime.TimeRange(tstart, tdur)
972+
973+
self.assertTrue(tr.intersects(tr_t))
974+
975+
tstart = otio.opentime.RationalTime(10, 25)
976+
tdur = otio.opentime.RationalTime(2, 25)
977+
tr_t = otio.opentime.TimeRange(tstart, tdur)
978+
979+
self.assertFalse(tr.intersects(tr_t))
980+
981+
tstart = otio.opentime.RationalTime(14, 25)
982+
tdur = otio.opentime.RationalTime(2, 25)
983+
tr_t = otio.opentime.TimeRange(tstart, tdur)
984+
985+
self.assertTrue(tr.intersects(tr_t))
986+
987+
tstart = otio.opentime.RationalTime(15, 25)
988+
tdur = otio.opentime.RationalTime(2, 25)
989+
tr_t = otio.opentime.TimeRange(tstart, tdur)
990+
991+
self.assertFalse(tr.intersects(tr_t))
992+
993+
tstart = otio.opentime.RationalTime(13, 25)
994+
tdur = otio.opentime.RationalTime(1, 25)
995+
tr_t = otio.opentime.TimeRange(tstart, tdur)
996+
997+
self.assertTrue(tr.intersects(tr_t))
998+
999+
tstart = otio.opentime.RationalTime(2, 25)
1000+
tdur = otio.opentime.RationalTime(30, 25)
1001+
tr_t = otio.opentime.TimeRange(tstart, tdur)
1002+
1003+
self.assertTrue(tr.intersects(tr_t))
1004+
1005+
tstart = otio.opentime.RationalTime(2, 50)
1006+
tdur = otio.opentime.RationalTime(60, 50)
1007+
tr_t = otio.opentime.TimeRange(tstart, tdur)
1008+
1009+
self.assertTrue(tr.intersects(tr_t))
1010+
1011+
tstart = otio.opentime.RationalTime(2, 50)
1012+
tdur = otio.opentime.RationalTime(14, 50)
1013+
tr_t = otio.opentime.TimeRange(tstart, tdur)
1014+
1015+
self.assertFalse(tr.intersects(tr_t))
1016+
1017+
tstart = otio.opentime.RationalTime(-100, 50)
1018+
tdur = otio.opentime.RationalTime(400, 50)
1019+
tr_t = otio.opentime.TimeRange(tstart, tdur)
1020+
1021+
self.assertTrue(tr.intersects(tr_t))
1022+
1023+
tstart = otio.opentime.RationalTime(100, 50)
1024+
tdur = otio.opentime.RationalTime(400, 50)
1025+
tr_t = otio.opentime.TimeRange(tstart, tdur)
1026+
1027+
self.assertFalse(tr.intersects(tr_t))
1028+
9581029
def test_before_timerange(self):
9591030
tstart = otio.opentime.RationalTime(12, 25)
9601031
tdur = otio.opentime.RationalTime(3, 25)

0 commit comments

Comments
 (0)