yta-video-frame-time 0.0.12__tar.gz → 0.0.13__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of yta-video-frame-time might be problematic. Click here for more details.
- {yta_video_frame_time-0.0.12 → yta_video_frame_time-0.0.13}/PKG-INFO +1 -1
- {yta_video_frame_time-0.0.12 → yta_video_frame_time-0.0.13}/pyproject.toml +1 -1
- yta_video_frame_time-0.0.13/src/yta_video_frame_time/interval.py +569 -0
- {yta_video_frame_time-0.0.12 → yta_video_frame_time-0.0.13}/LICENSE +0 -0
- {yta_video_frame_time-0.0.12 → yta_video_frame_time-0.0.13}/README.md +0 -0
- {yta_video_frame_time-0.0.12 → yta_video_frame_time-0.0.13}/src/yta_video_frame_time/__init__.py +0 -0
- {yta_video_frame_time-0.0.12 → yta_video_frame_time-0.0.13}/src/yta_video_frame_time/t_fraction.py +0 -0
|
@@ -0,0 +1,569 @@
|
|
|
1
|
+
from yta_validation.parameter import ParameterValidator
|
|
2
|
+
from quicktions import Fraction
|
|
3
|
+
from typing import Union
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
Tengo un elemento con una duración concreta, por lo que
|
|
8
|
+
el rango es [0, duration):
|
|
9
|
+
- Recortar solo por el principio => 2 segmentos
|
|
10
|
+
- Recortar solo por el final => 2 segmentos
|
|
11
|
+
- Recortar en medio => 3 segmentos
|
|
12
|
+
"""
|
|
13
|
+
Number = Union[int, float, Fraction]
|
|
14
|
+
"""
|
|
15
|
+
Custom type to represent numbers.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
"""
|
|
19
|
+
TODO: Maybe we can add the possibility of having an
|
|
20
|
+
`fps` value when initializing it to be able to force
|
|
21
|
+
the time interval values to be multiple of `1/fps`.
|
|
22
|
+
But this, if implemented, should be `TimeIntervalFPS`
|
|
23
|
+
or similar, and inheritance from this one but forcing
|
|
24
|
+
the values to be transformed according to that `1/fps`.
|
|
25
|
+
"""
|
|
26
|
+
class TimeInterval:
|
|
27
|
+
"""
|
|
28
|
+
Class to represent a time interval, which is a tuple
|
|
29
|
+
of time moments representing the time range
|
|
30
|
+
`[start, end)`.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def start_base(
|
|
35
|
+
self
|
|
36
|
+
) -> float:
|
|
37
|
+
"""
|
|
38
|
+
The `start` of the interval but always as 0.
|
|
39
|
+
"""
|
|
40
|
+
return 0
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def end_base(
|
|
44
|
+
self
|
|
45
|
+
) -> float:
|
|
46
|
+
"""
|
|
47
|
+
The `end` of the interval but adapted to a `start=0`.
|
|
48
|
+
"""
|
|
49
|
+
return self.end - self.start
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def duration(
|
|
53
|
+
self
|
|
54
|
+
) -> float:
|
|
55
|
+
"""
|
|
56
|
+
The `duration` of the time interval.
|
|
57
|
+
"""
|
|
58
|
+
return self.end - self.start
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def copy(
|
|
62
|
+
self
|
|
63
|
+
) -> 'TimeInterval':
|
|
64
|
+
"""
|
|
65
|
+
A copy of this instance.
|
|
66
|
+
"""
|
|
67
|
+
return TimeInterval(
|
|
68
|
+
start = self.start,
|
|
69
|
+
end = self.end
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def as_tuple(
|
|
74
|
+
self
|
|
75
|
+
) -> tuple[float, float]:
|
|
76
|
+
"""
|
|
77
|
+
The time interval but as a `(start, end)` tuple.
|
|
78
|
+
"""
|
|
79
|
+
return (self.start, self.end)
|
|
80
|
+
|
|
81
|
+
def __init__(
|
|
82
|
+
self,
|
|
83
|
+
start: Number,
|
|
84
|
+
end: Number,
|
|
85
|
+
):
|
|
86
|
+
"""
|
|
87
|
+
Provide the interval as it actually is, with the `start`
|
|
88
|
+
and `end`. These values will be adjusted to an internal
|
|
89
|
+
interval starting on 0.
|
|
90
|
+
|
|
91
|
+
The `end` value must be greater than the `start` value.
|
|
92
|
+
"""
|
|
93
|
+
if start > end:
|
|
94
|
+
raise Exception('The `start` value provided is greater than the `end` value provided.')
|
|
95
|
+
|
|
96
|
+
if start == end:
|
|
97
|
+
raise Exception('The `start` value provided is exactly the `end` value provided.')
|
|
98
|
+
|
|
99
|
+
self.start: float = start
|
|
100
|
+
"""
|
|
101
|
+
The original `start` of the time segment.
|
|
102
|
+
"""
|
|
103
|
+
self.end: float = end
|
|
104
|
+
"""
|
|
105
|
+
The original `end` of the time segment.
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
def _validate_t(
|
|
109
|
+
self,
|
|
110
|
+
t: Number,
|
|
111
|
+
do_include_start: bool = False,
|
|
112
|
+
do_include_end: bool = False
|
|
113
|
+
) -> None:
|
|
114
|
+
"""
|
|
115
|
+
Validate that the provided `t` value is between the `start`
|
|
116
|
+
and the `end` parameters provided, including them or not
|
|
117
|
+
according to the boolean parameters provided.
|
|
118
|
+
"""
|
|
119
|
+
ParameterValidator.validate_mandatory_number_between(
|
|
120
|
+
name = 't',
|
|
121
|
+
value = t,
|
|
122
|
+
lower_limit = self.start,
|
|
123
|
+
upper_limit = self.end,
|
|
124
|
+
do_include_lower_limit = do_include_start,
|
|
125
|
+
do_include_upper_limit = do_include_end
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
def _cut(
|
|
129
|
+
self,
|
|
130
|
+
start: Number,
|
|
131
|
+
end: Number
|
|
132
|
+
) -> tuple[Union['TimeInterval', None], Union['TimeInterval', None], Union['TimeInterval', None]]:
|
|
133
|
+
"""
|
|
134
|
+
*For internal use only*
|
|
135
|
+
|
|
136
|
+
Cut a segment with the given `start` and `end` time moments.
|
|
137
|
+
|
|
138
|
+
This method will return a tuple of 3 elements including the
|
|
139
|
+
segments created by cutting this time interval. The tuple
|
|
140
|
+
will include all the segments at the begining and the rest
|
|
141
|
+
will be None.
|
|
142
|
+
|
|
143
|
+
Examples below:
|
|
144
|
+
- A time interval of `[2, 5)` cut with `start=3` and `end=4`
|
|
145
|
+
will generate `((2, 3), (3, 4), (4, 5))`.
|
|
146
|
+
- A time interval of `[2, 5)` cut with `start=2` and `end=4`
|
|
147
|
+
will generate `((2, 4), (4, 5), None)`.
|
|
148
|
+
- A time interval of `[2, 5)` cut with `start=4` and `end=5`
|
|
149
|
+
will generate `((2, 4), (4, 5), None)`.
|
|
150
|
+
- A time interval of `[2, 5)` cut with `start=2` and `end=5`
|
|
151
|
+
will generate `((2, 5), None, None)`.
|
|
152
|
+
|
|
153
|
+
As you can see, the result could be the same in different
|
|
154
|
+
situations, but it's up to you (and the specific method in
|
|
155
|
+
which you are calling to this one) to choose the tuple you
|
|
156
|
+
want to return.
|
|
157
|
+
|
|
158
|
+
(!) This will not modify the original instance.
|
|
159
|
+
"""
|
|
160
|
+
self._validate_t(start, do_include_start = True)
|
|
161
|
+
self._validate_t(end, do_include_end = True)
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
(
|
|
165
|
+
self.copy,
|
|
166
|
+
None,
|
|
167
|
+
None
|
|
168
|
+
)
|
|
169
|
+
if (
|
|
170
|
+
start == self.start and
|
|
171
|
+
end == self.end
|
|
172
|
+
) else
|
|
173
|
+
(
|
|
174
|
+
TimeInterval(
|
|
175
|
+
start = self.start,
|
|
176
|
+
end = end
|
|
177
|
+
),
|
|
178
|
+
TimeInterval(
|
|
179
|
+
start = end,
|
|
180
|
+
end = self.end
|
|
181
|
+
),
|
|
182
|
+
None
|
|
183
|
+
)
|
|
184
|
+
if start == self.start else
|
|
185
|
+
(
|
|
186
|
+
TimeInterval(
|
|
187
|
+
start = self.start,
|
|
188
|
+
end = start
|
|
189
|
+
),
|
|
190
|
+
TimeInterval(
|
|
191
|
+
start = start,
|
|
192
|
+
end = self.end
|
|
193
|
+
),
|
|
194
|
+
None
|
|
195
|
+
)
|
|
196
|
+
if end == self.end else
|
|
197
|
+
(
|
|
198
|
+
TimeInterval(
|
|
199
|
+
start = self.start,
|
|
200
|
+
end = start
|
|
201
|
+
),
|
|
202
|
+
TimeInterval(
|
|
203
|
+
start = start,
|
|
204
|
+
end = end
|
|
205
|
+
),
|
|
206
|
+
TimeInterval(
|
|
207
|
+
start = end,
|
|
208
|
+
end = self.end
|
|
209
|
+
)
|
|
210
|
+
)
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
def cut_from_start_to(
|
|
214
|
+
self,
|
|
215
|
+
t: Number,
|
|
216
|
+
do_get_cut: bool = False
|
|
217
|
+
) -> Union['TimeInterval', None]:
|
|
218
|
+
"""
|
|
219
|
+
Cut the interval from the start to the `t` value
|
|
220
|
+
provided. The return will be the segment cut if
|
|
221
|
+
`do_get_cut` is False, or the remaining part if
|
|
222
|
+
True.
|
|
223
|
+
|
|
224
|
+
(!) This will not modify the original instance.
|
|
225
|
+
"""
|
|
226
|
+
intervals = self._cut(
|
|
227
|
+
start = self.start,
|
|
228
|
+
end = t
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
return (
|
|
232
|
+
intervals[0]
|
|
233
|
+
if (
|
|
234
|
+
len(intervals) == 1 or
|
|
235
|
+
do_get_cut
|
|
236
|
+
) else
|
|
237
|
+
intervals[1]
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
def cut_to_end_from(
|
|
241
|
+
self,
|
|
242
|
+
t: Number,
|
|
243
|
+
do_get_cut: bool = False
|
|
244
|
+
) -> Union['TimeInterval', None]:
|
|
245
|
+
"""
|
|
246
|
+
Cut the interval from the start to the `t` value
|
|
247
|
+
provided. The return will be the segment cut if
|
|
248
|
+
`do_get_cut` is False, or the remaining part if
|
|
249
|
+
True.
|
|
250
|
+
|
|
251
|
+
(!) This will not modify the original instance.
|
|
252
|
+
"""
|
|
253
|
+
intervals = self._cut(
|
|
254
|
+
start = t,
|
|
255
|
+
end = self.end
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
return (
|
|
259
|
+
intervals[0]
|
|
260
|
+
if (
|
|
261
|
+
len(intervals) == 1 or
|
|
262
|
+
not do_get_cut
|
|
263
|
+
) else
|
|
264
|
+
intervals[1]
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
def cut_from_to(
|
|
268
|
+
self,
|
|
269
|
+
from_t: Number,
|
|
270
|
+
to_t: Number,
|
|
271
|
+
# do_get_cut: bool = False
|
|
272
|
+
) -> Union['TimeInterval', None]:
|
|
273
|
+
"""
|
|
274
|
+
Cut the interval from the `from_t` value provided
|
|
275
|
+
to the `to_t` value given. The return will be the
|
|
276
|
+
segment cut.
|
|
277
|
+
|
|
278
|
+
(!) This will not modify the original instance.
|
|
279
|
+
|
|
280
|
+
TODO: By now we are only getting the cut
|
|
281
|
+
"""
|
|
282
|
+
intervals = self._cut(
|
|
283
|
+
start = from_t,
|
|
284
|
+
end = to_t
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
return (
|
|
288
|
+
intervals[0]
|
|
289
|
+
if (
|
|
290
|
+
len(intervals) == 1 or
|
|
291
|
+
(
|
|
292
|
+
len(intervals) == 2 and
|
|
293
|
+
from_t == self.start
|
|
294
|
+
)
|
|
295
|
+
) else
|
|
296
|
+
intervals[1]
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
def is_t_included(
|
|
300
|
+
self,
|
|
301
|
+
t: float,
|
|
302
|
+
do_include_end: bool = False
|
|
303
|
+
) -> bool:
|
|
304
|
+
"""
|
|
305
|
+
Check if the `t` time moment provided is included in
|
|
306
|
+
this time interval, including the `end` only if the
|
|
307
|
+
`do_include_end` parameter is set as `True`.
|
|
308
|
+
"""
|
|
309
|
+
return TimeIntervalUtils.a_includes_t(
|
|
310
|
+
t = t,
|
|
311
|
+
time_interval_a = self,
|
|
312
|
+
do_include_end = do_include_end
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
def is_adjacent_to(
|
|
316
|
+
self,
|
|
317
|
+
time_interval: 'TimeInterval'
|
|
318
|
+
) -> bool:
|
|
319
|
+
"""
|
|
320
|
+
Check if the `time_interval` provided is adjacent
|
|
321
|
+
to this time interval, which means that the `end`
|
|
322
|
+
of one interval is also the `start` of the other
|
|
323
|
+
one.
|
|
324
|
+
|
|
325
|
+
(!) Giving the time intervals inverted will
|
|
326
|
+
provide the same result.
|
|
327
|
+
|
|
328
|
+
Example below:
|
|
329
|
+
- `a=[2, 5)` and `b=[5, 7)` => `True`
|
|
330
|
+
- `a=[5, 7)` and `b=[2, 5)` => `True`
|
|
331
|
+
- `a=[2, 5)` and `b=[3, 4)` => `False`
|
|
332
|
+
- `a=[2, 5)` and `b=[6, 8)` => `False`
|
|
333
|
+
"""
|
|
334
|
+
return TimeIntervalUtils.a_is_adjacent_to_b(
|
|
335
|
+
time_interval_a = self,
|
|
336
|
+
time_interval_b = time_interval
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
def do_contains_a(
|
|
340
|
+
self,
|
|
341
|
+
time_interval: 'TimeInterval'
|
|
342
|
+
) -> bool:
|
|
343
|
+
"""
|
|
344
|
+
Check if this time interval includes the `time_interval`
|
|
345
|
+
provided or not, which means that the `time_interval`
|
|
346
|
+
provided is fully contained (included) in this one.
|
|
347
|
+
"""
|
|
348
|
+
return TimeIntervalUtils.a_contains_b(
|
|
349
|
+
time_interval_a = self,
|
|
350
|
+
time_interval_b = time_interval
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
def is_contained_in(
|
|
354
|
+
self,
|
|
355
|
+
time_interval: 'TimeInterval'
|
|
356
|
+
) -> bool:
|
|
357
|
+
"""
|
|
358
|
+
Check if this time interval is fully contained in
|
|
359
|
+
the `time_interval` provided, which is a synonim
|
|
360
|
+
of being fully overlapped by that `time_interval`.
|
|
361
|
+
"""
|
|
362
|
+
return TimeIntervalUtils.a_is_contained_in_b(
|
|
363
|
+
time_interval_a = self,
|
|
364
|
+
time_interval_b = time_interval
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
def do_intersects_with(
|
|
368
|
+
self,
|
|
369
|
+
time_interval: 'TimeInterval'
|
|
370
|
+
) -> bool:
|
|
371
|
+
"""
|
|
372
|
+
Check if this time interval intersects with the one
|
|
373
|
+
provided as `time_interval`, which means that they
|
|
374
|
+
have at least a part in common.
|
|
375
|
+
"""
|
|
376
|
+
return TimeIntervalUtils.a_intersects_with_b(
|
|
377
|
+
time_interval_a = self,
|
|
378
|
+
time_interval_b = time_interval
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
def get_intersection_with_a(
|
|
382
|
+
self,
|
|
383
|
+
time_interval: 'TimeInterval'
|
|
384
|
+
) -> Union['TimeInterval', None]:
|
|
385
|
+
"""
|
|
386
|
+
Get the time interval that intersects this one and the
|
|
387
|
+
one provided as `time_interval`. The result can be `None`
|
|
388
|
+
if there is no intersection in between both.
|
|
389
|
+
"""
|
|
390
|
+
return TimeIntervalUtils.get_intersection_of_a_and_b(
|
|
391
|
+
time_interval_a = self,
|
|
392
|
+
time_interval_b = time_interval
|
|
393
|
+
)
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
class TimeIntervalUtils:
|
|
397
|
+
"""
|
|
398
|
+
Static class to wrap the utils related to time intervals.
|
|
399
|
+
"""
|
|
400
|
+
|
|
401
|
+
@staticmethod
|
|
402
|
+
def a_includes_t(
|
|
403
|
+
t: float,
|
|
404
|
+
time_interval_a: 'TimeInterval',
|
|
405
|
+
do_include_end: bool = False
|
|
406
|
+
) -> bool:
|
|
407
|
+
"""
|
|
408
|
+
Check if the `t` time moment provided is included in
|
|
409
|
+
the `time_interval_a` given. The `time_interval_a.end`
|
|
410
|
+
is excluded unless the `do_include_end` parameter is
|
|
411
|
+
set as `True`.
|
|
412
|
+
|
|
413
|
+
A time interval is `[start, end)`, thats why the end is
|
|
414
|
+
excluded by default.
|
|
415
|
+
"""
|
|
416
|
+
return (
|
|
417
|
+
time_interval_a.start <= t <= time_interval_a.end
|
|
418
|
+
if do_include_end else
|
|
419
|
+
time_interval_a.start <= t < time_interval_a.end
|
|
420
|
+
)
|
|
421
|
+
|
|
422
|
+
@staticmethod
|
|
423
|
+
def a_is_adjacent_to_b(
|
|
424
|
+
time_interval_a: 'TimeInterval',
|
|
425
|
+
time_interval_b: 'TimeInterval',
|
|
426
|
+
) -> bool:
|
|
427
|
+
"""
|
|
428
|
+
Check if the `time_interval_a` provided and the
|
|
429
|
+
also given `time_interval_b` are adjacent, which
|
|
430
|
+
means that the `end` of one interval is also the
|
|
431
|
+
`start` of the other one.
|
|
432
|
+
|
|
433
|
+
(!) Giving the time intervals inverted will
|
|
434
|
+
provide the same result.
|
|
435
|
+
|
|
436
|
+
Examples below:
|
|
437
|
+
- `a=[2, 5)` and `b=[5, 7)` => `True`
|
|
438
|
+
- `a=[5, 7)` and `b=[2, 5)` => `True`
|
|
439
|
+
- `a=[2, 5)` and `b=[3, 4)` => `False`
|
|
440
|
+
- `a=[2, 5)` and `b=[6, 8)` => `False`
|
|
441
|
+
"""
|
|
442
|
+
return (
|
|
443
|
+
TimeIntervalUtils.a_is_inmediately_before_b(time_interval_a, time_interval_b) or
|
|
444
|
+
TimeIntervalUtils.a_is_inmediately_after_b(time_interval_a, time_interval_b)
|
|
445
|
+
)
|
|
446
|
+
|
|
447
|
+
@staticmethod
|
|
448
|
+
def a_is_inmediately_before_b(
|
|
449
|
+
time_interval_a: 'TimeInterval',
|
|
450
|
+
time_interval_b: 'TimeInterval',
|
|
451
|
+
) -> bool:
|
|
452
|
+
"""
|
|
453
|
+
Check if the `time_interval_a` provided is inmediately
|
|
454
|
+
before the also given `time_interval_b`, which means
|
|
455
|
+
that the `end` of the first one is also the `start` of
|
|
456
|
+
the second one.
|
|
457
|
+
|
|
458
|
+
Examples below:
|
|
459
|
+
- `a=[2, 5)` and `b=[5, 7)` => `True`
|
|
460
|
+
- `a=[5, 7)` and `b=[2, 5)` => `False`
|
|
461
|
+
- `a=[2, 5)` and `b=[3, 4)` => `False`
|
|
462
|
+
- `a=[2, 5)` and `b=[6, 8)` => `False`
|
|
463
|
+
"""
|
|
464
|
+
return time_interval_a.end == time_interval_b.start
|
|
465
|
+
|
|
466
|
+
@staticmethod
|
|
467
|
+
def a_is_inmediately_after_b(
|
|
468
|
+
time_interval_a: 'TimeInterval',
|
|
469
|
+
time_interval_b: 'TimeInterval',
|
|
470
|
+
) -> bool:
|
|
471
|
+
"""
|
|
472
|
+
Check if the `time_interval_a` provided is inmediately
|
|
473
|
+
after the also given `time_interval_b`, which means
|
|
474
|
+
that the `start` of the first one is also the `end` of
|
|
475
|
+
the second one.
|
|
476
|
+
|
|
477
|
+
Examples below:
|
|
478
|
+
- `a=[2, 5)` and `b=[5, 7)` => `False`
|
|
479
|
+
- `a=[5, 7)` and `b=[2, 5)` => `True`
|
|
480
|
+
- `a=[2, 5)` and `b=[3, 4)` => `False`
|
|
481
|
+
- `a=[2, 5)` and `b=[6, 8)` => `False`
|
|
482
|
+
"""
|
|
483
|
+
return time_interval_a.start == time_interval_b.end
|
|
484
|
+
|
|
485
|
+
@staticmethod
|
|
486
|
+
def a_contains_b(
|
|
487
|
+
time_interval_a: 'TimeInterval',
|
|
488
|
+
time_interval_b: 'TimeInterval'
|
|
489
|
+
) -> bool:
|
|
490
|
+
"""
|
|
491
|
+
Check if the `time_interval_a` time interval provided
|
|
492
|
+
includes the `time_interval_b` or not, which means that
|
|
493
|
+
the `time_interval_b` is fully contained in the first
|
|
494
|
+
one.
|
|
495
|
+
|
|
496
|
+
Examples below:
|
|
497
|
+
- `a=[2, 5)` and `b=[3, 4)` => `True`
|
|
498
|
+
- `a=[2, 5)` and `b=[2, 4)` => `True`
|
|
499
|
+
- `a=[2, 5)` and `b=[3, 6)` => `False`
|
|
500
|
+
- `a=[2, 5)` and `b=[6, 8)` => `False`
|
|
501
|
+
"""
|
|
502
|
+
return (
|
|
503
|
+
time_interval_a.start <= time_interval_b.start and
|
|
504
|
+
time_interval_a.end >= time_interval_b.end
|
|
505
|
+
)
|
|
506
|
+
|
|
507
|
+
@staticmethod
|
|
508
|
+
def a_is_contained_in_b(
|
|
509
|
+
time_interval_a: 'TimeInterval',
|
|
510
|
+
time_interval_b: 'TimeInterval',
|
|
511
|
+
) -> bool:
|
|
512
|
+
"""
|
|
513
|
+
Check if the `time_interval_a` provided is fully
|
|
514
|
+
contained into the also provided `time_interval_b`.
|
|
515
|
+
|
|
516
|
+
Examples below:
|
|
517
|
+
- `a=[2, 5)` and `b=[1, 6)` => `True`
|
|
518
|
+
- `a=[2, 5)` and `b=[0, 9)` => `True`
|
|
519
|
+
- `a=[2, 5)` and `b=[2, 4)` => `False`
|
|
520
|
+
- `a=[2, 5)` and `b=[4, 8)` => `False`
|
|
521
|
+
- `a=[2, 5)` and `b=[7, 8)` => `False`
|
|
522
|
+
"""
|
|
523
|
+
return TimeIntervalUtils.a_contains_b(
|
|
524
|
+
time_interval_a = time_interval_b,
|
|
525
|
+
time_interval_b = time_interval_a
|
|
526
|
+
)
|
|
527
|
+
|
|
528
|
+
@staticmethod
|
|
529
|
+
def a_intersects_with_b(
|
|
530
|
+
time_interval_a: 'TimeInterval',
|
|
531
|
+
time_interval_b: 'TimeInterval',
|
|
532
|
+
) -> bool:
|
|
533
|
+
"""
|
|
534
|
+
Check if the `time_interval_a` and the `time_interval_b`
|
|
535
|
+
provided has at least a part in common.
|
|
536
|
+
|
|
537
|
+
Examples below:
|
|
538
|
+
- `a=[2, 5)` and `b=[4, 6)` => `True`
|
|
539
|
+
- `a=[2, 5)` and `b=[1, 3)` => `True`
|
|
540
|
+
- `a=[2, 5)` and `b=[5, 6)` => `False`
|
|
541
|
+
- `a=[2, 5)` and `b=[7, 8)` => `False`
|
|
542
|
+
- `a=[2, 5)` and `b=[1, 2)` => `False`
|
|
543
|
+
"""
|
|
544
|
+
return (
|
|
545
|
+
time_interval_b.start < time_interval_a.end and
|
|
546
|
+
time_interval_a.start < time_interval_b.end
|
|
547
|
+
)
|
|
548
|
+
|
|
549
|
+
@staticmethod
|
|
550
|
+
def get_intersection_of_a_and_b(
|
|
551
|
+
time_interval_a: 'TimeInterval',
|
|
552
|
+
time_interval_b: 'TimeInterval'
|
|
553
|
+
) -> Union['TimeInterval', None]:
|
|
554
|
+
"""
|
|
555
|
+
Get the time interval that intersects the two time
|
|
556
|
+
intervals provided, that can be `None` if there is no
|
|
557
|
+
intersection in between both.
|
|
558
|
+
"""
|
|
559
|
+
return (
|
|
560
|
+
None
|
|
561
|
+
if not TimeIntervalUtils.a_intersects_with_b(
|
|
562
|
+
time_interval_a = time_interval_a,
|
|
563
|
+
time_interval_b = time_interval_b
|
|
564
|
+
) else
|
|
565
|
+
TimeInterval(
|
|
566
|
+
start = max(time_interval_a.start, time_interval_b.start),
|
|
567
|
+
end = min(time_interval_a.end, time_interval_b.end)
|
|
568
|
+
)
|
|
569
|
+
)
|
|
File without changes
|
|
File without changes
|
{yta_video_frame_time-0.0.12 → yta_video_frame_time-0.0.13}/src/yta_video_frame_time/__init__.py
RENAMED
|
File without changes
|
{yta_video_frame_time-0.0.12 → yta_video_frame_time-0.0.13}/src/yta_video_frame_time/t_fraction.py
RENAMED
|
File without changes
|