from functools import reduce import numpy as np from manimlib.constants import * from manimlib.animation.animation import Animation from manimlib.animation.movement import Homotopy 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.creation import FadeOut from manimlib.animation.transform import Transform from manimlib.animation.update import UpdateFromAlphaFunc from manimlib.mobject.mobject import Mobject from manimlib.mobject.geometry import Circle from manimlib.mobject.geometry import Dot from manimlib.mobject.shape_matchers import SurroundingRectangle from manimlib.mobject.types.vectorized_mobject import VGroup from manimlib.mobject.geometry import Line from manimlib.utils.bezier import interpolate from manimlib.utils.config_ops import digest_config from manimlib.utils.rate_functions import linear from manimlib.utils.rate_functions import smooth from manimlib.utils.rate_functions import squish_rate_func from manimlib.utils.rate_functions import there_and_back from manimlib.utils.rate_functions import wiggle class FocusOn(Transform): CONFIG = { "opacity": 0.2, "color": GREY, "run_time": 2, "remover": True, } def __init__(self, mobject_or_point, **kwargs): digest_config(self, kwargs) big_dot = 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): CONFIG = { "rate_func": there_and_back, "scale_factor": 1.2, "color": YELLOW, } def __init__(self, mobject, **kwargs): digest_config(self, kwargs) target = mobject.copy() target.scale_in_place(self.scale_factor) target.set_color(self.color) Transform.__init__(self, mobject, target, **kwargs) class Flash(AnimationGroup): CONFIG = { "line_length": 0.2, "num_lines": 12, "flash_radius": 0.3, "line_stroke_width": 3, } def __init__(self, point, color=YELLOW, **kwargs): digest_config(self, kwargs) 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_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 ] AnimationGroup.__init__( self, *line_anims + fade_anims, **kwargs ) class CircleIndicate(Indicate): CONFIG = { "rate_func": squish_rate_func(there_and_back, 0, 0.8), "remover": True } def __init__(self, mobject, **kwargs): digest_config(self, kwargs) circle = Circle(color=self.color, **kwargs) circle.surround(mobject) Indicate.__init__(self, circle, **kwargs) class ShowPassingFlash(ShowPartial): CONFIG = { "time_width": 0.1, "remover": True, } def get_bounds(self, alpha): tw = self.time_width upper = interpolate(0, 1 + tw, alpha) lower = upper - tw upper = min(upper, 1) 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) class ShowCreationThenDestruction(ShowPassingFlash): CONFIG = { "time_width": 2.0, "run_time": 1, } class ShowCreationThenFadeOut(Succession): CONFIG = { "remover": True, } def __init__(self, mobject, **kwargs): Succession.__init__( self, ShowCreation, mobject, FadeOut, mobject, **kwargs ) class AnimationOnSurroundingRectangle(AnimationGroup): CONFIG = { "surrounding_rectangle_config": {}, # Function which takes in a rectangle, and spits # out some animation. Could be some animation class, # could be something more "rect_to_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)) class ShowPassingFlashAround(AnimationOnSurroundingRectangle): CONFIG = { "rect_to_animation": ShowPassingFlash } class ShowCreationThenDestructionAround(AnimationOnSurroundingRectangle): CONFIG = { "rect_to_animation": ShowCreationThenDestruction } class ShowCreationThenFadeAround(AnimationOnSurroundingRectangle): CONFIG = { "rect_to_animation": ShowCreationThenFadeOut } class ApplyWave(Homotopy): CONFIG = { "direction": UP, "amplitude": 0.2, "run_time": 1, } def __init__(self, mobject, **kwargs): digest_config(self, kwargs, locals()) left_x = mobject.get_left()[0] right_x = mobject.get_right()[0] vect = self.amplitude * self.direction def homotopy(x, y, z, t): alpha = (x - left_x) / (right_x - left_x) # lf = self.lag_factor power = np.exp(2.0 * (alpha - 0.5)) nudge = there_and_back(t**power) return np.array([x, y, z]) + nudge * vect Homotopy.__init__(self, homotopy, mobject, **kwargs) class WiggleOutThenIn(Animation): CONFIG = { "scale_value": 1.1, "rotation_angle": 0.01 * TAU, "n_wiggles": 6, "run_time": 2, "scale_about_point": None, "rotate_about_point": None, } def __init__(self, mobject, **kwargs): digest_config(self, kwargs) if self.scale_about_point is None: self.scale_about_point = mobject.get_center() if self.rotate_about_point is None: self.rotate_about_point = mobject.get_center() Animation.__init__(self, mobject, **kwargs) def interpolate_submobject(self, submobject, starting_sumobject, alpha): submobject.points[:, :] = starting_sumobject.points submobject.scale( interpolate(1, self.scale_value, there_and_back(alpha)), about_point=self.scale_about_point ) submobject.rotate( wiggle(alpha, self.n_wiggles) * self.rotation_angle, about_point=self.rotate_about_point ) class Vibrate(Animation): CONFIG = { "spatial_period": 6, "temporal_period": 1, "overtones": 4, "amplitude": 0.5, "radius": FRAME_X_RADIUS / 2, "run_time": 3.0, "rate_func": linear } def __init__(self, mobject=None, **kwargs): if mobject is None: mobject = Line(3 * LEFT, 3 * RIGHT) Animation.__init__(self, mobject, **kwargs) def wave_function(self, x, t): return sum([ reduce(op.mul, [ self.amplitude / (k**2), # Amplitude np.sin(2 * np.pi * (k**1.5) * t / \ self.temporal_period), # Frequency # Number of waves np.sin(2 * np.pi * k * x / self.spatial_period) ]) for k in range(1, self.overtones + 1) ]) def interpolate_mobject(self, alpha): time = alpha * self.run_time families = list(map( Mobject.get_family, [self.mobject, self.starting_mobject] )) for mob, start in zip(*families): mob.points = np.apply_along_axis( lambda x_y_z: ( x_y_z[0], x_y_z[1] + self.wave_function(x_y_z[0], time), x_y_z[2]), 1, start.points ) class TurnInsideOut(Transform): CONFIG = { "path_arc": TAU / 4, } def __init__(self, mobject, **kwargs): mob_copy = mobject.copy() mob_copy.reverse_points() Transform.__init__(self, mobject, mob_copy, **kwargs)