Skip to content

Commit 8b2e34d

Browse files
authored
Simplify the animation logic within Scene (#562)
Remove several extraneous functions and function arguments from scene.py
1 parent 7f17bc2 commit 8b2e34d

File tree

4 files changed

+218
-259
lines changed

4 files changed

+218
-259
lines changed

manim/renderer/cairo_renderer.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ def __init__(self, camera_class=None, **kwargs):
7676
self.animations_hashes = []
7777
self.num_plays = 0
7878
self.time = 0
79+
self.static_mobject_data = None
7980

8081
def init(self, scene):
8182
self.file_writer = SceneFileWriter(
@@ -101,7 +102,6 @@ def update_frame( # TODO Description in Docstring
101102
self,
102103
scene,
103104
mobjects=None,
104-
background=None,
105105
include_submobjects=True,
106106
ignore_skipping=True,
107107
**kwargs,
@@ -130,8 +130,8 @@ def update_frame( # TODO Description in Docstring
130130
scene.mobjects,
131131
scene.foreground_mobjects,
132132
)
133-
if background is not None:
134-
self.camera.set_frame_to_background(background)
133+
if self.static_mobject_data is not None:
134+
self.camera.set_frame_to_background(self.static_mobject_data)
135135
else:
136136
self.camera.reset()
137137

@@ -150,6 +150,10 @@ def get_frame(self):
150150
"""
151151
return np.array(self.camera.pixel_array)
152152

153+
def save_static_mobject_data(self, scene, static_mobjects):
154+
self.update_frame(scene, static_mobjects)
155+
self.static_mobject_data = self.get_frame()
156+
153157
def add_frame(self, frame, num_frames=1):
154158
"""
155159
Adds a frame to the video_file_stream

manim/scene/scene.py

Lines changed: 50 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,23 @@ def get_moving_mobjects(self, *animations):
530530
return mobjects[i:]
531531
return []
532532

533+
def get_moving_and_static_mobjects(self, animations):
534+
all_mobjects = list_update(self.mobjects, self.foreground_mobjects)
535+
all_mobject_families = extract_mobject_family_members(
536+
all_mobjects,
537+
use_z_index=self.renderer.camera.use_z_index,
538+
only_those_with_points=True,
539+
)
540+
moving_mobjects = self.get_moving_mobjects(*animations)
541+
all_moving_mobject_families = extract_mobject_family_members(
542+
moving_mobjects,
543+
use_z_index=self.renderer.camera.use_z_index,
544+
)
545+
static_mobjects = filter(
546+
lambda m: m not in all_moving_mobject_families, all_mobject_families
547+
)
548+
return all_moving_mobject_families, static_mobjects
549+
533550
def get_time_progression(
534551
self, run_time, n_iterations=None, override_skip_animations=False
535552
):
@@ -611,7 +628,8 @@ def get_animation_time_progression(self, animations):
611628
ProgressDisplay
612629
The CommandLine Progress Bar.
613630
"""
614-
time_progression = self.get_time_progression(self.run_time)
631+
run_time = self.get_run_time(animations)
632+
time_progression = self.get_time_progression(run_time)
615633
time_progression.set_description(
616634
"".join(
617635
[
@@ -702,77 +720,12 @@ def compile_method(state):
702720

703721
return animations
704722

705-
def begin_animations(self, animations):
706-
"""
707-
This method begins the list of animations that is passed,
708-
and adds any mobjects involved (if not already present)
709-
to the scene again.
710-
711-
Parameters
712-
----------
713-
animations : list
714-
List of involved animations.
715-
716-
"""
717-
for animation in animations:
718-
# Begin animation
719-
animation.begin()
720-
721-
def progress_through_animations(self):
722-
"""
723-
This method progresses through each animation
724-
in the list passed and and updates the frames as required.
725-
"""
726-
for t in self.get_animation_time_progression(self.animations):
727-
self.update_animation_to_time(t)
728-
self.renderer.update_frame(self, self.moving_mobjects, self.static_image)
729-
self.renderer.add_frame(self.renderer.get_frame())
730-
731-
def update_animation_to_time(self, t):
732-
"""
733-
Updates the current animation to the specified time.
734-
735-
Parameters
736-
----------
737-
t : int
738-
Offset from the start of the animation to which to update the current
739-
animation.
740-
"""
741-
dt = t - self.last_t
742-
self.last_t = t
743-
for animation in self.animations:
744-
animation.update_mobjects(dt)
745-
alpha = t / animation.run_time
746-
animation.interpolate(alpha)
747-
self.update_mobjects(dt)
748-
749-
def finish_animations(self, animations):
750-
"""
751-
This function cleans up after the end
752-
of each animation in the passed list.
753-
754-
Parameters
755-
----------
756-
animations : list
757-
list of animations to finish.
758-
"""
759-
for animation in animations:
760-
animation.finish()
761-
animation.clean_up_from_scene(self)
762-
# TODO: This is only used in one place and should probably be removed.
763-
self.mobjects_from_last_animation = [anim.mobject for anim in animations]
764-
if file_writer_config["skip_animations"]:
765-
# TODO, run this call in for each animation?
766-
self.update_mobjects(self.get_run_time(animations))
767-
else:
768-
self.update_mobjects(0)
723+
def play(self, *args, **kwargs):
724+
self.renderer.play(self, *args, **kwargs)
769725

770726
def wait(self, duration=DEFAULT_WAIT_TIME, stop_condition=None):
771727
self.renderer.wait(self, duration=duration, stop_condition=stop_condition)
772728

773-
def play(self, *args, **kwargs):
774-
self.renderer.play(self, *args, **kwargs)
775-
776729
def play_internal(self, *args, **kwargs):
777730
"""
778731
This method is used to prep the animations for rendering,
@@ -782,47 +735,59 @@ def play_internal(self, *args, **kwargs):
782735
Parameters
783736
----------
784737
*args : Animation or mobject with mobject method and params
785-
**kwargs : named parameters affecting what was passed in *args e.g run_time, lag_ratio etc.
738+
**kwargs : named parameters affecting what was passed in *args e.g
739+
run_time, lag_ratio etc.
786740
"""
787741
if len(args) == 0:
788742
warnings.warn("Called Scene.play with no animations")
789743
return
790-
self.animations = self.compile_play_args_to_animation_list(*args, **kwargs)
791-
self.begin_animations(self.animations)
744+
745+
animations = self.compile_play_args_to_animation_list(*args, **kwargs)
746+
for animation in animations:
747+
animation.begin()
792748

793749
# Paint all non-moving objects onto the screen, so they don't
794750
# have to be rendered every frame
795-
self.moving_mobjects = self.get_moving_mobjects(*self.animations)
796-
self.renderer.update_frame(self, excluded_mobjects=self.moving_mobjects)
797-
self.static_image = self.renderer.get_frame()
798-
self.last_t = 0
799-
self.run_time = self.get_run_time(self.animations)
800-
801-
self.progress_through_animations()
751+
moving_mobjects, static_mobjects = self.get_moving_and_static_mobjects(
752+
animations
753+
)
754+
self.renderer.save_static_mobject_data(self, static_mobjects)
755+
756+
last_t = 0
757+
for t in self.get_animation_time_progression(animations):
758+
dt = t - last_t
759+
last_t = t
760+
for animation in animations:
761+
animation.update_mobjects(dt)
762+
alpha = t / animation.run_time
763+
animation.interpolate(alpha)
764+
self.update_mobjects(dt)
765+
self.renderer.update_frame(self, moving_mobjects)
766+
self.renderer.add_frame(self.renderer.get_frame())
802767

803-
self.finish_animations(self.animations)
768+
for animation in animations:
769+
animation.finish()
770+
animation.clean_up_from_scene(self)
804771

805772
def wait_internal(self, duration=DEFAULT_WAIT_TIME, stop_condition=None):
806773
self.update_mobjects(dt=0) # Any problems with this?
807-
self.animations = []
808774
self.duration = duration
809775
self.stop_condition = stop_condition
810-
self.last_t = 0
776+
last_t = 0
811777

812778
if self.should_update_mobjects():
813779
time_progression = self.get_wait_time_progression(duration, stop_condition)
814780
# TODO, be smart about setting a static image
815781
# the same way Scene.play does
816782
for t in time_progression:
817-
self.update_animation_to_time(t)
783+
dt = t - last_t
784+
last_t = t
785+
self.update_mobjects(dt)
818786
self.renderer.update_frame(self)
819787
self.renderer.add_frame(self.renderer.get_frame())
820788
if stop_condition is not None and stop_condition():
821789
time_progression.close()
822790
break
823-
elif self.skip_animations:
824-
# Do nothing
825-
return self
826791
else:
827792
self.renderer.update_frame(self)
828793
dt = 1 / self.renderer.camera.frame_rate
@@ -831,27 +796,6 @@ def wait_internal(self, duration=DEFAULT_WAIT_TIME, stop_condition=None):
831796
)
832797
return self
833798

834-
def clean_up_animations(self, *animations):
835-
"""
836-
This method cleans up and removes from the
837-
scene all the animations that were passed
838-
839-
Parameters
840-
----------
841-
*animations : Animation
842-
Animation to clean up.
843-
844-
Returns
845-
-------
846-
Scene
847-
The scene with the animations
848-
cleaned up.
849-
850-
"""
851-
for animation in animations:
852-
animation.clean_up_from_scene(self)
853-
return self
854-
855799
def get_wait_time_progression(self, duration, stop_condition):
856800
"""
857801
This method is used internally to obtain the CommandLine

manim/scene/vector_space_scene.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -401,13 +401,14 @@ def coords_to_vector(self, vector, coords_start=2 * RIGHT + 2 * UP, clean_up=Tru
401401
)
402402
)
403403
self.play(ShowCreation(x_line))
404-
self.play(
404+
animations = [
405405
ApplyFunction(
406406
lambda y: self.position_y_coordinate(y, y_line, vector), y_coord
407407
),
408408
FadeOut(array.get_brackets()),
409-
)
410-
y_coord, brackets = self.mobjects_from_last_animation
409+
]
410+
self.play(*animations)
411+
y_coord, _ = [anim.mobject for anim in animations]
411412
self.play(ShowCreation(y_line))
412413
self.play(ShowCreation(arrow))
413414
self.wait()

0 commit comments

Comments
 (0)