From f76f1b65de11ebe48b8b8455e871e9875097dde5 Mon Sep 17 00:00:00 2001 From: Devin Neal Date: Wed, 20 May 2020 20:18:05 -0700 Subject: [PATCH] Remove more 3b1b files --- manimlib/for_3b1b_videos/common_scenes.py | 395 ------------------ manimlib/for_3b1b_videos/pi_class.py | 18 - manimlib/for_3b1b_videos/pi_creature.py | 389 ----------------- .../for_3b1b_videos/pi_creature_animations.py | 122 ------ manimlib/for_3b1b_videos/pi_creature_scene.py | 381 ----------------- manimlib/imports.py | 5 - manimlib/mobject/svg/drawings.py | 77 +--- 7 files changed, 2 insertions(+), 1385 deletions(-) delete mode 100644 manimlib/for_3b1b_videos/common_scenes.py delete mode 100644 manimlib/for_3b1b_videos/pi_class.py delete mode 100644 manimlib/for_3b1b_videos/pi_creature.py delete mode 100644 manimlib/for_3b1b_videos/pi_creature_animations.py delete mode 100644 manimlib/for_3b1b_videos/pi_creature_scene.py diff --git a/manimlib/for_3b1b_videos/common_scenes.py b/manimlib/for_3b1b_videos/common_scenes.py deleted file mode 100644 index da83fbb470..0000000000 --- a/manimlib/for_3b1b_videos/common_scenes.py +++ /dev/null @@ -1,395 +0,0 @@ -import random - -from manimlib.animation.composition import LaggedStartMap -from manimlib.animation.creation import DrawBorderThenFill -from manimlib.animation.creation import Write -from manimlib.animation.fading import FadeIn -from manimlib.animation.fading import FadeOut -from manimlib.constants import * -from manimlib.for_3b1b_videos.pi_creature import Mortimer -from manimlib.for_3b1b_videos.pi_creature import Randolph -from manimlib.for_3b1b_videos.pi_creature_animations import Blink -from manimlib.for_3b1b_videos.pi_creature_scene import PiCreatureScene -from manimlib.mobject.geometry import DashedLine -from manimlib.mobject.geometry import Line -from manimlib.mobject.geometry import Rectangle -from manimlib.mobject.geometry import Square -from manimlib.mobject.svg.drawings import Logo -from manimlib.mobject.svg.drawings import PatreonLogo -from manimlib.mobject.svg.tex_mobject import TextMobject -from manimlib.mobject.types.vectorized_mobject import VGroup -from manimlib.mobject.mobject_update_utils import always_shift -from manimlib.scene.moving_camera_scene import MovingCameraScene -from manimlib.scene.scene import Scene -from manimlib.utils.rate_functions import linear -from manimlib.utils.space_ops import get_norm -from manimlib.utils.space_ops import normalize - - -class OpeningQuote(Scene): - CONFIG = { - "quote": [], - "quote_arg_separator": " ", - "highlighted_quote_terms": {}, - "author": "", - "fade_in_kwargs": { - "lag_ratio": 0.5, - "rate_func": linear, - "run_time": 5, - }, - "text_size": "\\Large", - "use_quotation_marks": True, - "top_buff": 1.0, - "author_buff": 1.0, - } - - def construct(self): - self.quote = self.get_quote() - self.author = self.get_author(self.quote) - - self.play(FadeIn(self.quote, **self.fade_in_kwargs)) - self.wait(2) - self.play(Write(self.author, run_time=3)) - self.wait() - - def get_quote(self, max_width=FRAME_WIDTH - 1): - text_mobject_kwargs = { - "alignment": "", - "arg_separator": self.quote_arg_separator, - } - if isinstance(self.quote, str): - if self.use_quotation_marks: - quote = TextMobject("``%s''" % - self.quote.strip(), **text_mobject_kwargs) - else: - quote = TextMobject("%s" % - self.quote.strip(), **text_mobject_kwargs) - else: - if self.use_quotation_marks: - words = [self.text_size + " ``"] + list(self.quote) + ["''"] - else: - words = [self.text_size] + list(self.quote) - quote = TextMobject(*words, **text_mobject_kwargs) - # TODO, make less hacky - if self.quote_arg_separator == " ": - quote[0].shift(0.2 * RIGHT) - quote[-1].shift(0.2 * LEFT) - for term, color in self.highlighted_quote_terms: - quote.set_color_by_tex(term, color) - quote.to_edge(UP, buff=self.top_buff) - if quote.get_width() > max_width: - quote.set_width(max_width) - return quote - - def get_author(self, quote): - author = TextMobject(self.text_size + " --" + self.author) - author.next_to(quote, DOWN, buff=self.author_buff) - author.set_color(YELLOW) - return author - - -class PatreonThanks(Scene): - CONFIG = { - "specific_patrons": [], - "max_patron_group_size": 20, - "patron_scale_val": 0.8, - } - - def construct(self): - morty = Mortimer() - morty.next_to(ORIGIN, DOWN) - - patreon_logo = PatreonLogo() - patreon_logo.to_edge(UP) - - patrons = list(map(TextMobject, self.specific_patronds)) - num_groups = float(len(patrons)) / self.max_patron_group_size - proportion_range = np.linspace(0, 1, num_groups + 1) - indices = (len(patrons) * proportion_range).astype('int') - patron_groups = [ - VGroup(*patrons[i:j]) - for i, j in zip(indices, indices[1:]) - ] - - for i, group in enumerate(patron_groups): - left_group = VGroup(*group[:len(group) / 2]) - right_group = VGroup(*group[len(group) / 2:]) - for subgroup, vect in (left_group, LEFT), (right_group, RIGHT): - subgroup.arrange(DOWN, aligned_edge=LEFT) - subgroup.scale(self.patron_scale_val) - subgroup.to_edge(vect) - - last_group = None - for i, group in enumerate(patron_groups): - anims = [] - if last_group is not None: - self.play( - FadeOut(last_group), - morty.look, UP + LEFT - ) - else: - anims += [ - DrawBorderThenFill(patreon_logo), - ] - self.play( - LaggedStartMap( - FadeIn, group, - run_time=2, - ), - morty.change, "gracious", group.get_corner(UP + LEFT), - *anims - ) - self.play(morty.look_at, group.get_corner(DOWN + LEFT)) - self.play(morty.look_at, group.get_corner(UP + RIGHT)) - self.play(morty.look_at, group.get_corner(DOWN + RIGHT)) - self.play(Blink(morty)) - last_group = group - - -class PatreonEndScreen(PatreonThanks, PiCreatureScene): - CONFIG = { - "n_patron_columns": 4, - "max_patron_width": 5, - "run_time": 20, - "randomize_order": True, - "capitalize": True, - "name_y_spacing": 0.6, - "thanks_words": "Find value in this? Join me in thanking these patrons:", - } - - def construct(self): - if self.randomize_order: - random.shuffle(self.specific_patrons) - if self.capitalize: - self.specific_patrons = [ - " ".join(map( - lambda s: s.capitalize(), - patron.split(" ") - )) - for patron in self.specific_patrons - ] - - # self.add_title() - self.scroll_through_patrons() - - def create_pi_creatures(self): - title = self.title = TextMobject("Clicky Stuffs") - title.scale(1.5) - title.to_edge(UP, buff=MED_SMALL_BUFF) - - randy, morty = self.pi_creatures = VGroup(Randolph(), Mortimer()) - for pi, vect in (randy, LEFT), (morty, RIGHT): - pi.set_height(title.get_height()) - pi.change_mode("thinking") - pi.look(DOWN) - pi.next_to(title, vect, buff=MED_LARGE_BUFF) - self.add_foreground_mobjects(title, randy, morty) - return self.pi_creatures - - def scroll_through_patrons(self): - logo_box = Square(side_length=2.5) - logo_box.to_corner(DOWN + LEFT, buff=MED_LARGE_BUFF) - - black_rect = Rectangle( - fill_color=BLACK, - fill_opacity=1, - stroke_width=3, - stroke_color=BLACK, - width=FRAME_WIDTH, - height=0.6 * FRAME_HEIGHT, - ) - black_rect.to_edge(UP, buff=0) - line = DashedLine(FRAME_X_RADIUS * LEFT, FRAME_X_RADIUS * RIGHT) - line.move_to(ORIGIN) - - thanks = TextMobject(self.thanks_words) - thanks.scale(0.9) - thanks.next_to(black_rect.get_bottom(), UP, SMALL_BUFF) - thanks.set_color(YELLOW) - underline = Line(LEFT, RIGHT) - underline.match_width(thanks) - underline.scale(1.1) - underline.next_to(thanks, DOWN, SMALL_BUFF) - thanks.add(underline) - - changed_patron_names = list(map( - self.modify_patron_name, - self.specific_patrons, - )) - changed_patron_names.sort() - patrons = VGroup(*map( - TextMobject, - changed_patron_names, - )) - patrons.scale(self.patron_scale_val) - for patron in patrons: - if patron.get_width() > self.max_patron_width: - patron.set_width(self.max_patron_width) - columns = VGroup(*[ - VGroup(*patrons[i::self.n_patron_columns]) - for i in range(self.n_patron_columns) - ]) - column_x_spacing = 0.5 + max([c.get_width() for c in columns]) - - for i, column in enumerate(columns): - for n, name in enumerate(column): - name.shift(n * self.name_y_spacing * DOWN) - name.align_to(ORIGIN, LEFT) - column.move_to(i * column_x_spacing * RIGHT, UL) - columns.center() - - max_width = FRAME_WIDTH - 1 - if columns.get_width() > max_width: - columns.set_width(max_width) - underline.match_width(columns) - # thanks.to_edge(RIGHT, buff=MED_SMALL_BUFF) - columns.next_to(underline, DOWN, buff=4) - - columns.generate_target() - columns.target.to_edge(DOWN, buff=4) - vect = columns.target.get_center() - columns.get_center() - distance = get_norm(vect) - wait_time = 20 - always_shift( - columns, - direction=normalize(vect), - rate=(distance / wait_time) - ) - - self.add(columns, black_rect, line, thanks) - self.wait(wait_time) - - def modify_patron_name(self, name): - modification_map = { - "RedAgent14": "Brian Shepetofsky", - "DeathByShrimp": "Henry Bresnahan", - "akostrikov": "Aleksandr Kostrikov", - "Jacob Baxter": "Will Fleshman", - } - for n1, n2 in modification_map.items(): - if name.lower() == n1.lower(): - return n2 - return name - - -class LogoGenerationTemplate(MovingCameraScene): - def setup(self): - MovingCameraScene.setup(self) - frame = self.camera_frame - frame.shift(DOWN) - - self.logo = Logo() - name = TextMobject("3Blue1Brown") - name.scale(2.5) - name.next_to(self.logo, DOWN, buff=MED_LARGE_BUFF) - name.set_sheen(-0.2, DR) - self.channel_name = name - - def construct(self): - logo = self.logo - name = self.channel_name - - self.play( - Write(name, run_time=3), - *self.get_logo_animations(logo) - ) - self.wait() - - def get_logo_animations(self, logo): - return [] # For subclasses - - -class ExternallyAnimatedScene(Scene): - def construct(self): - raise Exception("Don't actually run this class.") - - -class TODOStub(Scene): - CONFIG = { - "message": "" - } - - def construct(self): - self.add(TextMobject("TODO: %s" % self.message)) - self.wait() - - -class Banner(Scene): - CONFIG = { - "camera_config": { - "pixel_height": 1440, - "pixel_width": 2560, - }, - "pi_height": 1.25, - "pi_bottom": 0.25 * DOWN, - "use_date": False, - "date": "Sunday, February 3rd", - "message_scale_val": 0.9, - "add_supporter_note": False, - "pre_date_text": "Next video on ", - } - - def __init__(self, **kwargs): - # Force these dimensions - self.camera_config = { - "pixel_height": 1440, - "pixel_width": 2560, - } - Scene.__init__(self, **kwargs) - - def construct(self): - pis = self.get_pis() - pis.set_height(self.pi_height) - pis.arrange(RIGHT, aligned_edge=DOWN) - pis.move_to(self.pi_bottom, DOWN) - self.add(pis) - - if self.use_date: - message = self.get_date_message() - else: - message = self.get_probabalistic_message() - message.scale(self.message_scale_val) - message.next_to(pis, DOWN) - self.add(message) - - if self.add_supporter_note: - note = self.get_supporter_note() - note.scale(0.5) - message.shift((MED_SMALL_BUFF - SMALL_BUFF) * UP) - note.next_to(message, DOWN, SMALL_BUFF) - self.add(note) - - yellow_parts = [sm for sm in message if sm.get_color() == YELLOW] - for pi in pis: - if yellow_parts: - pi.look_at(yellow_parts[-1]) - else: - pi.look_at(message) - - def get_pis(self): - return VGroup( - Randolph(color=BLUE_E, mode="pondering"), - Randolph(color=BLUE_D, mode="hooray"), - Randolph(color=BLUE_C, mode="sassy"), - Mortimer(color=GREY_BROWN, mode="thinking") - ) - - def get_probabalistic_message(self): - return TextMobject( - "New video every ", "Sunday ", - "(with probability 0.3)", - tex_to_color_map={"Sunday": YELLOW}, - ) - - def get_date_message(self): - return TextMobject( - self.pre_date_text, - self.date, - tex_to_color_map={self.date: YELLOW}, - ) - - def get_supporter_note(self): - return TextMobject( - "(Available to supporters for review now)", - color="#F96854", - ) diff --git a/manimlib/for_3b1b_videos/pi_class.py b/manimlib/for_3b1b_videos/pi_class.py deleted file mode 100644 index 77a813e185..0000000000 --- a/manimlib/for_3b1b_videos/pi_class.py +++ /dev/null @@ -1,18 +0,0 @@ -from manimlib.constants import * -from manimlib.for_3b1b_videos.pi_creature import PiCreature -from manimlib.mobject.types.vectorized_mobject import VGroup - - -class PiCreatureClass(VGroup): - CONFIG = { - "width": 3, - "height": 2 - } - - def __init__(self, **kwargs): - VGroup.__init__(self, **kwargs) - for i in range(self.width): - for j in range(self.height): - pi = PiCreature().scale(0.3) - pi.move_to(i * DOWN + j * RIGHT) - self.add(pi) diff --git a/manimlib/for_3b1b_videos/pi_creature.py b/manimlib/for_3b1b_videos/pi_creature.py deleted file mode 100644 index 4e02646341..0000000000 --- a/manimlib/for_3b1b_videos/pi_creature.py +++ /dev/null @@ -1,389 +0,0 @@ -import os -import warnings - -import numpy as np - -from manimlib.constants import * -from manimlib.mobject.mobject import Mobject -from manimlib.mobject.geometry import Circle -from manimlib.mobject.svg.drawings import ThoughtBubble -from manimlib.mobject.svg.svg_mobject import SVGMobject -from manimlib.mobject.svg.tex_mobject import TextMobject -from manimlib.mobject.types.vectorized_mobject import VGroup -from manimlib.mobject.types.vectorized_mobject import VMobject -from manimlib.utils.config_ops import digest_config -from manimlib.utils.space_ops import get_norm -from manimlib.utils.space_ops import normalize - -pi_creature_dir_maybe = os.path.join(MEDIA_DIR, "assets", "PiCreature") -if os.path.exists(pi_creature_dir_maybe): - PI_CREATURE_DIR = pi_creature_dir_maybe -else: - PI_CREATURE_DIR = os.path.join("assets") - -PI_CREATURE_SCALE_FACTOR = 0.5 - -LEFT_EYE_INDEX = 0 -RIGHT_EYE_INDEX = 1 -LEFT_PUPIL_INDEX = 2 -RIGHT_PUPIL_INDEX = 3 -BODY_INDEX = 4 -MOUTH_INDEX = 5 - - -class PiCreature(SVGMobject): - CONFIG = { - "color": BLUE_E, - "file_name_prefix": "PiCreatures", - "stroke_width": 0, - "stroke_color": BLACK, - "fill_opacity": 1.0, - "height": 3, - "corner_scale_factor": 0.75, - "flip_at_start": False, - "is_looking_direction_purposeful": False, - "start_corner": None, - # Range of proportions along body where arms are - "right_arm_range": [0.55, 0.7], - "left_arm_range": [.34, .462], - "pupil_to_eye_width_ratio": 0.4, - "pupil_dot_to_pupil_width_ratio": 0.3, - } - - def __init__(self, mode="plain", **kwargs): - digest_config(self, kwargs) - self.mode = mode - self.parts_named = False - try: - svg_file = os.path.join( - PI_CREATURE_DIR, - "%s_%s.svg" % (self.file_name_prefix, mode) - ) - SVGMobject.__init__(self, file_name=svg_file, **kwargs) - except Exception: - warnings.warn("No %s design with mode %s" % - (self.file_name_prefix, mode)) - # TODO, this needs to change to a different, better directory - svg_file = os.path.join( - FILE_DIR, - "PiCreatures_plain.svg", - ) - SVGMobject.__init__(self, mode="plain", file_name=svg_file, **kwargs) - - if self.flip_at_start: - self.flip() - if self.start_corner is not None: - self.to_corner(self.start_corner) - - def align_data(self, mobject): - # This ensures that after a transform into a different mode, - # the pi creatures mode will be updated appropriately - SVGMobject.align_data(self, mobject) - if isinstance(mobject, PiCreature): - self.mode = mobject.get_mode() - - def name_parts(self): - self.mouth = self.submobjects[MOUTH_INDEX] - self.body = self.submobjects[BODY_INDEX] - self.pupils = VGroup(*[ - self.submobjects[LEFT_PUPIL_INDEX], - self.submobjects[RIGHT_PUPIL_INDEX] - ]) - self.eyes = VGroup(*[ - self.submobjects[LEFT_EYE_INDEX], - self.submobjects[RIGHT_EYE_INDEX] - ]) - self.eye_parts = VGroup(self.eyes, self.pupils) - self.parts_named = True - - def init_colors(self): - SVGMobject.init_colors(self) - if not self.parts_named: - self.name_parts() - self.mouth.set_fill(BLACK, opacity=1) - self.body.set_fill(self.color, opacity=1) - self.eyes.set_fill(WHITE, opacity=1) - self.init_pupils() - return self - - def init_pupils(self): - # Instead of what is drawn, make new circles. - # This is mostly because the paths associated - # with the eyes in all the drawings got slightly - # messed up. - for eye, pupil in zip(self.eyes, self.pupils): - pupil_r = eye.get_width() / 2 - pupil_r *= self.pupil_to_eye_width_ratio - dot_r = pupil_r - dot_r *= self.pupil_dot_to_pupil_width_ratio - - new_pupil = Circle( - radius=pupil_r, - color=BLACK, - fill_opacity=1, - stroke_width=0, - ) - dot = Circle( - radius=dot_r, - color=WHITE, - fill_opacity=1, - stroke_width=0, - ) - new_pupil.move_to(pupil) - pupil.become(new_pupil) - dot.shift( - new_pupil.get_boundary_point(UL) - - dot.get_boundary_point(UL) - ) - pupil.add(dot) - - def copy(self): - copy_mobject = SVGMobject.copy(self) - copy_mobject.name_parts() - return copy_mobject - - def set_color(self, color): - self.body.set_fill(color) - self.color = color - return self - - def change_mode(self, mode): - new_self = self.__class__( - mode=mode, - ) - new_self.match_style(self) - new_self.match_height(self) - if self.is_flipped() != new_self.is_flipped(): - new_self.flip() - new_self.shift(self.eyes.get_center() - new_self.eyes.get_center()) - if hasattr(self, "purposeful_looking_direction"): - new_self.look(self.purposeful_looking_direction) - self.become(new_self) - self.mode = mode - return self - - def get_mode(self): - return self.mode - - def look(self, direction): - norm = get_norm(direction) - if norm == 0: - return - direction /= norm - self.purposeful_looking_direction = direction - for pupil, eye in zip(self.pupils.split(), self.eyes.split()): - c = eye.get_center() - right = eye.get_right() - c - up = eye.get_top() - c - vect = direction[0] * right + direction[1] * up - v_norm = get_norm(vect) - p_radius = 0.5 * pupil.get_width() - vect *= (v_norm - 0.75 * p_radius) / v_norm - pupil.move_to(c + vect) - self.pupils[1].align_to(self.pupils[0], DOWN) - return self - - def look_at(self, point_or_mobject): - if isinstance(point_or_mobject, Mobject): - point = point_or_mobject.get_center() - else: - point = point_or_mobject - self.look(point - self.eyes.get_center()) - return self - - def change(self, new_mode, look_at_arg=None): - self.change_mode(new_mode) - if look_at_arg is not None: - self.look_at(look_at_arg) - return self - - def get_looking_direction(self): - vect = self.pupils.get_center() - self.eyes.get_center() - return normalize(vect) - - def get_look_at_spot(self): - return self.eyes.get_center() + self.get_looking_direction() - - def is_flipped(self): - return self.eyes.submobjects[0].get_center()[0] > \ - self.eyes.submobjects[1].get_center()[0] - - def blink(self): - eye_parts = self.eye_parts - eye_bottom_y = eye_parts.get_bottom()[1] - eye_parts.apply_function( - lambda p: [p[0], eye_bottom_y, p[2]] - ) - return self - - def to_corner(self, vect=None, **kwargs): - if vect is not None: - SVGMobject.to_corner(self, vect, **kwargs) - else: - self.scale(self.corner_scale_factor) - self.to_corner(DOWN + LEFT, **kwargs) - return self - - def get_bubble(self, *content, **kwargs): - bubble_class = kwargs.get("bubble_class", ThoughtBubble) - bubble = bubble_class(**kwargs) - if len(content) > 0: - if isinstance(content[0], str): - content_mob = TextMobject(*content) - else: - content_mob = content[0] - bubble.add_content(content_mob) - if "height" not in kwargs and "width" not in kwargs: - bubble.resize_to_content() - bubble.pin_to(self) - self.bubble = bubble - return bubble - - def make_eye_contact(self, pi_creature): - self.look_at(pi_creature.eyes) - pi_creature.look_at(self.eyes) - return self - - def shrug(self): - self.change_mode("shruggie") - top_mouth_point, bottom_mouth_point = [ - self.mouth.points[np.argmax(self.mouth.points[:, 1])], - self.mouth.points[np.argmin(self.mouth.points[:, 1])] - ] - self.look(top_mouth_point - bottom_mouth_point) - return self - - def get_arm_copies(self): - body = self.body - return VGroup(*[ - body.copy().pointwise_become_partial(body, *alpha_range) - for alpha_range in (self.right_arm_range, self.left_arm_range) - ]) - - -def get_all_pi_creature_modes(): - result = [] - prefix = "%s_" % PiCreature.CONFIG["file_name_prefix"] - suffix = ".svg" - for file in os.listdir(PI_CREATURE_DIR): - if file.startswith(prefix) and file.endswith(suffix): - result.append( - file[len(prefix):-len(suffix)] - ) - return result - - -class Randolph(PiCreature): - pass # Nothing more than an alternative name - - -class Mortimer(PiCreature): - CONFIG = { - "color": GREY_BROWN, - "flip_at_start": True, - } - - -class Mathematician(PiCreature): - CONFIG = { - "color": GREY, - } - - -class BabyPiCreature(PiCreature): - CONFIG = { - "scale_factor": 0.5, - "eye_scale_factor": 1.2, - "pupil_scale_factor": 1.3 - } - - def __init__(self, *args, **kwargs): - PiCreature.__init__(self, *args, **kwargs) - self.scale(self.scale_factor) - self.shift(LEFT) - self.to_edge(DOWN, buff=LARGE_BUFF) - eyes = VGroup(self.eyes, self.pupils) - eyes_bottom = eyes.get_bottom() - eyes.scale(self.eye_scale_factor) - eyes.move_to(eyes_bottom, aligned_edge=DOWN) - looking_direction = self.get_looking_direction() - for pupil in self.pupils: - pupil.scale_in_place(self.pupil_scale_factor) - self.look(looking_direction) - - -class TauCreature(PiCreature): - CONFIG = { - "file_name_prefix": "TauCreatures" - } - - -class ThreeLeggedPiCreature(PiCreature): - CONFIG = { - "file_name_prefix": "ThreeLeggedPiCreatures" - } - - -class Eyes(VMobject): - CONFIG = { - "height": 0.3, - "thing_to_look_at": None, - "mode": "plain", - } - - def __init__(self, body, **kwargs): - VMobject.__init__(self, **kwargs) - self.body = body - eyes = self.create_eyes() - self.become(eyes, copy_submobjects=False) - - def create_eyes(self, mode=None, thing_to_look_at=None): - if mode is None: - mode = self.mode - if thing_to_look_at is None: - thing_to_look_at = self.thing_to_look_at - self.thing_to_look_at = thing_to_look_at - self.mode = mode - looking_direction = None - - pi = PiCreature(mode=mode) - eyes = VGroup(pi.eyes, pi.pupils) - if self.submobjects: - eyes.match_height(self) - eyes.move_to(self, DOWN) - looking_direction = self[1].get_center() - self[0].get_center() - else: - eyes.set_height(self.height) - eyes.move_to(self.body.get_top(), DOWN) - - height = eyes.get_height() - if thing_to_look_at is not None: - pi.look_at(thing_to_look_at) - elif looking_direction is not None: - pi.look(looking_direction) - eyes.set_height(height) - - return eyes - - def change_mode(self, mode, thing_to_look_at=None): - new_eyes = self.create_eyes( - mode=mode, - thing_to_look_at=thing_to_look_at - ) - self.become(new_eyes, copy_submobjects=False) - return self - - def look_at(self, thing_to_look_at): - self.change_mode( - self.mode, - thing_to_look_at=thing_to_look_at - ) - return self - - def blink(self, **kwargs): # TODO, change Blink - bottom_y = self.get_bottom()[1] - for submob in self: - submob.apply_function( - lambda p: [p[0], bottom_y, p[2]] - ) - return self diff --git a/manimlib/for_3b1b_videos/pi_creature_animations.py b/manimlib/for_3b1b_videos/pi_creature_animations.py deleted file mode 100644 index 91df37739a..0000000000 --- a/manimlib/for_3b1b_videos/pi_creature_animations.py +++ /dev/null @@ -1,122 +0,0 @@ -from manimlib.animation.animation import Animation -from manimlib.animation.composition import AnimationGroup -from manimlib.animation.fading import FadeOut -from manimlib.animation.creation import DrawBorderThenFill -from manimlib.animation.creation import Write -from manimlib.animation.transform import ApplyMethod -from manimlib.animation.transform import MoveToTarget -from manimlib.constants import * -from manimlib.for_3b1b_videos.pi_class import PiCreatureClass -from manimlib.mobject.mobject import Group -from manimlib.mobject.svg.drawings import SpeechBubble -from manimlib.utils.config_ops import digest_config -from manimlib.utils.rate_functions import squish_rate_func -from manimlib.utils.rate_functions import there_and_back - - -class Blink(ApplyMethod): - CONFIG = { - "rate_func": squish_rate_func(there_and_back) - } - - def __init__(self, pi_creature, **kwargs): - ApplyMethod.__init__(self, pi_creature.blink, **kwargs) - - -class PiCreatureBubbleIntroduction(AnimationGroup): - CONFIG = { - "target_mode": "speaking", - "bubble_class": SpeechBubble, - "change_mode_kwargs": {}, - "bubble_creation_class": DrawBorderThenFill, - "bubble_creation_kwargs": {}, - "bubble_kwargs": {}, - "content_introduction_class": Write, - "content_introduction_kwargs": {}, - "look_at_arg": None, - } - - def __init__(self, pi_creature, *content, **kwargs): - digest_config(self, kwargs) - bubble = pi_creature.get_bubble( - *content, - bubble_class=self.bubble_class, - **self.bubble_kwargs - ) - Group(bubble, bubble.content).shift_onto_screen() - - pi_creature.generate_target() - pi_creature.target.change_mode(self.target_mode) - if self.look_at_arg is not None: - pi_creature.target.look_at(self.look_at_arg) - - change_mode = MoveToTarget(pi_creature, **self.change_mode_kwargs) - bubble_creation = self.bubble_creation_class( - bubble, **self.bubble_creation_kwargs - ) - content_introduction = self.content_introduction_class( - bubble.content, **self.content_introduction_kwargs - ) - AnimationGroup.__init__( - self, change_mode, bubble_creation, content_introduction, - **kwargs - ) - - -class PiCreatureSays(PiCreatureBubbleIntroduction): - CONFIG = { - "target_mode": "speaking", - "bubble_class": SpeechBubble, - } - - -class RemovePiCreatureBubble(AnimationGroup): - CONFIG = { - "target_mode": "plain", - "look_at_arg": None, - "remover": True, - } - - def __init__(self, pi_creature, **kwargs): - assert hasattr(pi_creature, "bubble") - digest_config(self, kwargs, locals()) - - pi_creature.generate_target() - pi_creature.target.change_mode(self.target_mode) - if self.look_at_arg is not None: - pi_creature.target.look_at(self.look_at_arg) - - AnimationGroup.__init__( - self, - MoveToTarget(pi_creature), - FadeOut(pi_creature.bubble), - FadeOut(pi_creature.bubble.content), - ) - - def clean_up_from_scene(self, scene=None): - AnimationGroup.clean_up_from_scene(self, scene) - self.pi_creature.bubble = None - if scene is not None: - scene.add(self.pi_creature) - - -class FlashThroughClass(Animation): - CONFIG = { - "highlight_color": GREEN, - } - - def __init__(self, mobject, mode="linear", **kwargs): - if not isinstance(mobject, PiCreatureClass): - raise Exception("FlashThroughClass mobject must be a PiCreatureClass") - digest_config(self, kwargs) - self.indices = list(range(mobject.height * mobject.width)) - if mode == "random": - np.random.shuffle(self.indices) - Animation.__init__(self, mobject, **kwargs) - - def interpolate_mobject(self, alpha): - index = int(np.floor(alpha * self.mobject.height * self.mobject.width)) - for pi in self.mobject: - pi.set_color(BLUE_E) - if index < self.mobject.height * self.mobject.width: - self.mobject[self.indices[index]].set_color(self.highlight_color) diff --git a/manimlib/for_3b1b_videos/pi_creature_scene.py b/manimlib/for_3b1b_videos/pi_creature_scene.py deleted file mode 100644 index def1216d7b..0000000000 --- a/manimlib/for_3b1b_videos/pi_creature_scene.py +++ /dev/null @@ -1,381 +0,0 @@ -import itertools as it -import random - -from manimlib.animation.transform import ReplacementTransform -from manimlib.animation.transform import Transform -from manimlib.animation.transform import ApplyMethod -from manimlib.animation.composition import LaggedStart -from manimlib.constants import * -from manimlib.for_3b1b_videos.pi_creature import Mortimer -from manimlib.for_3b1b_videos.pi_creature import PiCreature -from manimlib.for_3b1b_videos.pi_creature import Randolph -from manimlib.for_3b1b_videos.pi_creature_animations import Blink -from manimlib.for_3b1b_videos.pi_creature_animations import PiCreatureBubbleIntroduction -from manimlib.for_3b1b_videos.pi_creature_animations import RemovePiCreatureBubble -from manimlib.mobject.mobject import Group -from manimlib.mobject.frame import ScreenRectangle -from manimlib.mobject.svg.drawings import SpeechBubble -from manimlib.mobject.svg.drawings import ThoughtBubble -from manimlib.mobject.types.vectorized_mobject import VGroup -from manimlib.scene.scene import Scene -from manimlib.utils.rate_functions import squish_rate_func -from manimlib.utils.rate_functions import there_and_back -from manimlib.utils.space_ops import get_norm - - -class PiCreatureScene(Scene): - CONFIG = { - "total_wait_time": 0, - "seconds_to_blink": 3, - "pi_creatures_start_on_screen": True, - "default_pi_creature_kwargs": { - "color": BLUE, - "flip_at_start": False, - }, - "default_pi_creature_start_corner": DL, - } - - def setup(self): - self.pi_creatures = VGroup(*self.create_pi_creatures()) - self.pi_creature = self.get_primary_pi_creature() - if self.pi_creatures_start_on_screen: - self.add(*self.pi_creatures) - - def create_pi_creatures(self): - """ - Likely updated for subclasses - """ - return VGroup(self.create_pi_creature()) - - def create_pi_creature(self): - pi_creature = PiCreature(**self.default_pi_creature_kwargs) - pi_creature.to_corner(self.default_pi_creature_start_corner) - return pi_creature - - def get_pi_creatures(self): - return self.pi_creatures - - def get_primary_pi_creature(self): - return self.pi_creatures[0] - - def any_pi_creatures_on_screen(self): - return len(self.get_on_screen_pi_creatures()) > 0 - - def get_on_screen_pi_creatures(self): - mobjects = self.get_mobject_family_members() - return VGroup(*[ - pi for pi in self.get_pi_creatures() - if pi in mobjects - ]) - - def introduce_bubble(self, *args, **kwargs): - if isinstance(args[0], PiCreature): - pi_creature = args[0] - content = args[1:] - else: - pi_creature = self.get_primary_pi_creature() - content = args - - bubble_class = kwargs.pop("bubble_class", SpeechBubble) - target_mode = kwargs.pop( - "target_mode", - "thinking" if bubble_class is ThoughtBubble else "speaking" - ) - bubble_kwargs = kwargs.pop("bubble_kwargs", {}) - bubble_removal_kwargs = kwargs.pop("bubble_removal_kwargs", {}) - added_anims = kwargs.pop("added_anims", []) - - anims = [] - on_screen_mobjects = self.camera.extract_mobject_family_members( - self.get_mobjects() - ) - - def has_bubble(pi): - return hasattr(pi, "bubble") and \ - pi.bubble is not None and \ - pi.bubble in on_screen_mobjects - - pi_creatures_with_bubbles = list(filter(has_bubble, self.get_pi_creatures())) - if pi_creature in pi_creatures_with_bubbles: - pi_creatures_with_bubbles.remove(pi_creature) - old_bubble = pi_creature.bubble - bubble = pi_creature.get_bubble( - *content, - bubble_class=bubble_class, - **bubble_kwargs - ) - anims += [ - ReplacementTransform(old_bubble, bubble), - ReplacementTransform(old_bubble.content, bubble.content), - pi_creature.change_mode, target_mode - ] - else: - anims.append(PiCreatureBubbleIntroduction( - pi_creature, - *content, - bubble_class=bubble_class, - bubble_kwargs=bubble_kwargs, - target_mode=target_mode, - **kwargs - )) - anims += [ - RemovePiCreatureBubble(pi, **bubble_removal_kwargs) - for pi in pi_creatures_with_bubbles - ] - anims += added_anims - - self.play(*anims, **kwargs) - - def pi_creature_says(self, *args, **kwargs): - self.introduce_bubble( - *args, - bubble_class=SpeechBubble, - **kwargs - ) - - def pi_creature_thinks(self, *args, **kwargs): - self.introduce_bubble( - *args, - bubble_class=ThoughtBubble, - **kwargs - ) - - def say(self, *content, **kwargs): - self.pi_creature_says( - self.get_primary_pi_creature(), *content, **kwargs) - - def think(self, *content, **kwargs): - self.pi_creature_thinks( - self.get_primary_pi_creature(), *content, **kwargs) - - def compile_play_args_to_animation_list(self, *args, **kwargs): - """ - Add animations so that all pi creatures look at the - first mobject being animated with each .play call - """ - animations = Scene.compile_play_args_to_animation_list(self, *args, **kwargs) - anim_mobjects = Group(*[a.mobject for a in animations]) - all_movers = anim_mobjects.get_family() - if not self.any_pi_creatures_on_screen(): - return animations - - pi_creatures = self.get_on_screen_pi_creatures() - non_pi_creature_anims = [ - anim - for anim in animations - if len(set(anim.mobject.get_family()).intersection(pi_creatures)) == 0 - ] - if len(non_pi_creature_anims) == 0: - return animations - # Get pi creatures to look at whatever - # is being animated - first_anim = non_pi_creature_anims[0] - main_mobject = first_anim.mobject - for pi_creature in pi_creatures: - if pi_creature not in all_movers: - animations.append(ApplyMethod( - pi_creature.look_at, - main_mobject, - )) - return animations - - def blink(self): - self.play(Blink(random.choice(self.get_on_screen_pi_creatures()))) - - def joint_blink(self, pi_creatures=None, shuffle=True, **kwargs): - if pi_creatures is None: - pi_creatures = self.get_on_screen_pi_creatures() - creatures_list = list(pi_creatures) - if shuffle: - random.shuffle(creatures_list) - - def get_rate_func(pi): - index = creatures_list.index(pi) - proportion = float(index) / len(creatures_list) - start_time = 0.8 * proportion - return squish_rate_func( - there_and_back, - start_time, start_time + 0.2 - ) - - self.play(*[ - Blink(pi, rate_func=get_rate_func(pi), **kwargs) - for pi in creatures_list - ]) - return self - - def wait(self, time=1, blink=True, **kwargs): - if "stop_condition" in kwargs: - self.non_blink_wait(time, **kwargs) - return - while time >= 1: - time_to_blink = self.total_wait_time % self.seconds_to_blink == 0 - if blink and self.any_pi_creatures_on_screen() and time_to_blink: - self.blink() - else: - self.non_blink_wait(**kwargs) - time -= 1 - self.total_wait_time += 1 - if time > 0: - self.non_blink_wait(time, **kwargs) - return self - - def non_blink_wait(self, time=1, **kwargs): - Scene.wait(self, time, **kwargs) - return self - - def change_mode(self, mode): - self.play(self.get_primary_pi_creature().change_mode, mode) - - def look_at(self, thing_to_look_at, pi_creatures=None, **kwargs): - if pi_creatures is None: - pi_creatures = self.get_pi_creatures() - args = list(it.chain(*[ - [pi.look_at, thing_to_look_at] - for pi in pi_creatures - ])) - self.play(*args, **kwargs) - - -class MortyPiCreatureScene(PiCreatureScene): - CONFIG = { - "default_pi_creature_kwargs": { - "color": GREY_BROWN, - "flip_at_start": True, - }, - "default_pi_creature_start_corner": DR, - } - - -class TeacherStudentsScene(PiCreatureScene): - CONFIG = { - "student_colors": [BLUE_D, BLUE_E, BLUE_C], - "teacher_color": GREY_BROWN, - "student_scale_factor": 0.8, - "seconds_to_blink": 2, - "screen_height": 3, - "camera_config": { - "background_color": DARKER_GREY, - }, - } - - def setup(self): - PiCreatureScene.setup(self) - self.screen = ScreenRectangle(height=self.screen_height) - self.screen.to_corner(UP + LEFT) - self.hold_up_spot = self.teacher.get_corner(UP + LEFT) + MED_LARGE_BUFF * UP - - def create_pi_creatures(self): - self.teacher = Mortimer(color=self.teacher_color) - self.teacher.to_corner(DOWN + RIGHT) - self.teacher.look(DOWN + LEFT) - self.students = VGroup(*[ - Randolph(color=c) - for c in self.student_colors - ]) - self.students.arrange(RIGHT) - self.students.scale(self.student_scale_factor) - self.students.to_corner(DOWN + LEFT) - self.teacher.look_at(self.students[-1].eyes) - for student in self.students: - student.look_at(self.teacher.eyes) - - return [self.teacher] + list(self.students) - - def get_teacher(self): - return self.teacher - - def get_students(self): - return self.students - - def teacher_says(self, *content, **kwargs): - return self.pi_creature_says( - self.get_teacher(), *content, **kwargs - ) - - def student_says(self, *content, **kwargs): - if "target_mode" not in kwargs: - target_mode = random.choice([ - "raise_right_hand", - "raise_left_hand", - ]) - kwargs["target_mode"] = target_mode - if "bubble_kwargs" not in kwargs: - kwargs["bubble_kwargs"] = {"direction": LEFT} - student = self.get_students()[kwargs.get("student_index", 2)] - return self.pi_creature_says( - student, *content, **kwargs - ) - - def teacher_thinks(self, *content, **kwargs): - return self.pi_creature_thinks( - self.get_teacher(), *content, **kwargs - ) - - def student_thinks(self, *content, **kwargs): - student = self.get_students()[kwargs.get("student_index", 2)] - return self.pi_creature_thinks(student, *content, **kwargs) - - def change_all_student_modes(self, mode, **kwargs): - self.change_student_modes(*[mode] * len(self.students), **kwargs) - - def change_student_modes(self, *modes, **kwargs): - added_anims = kwargs.pop("added_anims", []) - self.play( - self.get_student_changes(*modes, **kwargs), - *added_anims - ) - - def get_student_changes(self, *modes, **kwargs): - pairs = list(zip(self.get_students(), modes)) - pairs = [(s, m) for s, m in pairs if m is not None] - start = VGroup(*[s for s, m in pairs]) - target = VGroup(*[s.copy().change_mode(m) for s, m in pairs]) - if "look_at_arg" in kwargs: - for pi in target: - pi.look_at(kwargs["look_at_arg"]) - anims = [ - Transform(s, t) - for s, t in zip(start, target) - ] - return LaggedStart( - *anims, - lag_ratio=kwargs.get("lag_ratio", 0.5), - run_time=1, - ) - # return Transform( - # start, target, - # lag_ratio=lag_ratio, - # run_time=2 - # ) - - def zoom_in_on_thought_bubble(self, bubble=None, radius=FRAME_Y_RADIUS + FRAME_X_RADIUS): - if bubble is None: - for pi in self.get_pi_creatures(): - if hasattr(pi, "bubble") and isinstance(pi.bubble, ThoughtBubble): - bubble = pi.bubble - break - if bubble is None: - raise Exception("No pi creatures have a thought bubble") - vect = -bubble.get_bubble_center() - - def func(point): - centered = point + vect - return radius * centered / get_norm(centered) - self.play(*[ - ApplyPointwiseFunction(func, mob) - for mob in self.get_mobjects() - ]) - - def teacher_holds_up(self, mobject, target_mode="raise_right_hand", added_anims=None, **kwargs): - mobject.move_to(self.hold_up_spot, DOWN) - mobject.shift_onto_screen() - mobject_copy = mobject.copy() - mobject_copy.shift(DOWN) - mobject_copy.fade(1) - added_anims = added_anims or [] - self.play( - ReplacementTransform(mobject_copy, mobject), - self.teacher.change, target_mode, - *added_anims - ) diff --git a/manimlib/imports.py b/manimlib/imports.py index ad1ecc7e52..92dddbe54a 100644 --- a/manimlib/imports.py +++ b/manimlib/imports.py @@ -60,11 +60,6 @@ from manimlib.mobject.value_tracker import * from manimlib.mobject.vector_field import * -from manimlib.for_3b1b_videos.common_scenes import * -from manimlib.for_3b1b_videos.pi_creature import * -from manimlib.for_3b1b_videos.pi_creature_animations import * -from manimlib.for_3b1b_videos.pi_creature_scene import * - from manimlib.scene.graph_scene import * from manimlib.scene.moving_camera_scene import * from manimlib.scene.reconfigurable_scene import * diff --git a/manimlib/mobject/svg/drawings.py b/manimlib/mobject/svg/drawings.py index 866250853a..b0efa84741 100644 --- a/manimlib/mobject/svg/drawings.py +++ b/manimlib/mobject/svg/drawings.py @@ -65,22 +65,6 @@ class Guitar(SVGMobject): } -class SunGlasses(SVGMobject): - CONFIG = { - "file_name": "sunglasses", - "glasses_width_to_eyes_width": 1.1, - } - - def __init__(self, pi_creature, **kwargs): - SVGMobject.__init__(self, **kwargs) - self.set_stroke(WHITE, width=0) - self.set_fill(GREY, 1) - self.set_width( - self.glasses_width_to_eyes_width * pi_creature.eyes.get_width() - ) - self.move_to(pi_creature.eyes, UP) - - class Speedometer(VMobject): CONFIG = { "arc_angle": 4 * np.pi / 3, @@ -175,7 +159,6 @@ class PartyHat(SVGMobject): CONFIG = { "file_name": "party_hat", "height": 1.5, - "pi_creature": None, "stroke_width": 0, "fill_opacity": 1, "frills_colors": [MAROON_B, PURPLE], @@ -188,8 +171,6 @@ class PartyHat(SVGMobject): def __init__(self, **kwargs): SVGMobject.__init__(self, **kwargs) self.set_height(self.height) - if self.pi_creature is not None: - self.next_to(self.pi_creature.eyes, UP, buff=0) self.frills = VGroup(*self[:self.NUM_FRILLS]) self.cone = self[self.NUM_FRILLS] @@ -332,18 +313,13 @@ class Headphones(SVGMobject): "color": GREY, } - def __init__(self, pi_creature=None, **kwargs): + def __init__(self, **kwargs): digest_config(self, kwargs) SVGMobject.__init__(self, file_name=self.file_name, **kwargs) self.stretch(self.y_stretch_factor, 1) self.set_height(self.height) self.set_stroke(width=0) self.set_fill(color=self.color) - if pi_creature is not None: - eyes = pi_creature.eyes - self.set_height(3 * eyes.get_height()) - self.move_to(eyes, DOWN) - self.shift(DOWN * eyes.get_height() / 4) class Clock(VGroup): @@ -560,16 +536,6 @@ def __init__(self, **kwargs): self.set_stroke(color=WHITE, width=0) self.set_fill(self.color, opacity=1) - from manimlib.for_3b1b_videos.pi_creature import Randolph - randy = Randolph(mode="happy") - randy.set_height(0.6 * self.get_height()) - randy.stretch(0.8, 0) - randy.look(RIGHT) - randy.move_to(self) - randy.shift(0.07 * self.height * (RIGHT + UP)) - self.randy = self.pi_creature = randy - self.add_to_back(randy) - orientation_line = Line(self.get_left(), self.get_right()) orientation_line.set_stroke(width=0) self.add(orientation_line) @@ -994,46 +960,7 @@ def get_number_design(self, value, symbol): return design def get_face_card_design(self, value, symbol): - from for_3b1b_videos.pi_creature import PiCreature - sub_rect = Rectangle( - stroke_color=BLACK, - fill_opacity=0, - height=0.9 * self.get_height(), - width=0.6 * self.get_width(), - ) - sub_rect.move_to(self) - - # pi_color = average_color(symbol.get_color(), GREY) - pi_color = symbol.get_color() - pi_mode = { - "J": "plain", - "Q": "thinking", - "K": "hooray" - }[value] - pi_creature = PiCreature( - mode=pi_mode, - color=pi_color, - ) - pi_creature.set_width(0.8 * sub_rect.get_width()) - if value in ["Q", "K"]: - prefix = "king" if value == "K" else "queen" - crown = SVGMobject(file_name=prefix + "_crown") - crown.set_stroke(width=0) - crown.set_fill(YELLOW, 1) - crown.stretch_to_fit_width(0.5 * sub_rect.get_width()) - crown.stretch_to_fit_height(0.17 * sub_rect.get_height()) - crown.move_to(pi_creature.eyes.get_center(), DOWN) - pi_creature.add_to_back(crown) - to_top_buff = 0 - else: - to_top_buff = SMALL_BUFF * sub_rect.get_height() - pi_creature.next_to(sub_rect.get_top(), DOWN, to_top_buff) - # pi_creature.shift(0.05*sub_rect.get_width()*RIGHT) - - pi_copy = pi_creature.copy() - pi_copy.rotate(np.pi, about_point=sub_rect.get_center()) - - return VGroup(sub_rect, pi_creature, pi_copy) + return VGroup() def get_corner_numbers(self, value, symbol): value_mob = TextMobject(value)