def __init__(self, mobject: Mobject, tracked_mobject: Mobject, **kwargs): self.tracked_mobject = tracked_mobject self.diff = op.sub( mobject.get_center(), tracked_mobject.get_center(), ) super().__init__(mobject, **kwargs)
def flip(self, axis=UP): Mobject.flip(self, axis=axis) self.refresh_unit_normal() self.refresh_triangulation() if abs(axis[1]) > 0: self.direction = -np.array(self.direction) return self
def test_clear_updaters(self): obj = Mobject() obj.add_updater(__func__) obj.add_updater(__dt_func__) obj.add_updater(__func__) self.assertListEqual([__func__, __dt_func__, __func__], obj.updaters) obj.clear_updaters() self.assertListEqual([], obj.updaters)
def test_remove_updater(self): obj = Mobject() obj.add_updater(__func__) obj.add_updater(__dt_func__) obj.add_updater(__func__) self.assertListEqual([__func__, __dt_func__, __func__], obj.updaters) obj.remove_updater(__func__) self.assertListEqual([__dt_func__], obj.updaters)
def align_points(self, vmobject): Mobject.align_points(self, vmobject) self.align_rgbas(vmobject) is_subpath = self.is_subpath or vmobject.is_subpath self.is_subpath = vmobject.is_subpath = is_subpath mark_closed = self.mark_paths_closed and vmobject.mark_paths_closed self.mark_paths_closed = vmobject.mark_paths_closed = mark_closed return self
def test_center(self): x = random.Random().randint(-1000, 1000) y = random.Random().randint(-1000, 1000) z = random.Random().randint(-1000, 1000) obj = Mobject() obj.points = np.array([[x, y, z]]) obj.center() np.testing.assert_array_equal(obj.points, np.zeros((1, 3)))
def apply_function(self, function): factor = self.pre_function_handle_to_anchor_scale_factor self.scale_handle_to_anchor_distances(factor) Mobject.apply_function(self, function) self.scale_handle_to_anchor_distances(1. / factor) if self.make_smooth_after_applying_functions: self.make_smooth() return self
def test_shift_onto_screen_two(self): obj = Mobject() obj.points = np.array([[FRAME_X_RADIUS * 2, 0, 0]]) obj.shift_onto_screen() np.testing.assert_array_equal( obj.points, np.array([[FRAME_X_RADIUS - DEFAULT_MOBJECT_TO_EDGE_BUFFER, 0, 0]]))
def save_mobject_to_file(self, mobject: Mobject, file_path: str | None = None) -> None: if file_path is None: file_path = self.file_writer.get_saved_mobject_path(mobject) if file_path is None: return mobject.save_to_file(file_path)
def test_rotate_returns_self(self): a = random.Random().randint(-1000, 1000) x = random.Random().randint(-1000, 1000) y = random.Random().randint(-1000, 1000) z = random.Random().randint(-1000, 1000) obj = Mobject() obj.points = np.array([x, y, z]) self.assertEqual(obj, obj.rotate(a, about_point=np.array([0, 0, 0])))
def __init__(self, mobject: Mobject, target_mobject: Mobject, **kwargs): digest_config(self, kwargs) assert (isinstance(mobject, self.mobject_type)) assert (isinstance(target_mobject, self.mobject_type)) source_map = self.get_shape_map(mobject) target_map = self.get_shape_map(target_mobject) # Create two mobjects whose submobjects all match each other # according to whatever keys are used for source_map and # target_map transform_source = self.group_type() transform_target = self.group_type() kwargs["final_alpha_value"] = 0 for key in set(source_map).intersection(target_map): transform_source.add(source_map[key]) transform_target.add(target_map[key]) anims = [Transform(transform_source, transform_target, **kwargs)] # User can manually specify when one part should transform # into another despite not matching by using key_map key_mapped_source = self.group_type() key_mapped_target = self.group_type() for key1, key2 in self.key_map.items(): if key1 in source_map and key2 in target_map: key_mapped_source.add(source_map[key1]) key_mapped_target.add(target_map[key2]) source_map.pop(key1, None) target_map.pop(key2, None) if len(key_mapped_source) > 0: anims.append( FadeTransformPieces( key_mapped_source, key_mapped_target, )) fade_source = self.group_type() fade_target = self.group_type() for key in set(source_map).difference(target_map): fade_source.add(source_map[key]) for key in set(target_map).difference(source_map): fade_target.add(target_map[key]) if self.transform_mismatches: anims.append(Transform(fade_source.copy(), fade_target, **kwargs)) if self.fade_transform_mismatches: anims.append( FadeTransformPieces(fade_source, fade_target, **kwargs)) else: anims.append( FadeOutToPoint(fade_source, target_mobject.get_center(), **kwargs)) anims.append( FadeInFromPoint(fade_target.copy(), mobject.get_center(), **kwargs)) super().__init__(*anims) self.to_remove = mobject self.to_add = target_mobject
def interpolate_submobject( self, submob: Mobject, start: Mobject, target_copy: Mobject, alpha: float ): submob.interpolate(start, target_copy, alpha, self.path_func) return self
def test_add_to_back_singly(self): a, b, c, obj = Mobject(), Mobject(), Mobject(), Mobject() self.assertListEqual([], obj.submobjects) obj.add_to_back(a) self.assertListEqual([a], obj.submobjects) obj.add_to_back(b) self.assertListEqual([b, a], obj.submobjects) obj.add_to_back(c) self.assertListEqual([c, b, a], obj.submobjects)
def test_add_submobjects_singly(self): a, b, c, obj = Mobject(), Mobject(), Mobject(), Mobject() self.assertListEqual([], obj.submobjects) obj.add(a) self.assertListEqual([a], obj.submobjects) obj.add(b) self.assertListEqual([a, b], obj.submobjects) obj.add(c) self.assertListEqual([a, b, c], obj.submobjects)
def move_submobjects_along_vector_field( mobject: Mobject, func: Callable[[np.ndarray], np.ndarray]) -> Mobject: def apply_nudge(mob, dt): for submob in mob: x, y = submob.get_center()[:2] if abs(x) < FRAME_WIDTH and abs(y) < FRAME_HEIGHT: submob.shift(func(submob.get_center()) * dt) mobject.add_updater(apply_nudge) return mobject
def get_corner_dots(self, mobject: Mobject) -> Mobject: dots = DotCloud(**self.corner_dot_config) radius = self.corner_dot_config["radius"] if mobject.get_depth() < 1e-2: vects = [DL, UL, UR, DR] else: vects = np.array(list(it.product(*3 * [[-1, 1]]))) dots.add_updater(lambda d: d.set_points( [mobject.get_corner(v) + v * radius for v in vects])) return dots
def test_remove_singly(self): a, b, c, obj = Mobject(), Mobject(), Mobject(), Mobject() obj.add(a, b, c) self.assertListEqual([a, b, c], obj.submobjects) obj.remove(a) self.assertListEqual([b, c], obj.submobjects) obj.remove(b) self.assertListEqual([c], obj.submobjects) obj.remove(c) self.assertListEqual([], obj.submobjects)
def __init__(self, **kwargs): if not hasattr(self, "args"): self.args = serialize_args([]) if not hasattr(self, "config"): self.config = serialize_config({ **kwargs, }) digest_config(self, kwargs) self.epsilon = 1.0 / self.density Mobject.__init__(self, **kwargs)
def __init__(self, condition=(lambda x, y: True), **kwargs): """ Condition must be a function which takes in two real arrays (representing x and y values of space respectively) and return a boolean array. This can essentially look like a function from R^2 to {True, False}, but & and | must be used in place of "and" and "or" """ Mobject.__init__(self, **kwargs) self.condition = condition
def move_along_vector_field( mobject: Mobject, func: Callable[[np.ndarray], np.ndarray] ) -> Mobject: mobject.add_updater( lambda m, dt: m.shift( func(m.get_center()) * dt ) ) return mobject
def test_scale(self): s = random.Random().randint(-1000, 1000) x = random.Random().randint(-1000, 1000) y = random.Random().randint(-1000, 1000) z = random.Random().randint(-1000, 1000) obj = Mobject() obj.points = np.array([[x, y, z]]) obj.scale(s, about_point=np.array([0, 0, 0])) np.testing.assert_array_equal(obj.points, np.array([[x * s, y * s, z * s]]))
def interpolate_submobject( self, submob: Mobject, start: Mobject, alpha: float ) -> None: submob.match_points(start) submob.apply_function( self.function_at_time_t(alpha), **self.apply_function_kwargs )
def __init__(self, AnimationClass, mobjects, **kwargs): full_kwargs = AnimationClass.CONFIG full_kwargs.update(kwargs) full_kwargs["mobject"] = Mobject(*[ mob.get_point_mobject() for mob in mobjects ]) self.centers_container = AnimationClass(**full_kwargs) full_kwargs.pop("mobject") Animation.__init__(self, Mobject(*mobjects), **full_kwargs) self.name = str(self) + AnimationClass.__name__
def __init__(self, value=0, **kwargs): if not hasattr(self, "args"): self.args = serialize_args([]) if not hasattr(self, "config"): self.config = serialize_config({ 'value': value, **kwargs, }) Mobject.__init__(self, **kwargs) self.points = np.zeros((1, 3)) self.set_value(value)
def move_points_along_vector_field( mobject: Mobject, func: Callable[[float, float], Iterable[float]], coordinate_system: CoordinateSystem) -> Mobject: cs = coordinate_system origin = cs.get_origin() def apply_nudge(self, dt): mobject.apply_function(lambda p: p + (cs.c2p(*func(*cs.p2c(p))) - origin) * dt) mobject.add_updater(apply_nudge) return mobject
def test_shift(self): a = random.Random().randint(-1000, 1000) b = random.Random().randint(-1000, 1000) c = random.Random().randint(-1000, 1000) x = random.Random().randint(-1000, 1000) y = random.Random().randint(-1000, 1000) z = random.Random().randint(-1000, 1000) obj = Mobject() obj.points = np.array([[x, y, z]]) obj.shift(np.array([a, b, c])) np.testing.assert_array_equal(obj.points, np.array([[x + a, y + b, z + c]]))
def test_match_updater_2(self): a, b = Mobject(), Mobject() a.add_updater(__func__) a.add_updater(__dt_func__) self.assertListEqual([__func__, __dt_func__], a.updaters) self.assertListEqual([], b.updaters) a.match_updaters(b) self.assertListEqual([], a.updaters) self.assertListEqual([], b.updaters)
def __init__(self, **kwargs): digest_config(self, kwargs, locals()) if self.file_name is None: raise Exception("Must invoke Bubble subclass") SVGMobject.__init__(self, self.file_name, **kwargs) self.center() self.stretch_to_fit_height(self.height) self.stretch_to_fit_width(self.width) if self.direction[0] > 0: self.flip() self.direction_was_specified = ("direction" in kwargs) self.content = Mobject() self.refresh_triangulation()
def __init__(self, mobject: 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) power = np.exp(2.0 * (alpha - 0.5)) nudge = there_and_back(t**power) return np.array([x, y, z]) + nudge * vect super().__init__(homotopy, mobject, **kwargs)
def get_mobjects_to_display(self, mobjects, include_submobjects=True, excluded_mobjects=None): if include_submobjects: mobjects = Mobject.extract_mobject_family_members( mobjects, only_those_with_points=True, ) if excluded_mobjects: all_excluded = Mobject.extract_mobject_family_members( excluded_mobjects) mobjects = list_difference_update(mobjects, all_excluded) return mobjects
def __init__(self, **kwargs): digest_config(self, kwargs, locals()) if self.file_name is None: raise Exception("Must invoke Bubble subclass") try: SVGMobject.__init__(self, **kwargs) except IOError as err: self.file_name = os.path.join(FILE_DIR, self.file_name) SVGMobject.__init__(self, **kwargs) self.center() self.stretch_to_fit_height(self.height) self.stretch_to_fit_width(self.width) if self.direction[0] > 0: Mobject.flip(self) self.direction_was_specified = ("direction" in kwargs) self.content = Mobject()
def __init__(self, **kwargs): digest_config(self, kwargs) self.epsilon = 1.0 / self.density Mobject.__init__(self, **kwargs)
def get_array_attrs(self): return Mobject.get_array_attrs(self) + ["rgbas"]
def match_colors(self, mobject): Mobject.align_data(self, mobject) self.rgbas = np.array(mobject.rgbas) return self
class Bubble(SVGMobject): CONFIG = { "direction": LEFT, "center_point": ORIGIN, "content_scale_factor": 0.75, "height": 5, "width": 8, "bubble_center_adjustment_factor": 1. / 8, "file_name": None, "fill_color": BLACK, "fill_opacity": 0.8, "stroke_color": WHITE, "stroke_width": 3, } def __init__(self, **kwargs): digest_config(self, kwargs, locals()) if self.file_name is None: raise Exception("Must invoke Bubble subclass") try: SVGMobject.__init__(self, **kwargs) except IOError as err: self.file_name = os.path.join(FILE_DIR, self.file_name) SVGMobject.__init__(self, **kwargs) self.center() self.stretch_to_fit_height(self.height) self.stretch_to_fit_width(self.width) if self.direction[0] > 0: Mobject.flip(self) self.direction_was_specified = ("direction" in kwargs) self.content = Mobject() def get_tip(self): # TODO, find a better way return self.get_corner(DOWN + self.direction) - 0.6 * self.direction def get_bubble_center(self): factor = self.bubble_center_adjustment_factor return self.get_center() + factor * self.get_height() * UP def move_tip_to(self, point): mover = VGroup(self) if self.content is not None: mover.add(self.content) mover.shift(point - self.get_tip()) return self def flip(self): Mobject.flip(self) self.direction = -np.array(self.direction) return self def pin_to(self, mobject): mob_center = mobject.get_center() want_to_flip = np.sign(mob_center[0]) != np.sign(self.direction[0]) can_flip = not self.direction_was_specified if want_to_flip and can_flip: self.flip() boundary_point = mobject.get_critical_point(UP - self.direction) vector_from_center = 1.0 * (boundary_point - mob_center) self.move_tip_to(mob_center + vector_from_center) return self def position_mobject_inside(self, mobject): scaled_width = self.content_scale_factor * self.get_width() if mobject.get_width() > scaled_width: mobject.set_width(scaled_width) mobject.shift( self.get_bubble_center() - mobject.get_center() ) return mobject def add_content(self, mobject): self.position_mobject_inside(mobject) self.content = mobject return self.content def write(self, *text): self.add_content(TextMobject(*text)) return self def resize_to_content(self): target_width = self.content.get_width() target_width += max(MED_LARGE_BUFF, 2) target_height = self.content.get_height() target_height += 2.5 * LARGE_BUFF tip_point = self.get_tip() self.stretch_to_fit_width(target_width) self.stretch_to_fit_height(target_height) self.move_tip_to(tip_point) self.position_mobject_inside(self.content) def clear(self): self.add_content(VMobject()) return self
def flip(self): Mobject.flip(self) self.direction = -np.array(self.direction) return self