diff --git a/manimlib/animation/indication.py b/manimlib/animation/indication.py index aebcb6a1..1a367f89 100644 --- a/manimlib/animation/indication.py +++ b/manimlib/animation/indication.py @@ -9,10 +9,13 @@ from manimlib.animation.composition import AnimationGroup from manimlib.animation.composition import Succession from manimlib.animation.creation import ShowCreation from manimlib.animation.creation import ShowPartial +from manimlib.animation.fading import FadeIn from manimlib.animation.fading import FadeOut from manimlib.animation.transform import Transform from manimlib.animation.update import UpdateFromAlphaFunc +from manimlib.mobject.updater import updating_mobject_from_func from manimlib.mobject.mobject import Mobject +from manimlib.mobject.types.vectorized_mobject import VMobject from manimlib.mobject.geometry import Circle from manimlib.mobject.geometry import Dot from manimlib.mobject.shape_matchers import SurroundingRectangle @@ -35,19 +38,27 @@ class FocusOn(Transform): "remover": True, } - def __init__(self, mobject_or_point, **kwargs): - digest_config(self, kwargs) - big_dot = Dot( + def __init__(self, focus_point, **kwargs): + self.focus_point = focus_point + # Initialize with blank mobject, while create_target + # and create_starting_mobject handle the meat + super().__init__(VMobject(), **kwargs) + + def create_target(self): + little_dot = Dot(radius=0) + little_dot.set_fill(self.color, opacity=self.opacity) + little_dot.add_updater( + lambda d: d.move_to(self.focus_point) + ) + return little_dot + + def create_starting_mobject(self): + return Dot( radius=FRAME_X_RADIUS + FRAME_Y_RADIUS, stroke_width=0, fill_color=self.color, fill_opacity=0, ) - little_dot = Dot(radius=0) - little_dot.set_fill(self.color, opacity=self.opacity) - little_dot.move_to(mobject_or_point) - - Transform.__init__(self, big_dot, little_dot, **kwargs) class Indicate(Transform): @@ -57,12 +68,11 @@ class Indicate(Transform): "color": YELLOW, } - def __init__(self, mobject, **kwargs): - digest_config(self, kwargs) - target = mobject.copy() + def create_target(self): + target = self.mobject.copy() target.scale_in_place(self.scale_factor) target.set_color(self.color) - Transform.__init__(self, mobject, target, **kwargs) + return target class Flash(AnimationGroup): @@ -71,51 +81,62 @@ class Flash(AnimationGroup): "num_lines": 12, "flash_radius": 0.3, "line_stroke_width": 3, + "run_time": 1, } def __init__(self, point, color=YELLOW, **kwargs): + self.point = point + self.color = color digest_config(self, kwargs) + self.lines = self.create_lines() + animations = self.create_line_anims() + super().__init__( + *animations, + group=self.lines, + **kwargs, + ) + + def create_lines(self): lines = VGroup() for angle in np.arange(0, TAU, TAU / self.num_lines): line = Line(ORIGIN, self.line_length * RIGHT) line.shift((self.flash_radius - self.line_length) * RIGHT) line.rotate(angle, about_point=ORIGIN) lines.add(line) - lines.move_to(point) - lines.set_color(color) + lines.set_color(self.color) lines.set_stroke(width=3) - line_anims = [ - ShowCreationThenDestruction( - line, rate_func=squish_rate_func(smooth, 0, 0.5) - ) - for line in lines - ] - fade_anims = [ - UpdateFromAlphaFunc( - line, lambda m, a: m.set_stroke( - width=self.line_stroke_width * (1 - a) - ), - rate_func=squish_rate_func(smooth, 0, 0.75) - ) - for line in lines - ] + lines.add_updater(lambda l: l.move_to(self.point)) + return lines - AnimationGroup.__init__( - self, *line_anims + fade_anims, **kwargs - ) + def create_line_anims(self): + return [ + ShowCreationThenDestruction(line) + for line in self.lines + ] class CircleIndicate(Indicate): CONFIG = { - "rate_func": squish_rate_func(there_and_back, 0, 0.8), - "remover": True + "rate_func": there_and_back, + "remover": True, + "circle_config": { + "color": YELLOW, + }, } def __init__(self, mobject, **kwargs): digest_config(self, kwargs) - circle = Circle(color=self.color, **kwargs) - circle.surround(mobject) - Indicate.__init__(self, circle, **kwargs) + circle = self.get_circle(mobject) + super().__init__(circle, **kwargs) + + def get_circle(self, mobject): + circle = Circle(**self.circle_config) + circle.add_updater(lambda c: c.surround(mobject)) + return circle + + def interpolate_mobject(self, alpha): + super().interpolate_mobject(alpha) + self.mobject.set_stroke(opacity=alpha) class ShowPassingFlash(ShowPartial): @@ -132,10 +153,10 @@ class ShowPassingFlash(ShowPartial): lower = max(lower, 0) return (lower, upper) - def clean_up_from_scene(self, *args, **kwargs): - ShowPartial.clean_up_from_scene(self, *args, **kwargs) - for submob, start_submob in self.get_all_families_zipped(): - submob.pointwise_become_partial(start_submob, 0, 1) + def finish(self): + super().finish() + for submob, start in self.get_all_families_zipped(): + submob.pointwise_become_partial(start, 0, 1) class ShowCreationThenDestruction(ShowPassingFlash): @@ -151,10 +172,9 @@ class ShowCreationThenFadeOut(Succession): } def __init__(self, mobject, **kwargs): - Succession.__init__( - self, - ShowCreation, mobject, - FadeOut, mobject, + super().__init__( + ShowCreation(mobject), + FadeOut(mobject), **kwargs ) @@ -165,34 +185,44 @@ class AnimationOnSurroundingRectangle(AnimationGroup): # Function which takes in a rectangle, and spits # out some animation. Could be some animation class, # could be something more - "rect_to_animation": Animation + "rect_animation": Animation } def __init__(self, mobject, **kwargs): digest_config(self, kwargs) - rect = SurroundingRectangle( - mobject, **self.surrounding_rectangle_config - ) if "surrounding_rectangle_config" in kwargs: kwargs.pop("surrounding_rectangle_config") - AnimationGroup.__init__(self, self.rect_to_animation(rect, **kwargs)) + self.mobject_to_surround = mobject + + rect = self.get_rect() + rect.add_updater(lambda r: r.move_to(mobject)) + + super().__init__( + self.rect_animation(rect, **kwargs), + ) + + def get_rect(self): + return SurroundingRectangle( + self.mobject_to_surround, + **self.surrounding_rectangle_config + ) class ShowPassingFlashAround(AnimationOnSurroundingRectangle): CONFIG = { - "rect_to_animation": ShowPassingFlash + "rect_animation": ShowPassingFlash } class ShowCreationThenDestructionAround(AnimationOnSurroundingRectangle): CONFIG = { - "rect_to_animation": ShowCreationThenDestruction + "rect_animation": ShowCreationThenDestruction } class ShowCreationThenFadeAround(AnimationOnSurroundingRectangle): CONFIG = { - "rect_to_animation": ShowCreationThenFadeOut + "rect_animation": ShowCreationThenFadeOut }