Skip to content

Commit a96ad3e

Browse files
marcin-serwinpre-commit-ci[bot]Darylgolden
authored
Fixed animations introducing or removing objects (#2396)
* Replace finish with clean_up_from_scene in ShowPassingFlash * Add introducer flag to animations * Mark some animations as introducers * Handle animating graph * Update tests * Update tests to provide mocked scene * Make setup_scene internal * Replace string annotation with new typehints * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Darylgolden <[email protected]>
1 parent 6e1ad57 commit a96ad3e

File tree

12 files changed

+236
-77
lines changed

12 files changed

+236
-77
lines changed

manim/animation/animation.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,15 +134,20 @@ def __init__(
134134
name: str = None,
135135
remover: bool = False, # remove a mobject from the screen?
136136
suspend_mobject_updating: bool = True,
137+
introducer: bool = False,
138+
*,
139+
_on_finish: Callable[[], None] = lambda _: None,
137140
**kwargs,
138141
) -> None:
139142
self._typecheck_input(mobject)
140143
self.run_time: float = run_time
141144
self.rate_func: Callable[[float], float] = rate_func
142145
self.name: str | None = name
143146
self.remover: bool = remover
147+
self.introducer: bool = introducer
144148
self.suspend_mobject_updating: bool = suspend_mobject_updating
145149
self.lag_ratio: float = lag_ratio
150+
self._on_finish: Callable[[Scene], None] = _on_finish
146151
if config["renderer"] == "opengl":
147152
self.starting_mobject: OpenGLMobject = OpenGLMobject()
148153
self.mobject: OpenGLMobject = (
@@ -219,9 +224,26 @@ def clean_up_from_scene(self, scene: Scene) -> None:
219224
scene
220225
The scene the animation should be cleaned up from.
221226
"""
227+
self._on_finish(scene)
222228
if self.is_remover():
223229
scene.remove(self.mobject)
224230

231+
def _setup_scene(self, scene: Scene) -> None:
232+
"""Setup up the :class:`~.Scene` before starting the animation.
233+
234+
This includes to :meth:`~.Scene.add` the Animation's
235+
:class:`~.Mobject` if the animation is an introducer.
236+
237+
Parameters
238+
----------
239+
scene
240+
The scene the animation should be cleaned up from.
241+
"""
242+
if scene is None:
243+
return
244+
if self.is_introducer():
245+
scene.add(self.mobject)
246+
225247
def create_starting_mobject(self) -> Mobject:
226248
# Keep track of where the mobject starts
227249
return self.mobject.copy()
@@ -436,6 +458,16 @@ def is_remover(self) -> bool:
436458
"""
437459
return self.remover
438460

461+
def is_introducer(self) -> bool:
462+
"""Test if a the animation is a remover.
463+
464+
Returns
465+
-------
466+
bool
467+
``True`` if the animation is a remover, ``False`` otherwise.
468+
"""
469+
return self.introducer
470+
439471

440472
def prepare_animation(
441473
anim: Animation | mobject._AnimationBuilder,

manim/animation/composition.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def __init__(
3939
self.group = group
4040
if self.group is None:
4141
mobjects = remove_list_redundancies(
42-
[anim.mobject for anim in self.animations],
42+
[anim.mobject for anim in self.animations if not anim.is_introducer()],
4343
)
4444
if config["renderer"] == "opengl":
4545
self.group = OpenGLGroup(*mobjects)
@@ -57,13 +57,18 @@ def begin(self) -> None:
5757
for anim in self.animations:
5858
anim.begin()
5959

60+
def _setup_scene(self, scene) -> None:
61+
for anim in self.animations:
62+
anim._setup_scene(scene)
63+
6064
def finish(self) -> None:
6165
for anim in self.animations:
6266
anim.finish()
6367
if self.suspend_mobject_updating:
6468
self.group.resume_updating()
6569

6670
def clean_up_from_scene(self, scene: Scene) -> None:
71+
self._on_finish(scene)
6772
for anim in self.animations:
6873
if self.remover:
6974
anim.remover = self.remover
@@ -127,6 +132,16 @@ def update_mobjects(self, dt: float) -> None:
127132
if self.active_animation:
128133
self.active_animation.update_mobjects(dt)
129134

135+
def _setup_scene(self, scene) -> None:
136+
if scene is None:
137+
return
138+
if self.is_introducer():
139+
for anim in self.animations:
140+
if not anim.is_introducer() and anim.mobject is not None:
141+
scene.add(anim.mobject)
142+
143+
self.scene = scene
144+
130145
def update_active_animation(self, index: int) -> None:
131146
self.active_index = index
132147
if index >= len(self.animations):
@@ -135,6 +150,7 @@ def update_active_animation(self, index: int) -> None:
135150
self.active_end_time: float | None = None
136151
else:
137152
self.active_animation = self.animations[index]
153+
self.active_animation._setup_scene(self.scene)
138154
self.active_animation.begin()
139155
self.active_start_time = self.anims_with_timings[index][1]
140156
self.active_end_time = self.anims_with_timings[index][2]

manim/animation/creation.py

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,9 @@ class ShowPartial(Animation):
115115
"""
116116

117117
def __init__(
118-
self, mobject: VMobject | OpenGLVMobject | OpenGLSurface | None, **kwargs
118+
self,
119+
mobject: VMobject | OpenGLVMobject | OpenGLSurface | None,
120+
**kwargs,
119121
):
120122
pointwise = getattr(mobject, "pointwise_become_partial", None)
121123
if not callable(pointwise):
@@ -167,9 +169,10 @@ def __init__(
167169
self,
168170
mobject: VMobject | OpenGLVMobject | OpenGLSurface,
169171
lag_ratio: float = 1.0,
172+
introducer: bool = True,
170173
**kwargs,
171174
) -> None:
172-
super().__init__(mobject, lag_ratio=lag_ratio, **kwargs)
175+
super().__init__(mobject, lag_ratio=lag_ratio, introducer=introducer, **kwargs)
173176

174177
def _get_bounds(self, alpha: float) -> tuple[int, float]:
175178
return (0, alpha)
@@ -199,7 +202,13 @@ def __init__(
199202
remover: bool = True,
200203
**kwargs,
201204
) -> None:
202-
super().__init__(mobject, rate_func=rate_func, remover=remover, **kwargs)
205+
super().__init__(
206+
mobject,
207+
rate_func=rate_func,
208+
introducer=False,
209+
remover=remover,
210+
**kwargs,
211+
)
203212

204213

205214
class DrawBorderThenFill(Animation):
@@ -223,10 +232,17 @@ def __init__(
223232
stroke_color: str = None,
224233
draw_border_animation_config: dict = {}, # what does this dict accept?
225234
fill_animation_config: dict = {},
235+
introducer: bool = True,
226236
**kwargs,
227237
) -> None:
228238
self._typecheck_input(vmobject)
229-
super().__init__(vmobject, run_time=run_time, rate_func=rate_func, **kwargs)
239+
super().__init__(
240+
vmobject,
241+
run_time=run_time,
242+
introducer=introducer,
243+
rate_func=rate_func,
244+
**kwargs,
245+
)
230246
self.stroke_width = stroke_width
231247
self.stroke_color = stroke_color
232248
self.draw_border_animation_config = draw_border_animation_config
@@ -308,11 +324,14 @@ def __init__(
308324
lag_ratio,
309325
)
310326
self.reverse = reverse
327+
if "remover" not in kwargs:
328+
kwargs["remover"] = reverse
311329
super().__init__(
312330
vmobject,
313331
rate_func=rate_func,
314332
run_time=run_time,
315333
lag_ratio=lag_ratio,
334+
introducer=not reverse,
316335
**kwargs,
317336
)
318337

manim/animation/fading.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ def construct(self):
137137
138138
"""
139139

140+
def __init__(self, *mobjects: Mobject, **kwargs) -> None:
141+
super().__init__(*mobjects, introducer=True, **kwargs)
142+
140143
def create_target(self):
141144
return self.mobject
142145

manim/animation/growing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ def __init__(
7979
) -> None:
8080
self.point = point
8181
self.point_color = point_color
82-
super().__init__(mobject, **kwargs)
82+
super().__init__(mobject, introducer=True, **kwargs)
8383

8484
def create_target(self) -> Mobject:
8585
return self.mobject

manim/animation/indication.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ def construct(self):
300300

301301
def __init__(self, mobject: "VMobject", time_width: float = 0.1, **kwargs) -> None:
302302
self.time_width = time_width
303-
super().__init__(mobject, remover=True, **kwargs)
303+
super().__init__(mobject, remover=True, introducer=True, **kwargs)
304304

305305
def _get_bounds(self, alpha: float) -> Tuple[float]:
306306
tw = self.time_width
@@ -310,8 +310,8 @@ def _get_bounds(self, alpha: float) -> Tuple[float]:
310310
lower = max(lower, 0)
311311
return (lower, upper)
312312

313-
def finish(self) -> None:
314-
super().finish()
313+
def clean_up_from_scene(self, scene: "Scene") -> None:
314+
super().clean_up_from_scene(scene)
315315
for submob, start in self.get_all_families_zipped():
316316
submob.pointwise_become_partial(start, 0, 1)
317317

0 commit comments

Comments
 (0)