diff --git a/animation/simple_animations.py b/animation/simple_animations.py index d3c1a45f..91775b7d 100644 --- a/animation/simple_animations.py +++ b/animation/simple_animations.py @@ -267,7 +267,6 @@ class MaintainPositionRelativeTo(Animation): self.diff ) - ### Animation modifiers ### class ApplyToCenters(Animation): diff --git a/extract_scene.py b/extract_scene.py index 928ef510..a9a3d96c 100644 --- a/extract_scene.py +++ b/extract_scene.py @@ -186,8 +186,8 @@ def main(): try: handle_scene(SceneClass(**scene_kwargs), **config) play_finish_sound() - # except RuntimeError as e: - # play_finish_sound() + except RuntimeError as e: + play_finish_sound() except: print "\n\n" traceback.print_exc() diff --git a/highD.py b/highD.py new file mode 100644 index 00000000..6790ad28 --- /dev/null +++ b/highD.py @@ -0,0 +1,237 @@ +from helpers import * + +from mobject.tex_mobject import TexMobject +from mobject import Mobject +from mobject.image_mobject import ImageMobject +from mobject.vectorized_mobject import * + +from animation.animation import Animation +from animation.transform import * +from animation.simple_animations import * +from animation.playground import * +from topics.geometry import * +from topics.characters import * +from topics.functions import * +from topics.fractals import * +from topics.number_line import * +from topics.combinatorics import * +from topics.numerals import * +from topics.three_dimensions import * +from topics.objects import * +from topics.probability import * +from topics.complex_numbers import * +from topics.common_scenes import * +from scene import Scene +from scene.reconfigurable_scene import ReconfigurableScene +from scene.zoomed_scene import * +from camera import Camera +from mobject.svg_mobject import * +from mobject.tex_mobject import * + +########## +#revert_to_original_skipping_status + +class MathIsATease(Scene): + def construct(self): + randy = Randolph() + lashes = VGroup() + for eye in randy.eyes: + for angle in np.linspace(-np.pi/3, np.pi/3, 12): + lash = Line(ORIGIN, RIGHT) + lash.set_stroke(DARK_GREY, 2) + lash.scale_to_fit_width(0.27) + lash.next_to(ORIGIN, RIGHT, buff = 0) + lash.rotate(angle + np.pi/2) + lash.shift(eye.get_center()) + lashes.add(lash) + lashes.do_in_place(lashes.stretch, 0.8, 1) + lashes.shift(0.04*DOWN) + + + fan = SVGMobject( + file_name = "fan", + fill_opacity = 1, + fill_color = YELLOW, + stroke_width = 2, + stroke_color = YELLOW, + height = 0.7, + ) + VGroup(*fan[-12:]).set_fill(YELLOW_E) + fan.rotate(-np.pi/4) + fan.move_to(randy) + fan.shift(0.85*UP+0.25*LEFT) + + self.add(randy) + self.play( + ShowCreation(lashes, submobject_mode = "all_at_once"), + randy.change, "tease", + randy.look, OUT, + ) + self.add_foreground_mobjects(fan) + eye_bottom_y = randy.eyes.get_bottom()[1] + self.play( + ApplyMethod( + lashes.apply_function, + lambda p : [p[0], eye_bottom_y, p[2]], + rate_func = Blink.CONFIG["rate_func"], + ), + Blink(randy), + DrawBorderThenFill(fan), + ) + self.play( + ApplyMethod( + lashes.apply_function, + lambda p : [p[0], eye_bottom_y, p[2]], + rate_func = Blink.CONFIG["rate_func"], + ), + Blink(randy), + ) + self.dither() + +class TODODeterminants(TODOStub): + CONFIG = { + "message" : "Determinants clip" + } + +class CircleToPairsOfPoints(Scene): + def construct(self): + plane = NumberPlane(written_coordinate_height = 0.3) + plane.scale(2) + plane.add_coordinates(y_vals = [-1, 1]) + background_plane = plane.copy() + background_plane.highlight(GREY) + background_plane.fade() + circle = Circle(radius = 2, color = YELLOW) + dot = Dot(circle.get_right(), color = LIGHT_GREY) + + equation = TexMobject("x", "^2", "+", "y", "^2", "=", "1") + equation.highlight_by_tex("x", GREEN) + equation.highlight_by_tex("y", RED) + equation.to_corner(UP+LEFT) + equation.add_background_rectangle() + + x, y = 1, 0 + coord_pair = TexMobject("(", "-%.02f"%x, ",", "-%.02f"%y, ")") + fixed_numbers = coord_pair.get_parts_by_tex(".00") + fixed_numbers.set_fill(opacity = 0) + coord_pair.add_background_rectangle() + coord_pair.next_to(dot, UP+RIGHT, SMALL_BUFF) + numbers = VGroup(*[ + DecimalNumber(val).replace(num, dim_to_match = 1) + for val, num in zip([x, y], fixed_numbers) + ]) + numbers[0].highlight(GREEN) + numbers[1].highlight(RED) + + def get_update_func(i): + return lambda t : dot.get_center()[i]/2.0 + + + self.add(background_plane, plane) + self.play(ShowCreation(circle)) + self.play(Write(equation)) + self.play( + LaggedStart(FadeIn, coord_pair), + ShowCreation(dot), + *[ + ReplacementTransform( + equation.get_parts_by_tex(tex).copy(), + number + ) + for tex, number in zip("xy", numbers) + ] + ) + self.play( + Rotating( + dot, run_time = 7, in_place = False, + rate_func = smooth, + ), + MaintainPositionRelativeTo(coord_pair, dot), + *[ + ChangingDecimal( + num, get_update_func(i), + tracked_mobject = fixed_num + ) + for num, i, fixed_num in zip( + numbers, (0, 1), fixed_numbers + ) + ] + ) + self.dither() + + ######### Rotation equations ########## + + rot_equation = TexMobject( + "\\Rightarrow" + "\\big(\\cos(\\theta)x - \\sin(\\theta)y\\big)^2 + ", + "\\big(\\sin(\\theta)x + \\cos(\\theta)y\\big)^2 = 1", + ) + rot_equation.scale(0.9) + rot_equation.next_to(equation, RIGHT) + rot_equation.add_background_rectangle() + + words = TextMobject("Rotational \\\\ symmetry") + words.next_to(ORIGIN, UP) + words.to_edge(RIGHT) + words.add_background_rectangle() + + arrow = Arrow( + words.get_left(), rot_equation.get_bottom(), + path_arc = -np.pi/6 + ) + randy = Randolph().to_corner(DOWN+LEFT) + + self.play( + Write(rot_equation, run_time = 2), + FadeOut(coord_pair), + FadeOut(numbers), + FadeOut(dot), + FadeIn(randy) + ) + self.play(randy.change, "confused", rot_equation) + self.play(Blink(randy)) + self.play( + Write(words, run_time = 1), + ShowCreation(arrow), + randy.look_at, words + ) + plane.remove(*plane.coordinate_labels) + self.play( + Rotate( + plane, np.pi/3, + run_time = 4, + rate_func = there_and_back + ), + Animation(equation), + Animation(rot_equation), + Animation(words), + Animation(arrow), + Animation(circle), + randy.change, "hooray" + ) + self.dither() + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mobject/mobject.py b/mobject/mobject.py index 849b54af..4dd49cd2 100644 --- a/mobject/mobject.py +++ b/mobject/mobject.py @@ -643,7 +643,6 @@ class Mobject(object): self.points = np.array([mobject.points[0]]) return self - def push_self_into_submobjects(self): copy = self.copy() copy.submobjects = [] diff --git a/topics/characters.py b/topics/characters.py index 377a8d1e..47b5dc7d 100644 --- a/topics/characters.py +++ b/topics/characters.py @@ -72,6 +72,7 @@ class PiCreature(SVGMobject): 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): @@ -151,11 +152,11 @@ class PiCreature(SVGMobject): self.eyes.submobjects[1].get_center()[0] def blink(self): - eye_bottom_y = self.eyes.get_bottom()[1] - for mob in self.eyes, self.pupils: - mob.apply_function( - lambda p : [p[0], eye_bottom_y, p[2]] - ) + 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): diff --git a/topics/common_scenes.py b/topics/common_scenes.py index fde9f8ec..431a88db 100644 --- a/topics/common_scenes.py +++ b/topics/common_scenes.py @@ -150,7 +150,13 @@ 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.dither() diff --git a/topics/number_line.py b/topics/number_line.py index fd5157ca..82082e7b 100644 --- a/topics/number_line.py +++ b/topics/number_line.py @@ -222,10 +222,11 @@ class NumberPlane(VMobject): return self.axes.get_height() / (2.0*self.y_radius) def get_coordinate_labels(self, x_vals = None, y_vals = None): - result = [] - if x_vals == None and y_vals == None: - x_vals = range(-int(self.x_radius), int(self.x_radius)) - y_vals = range(-int(self.y_radius), int(self.y_radius)) + coordinate_labels = VGroup() + if x_vals == None: + x_vals = range(-int(self.x_radius), int(self.x_radius)+1) + if y_vals == None: + y_vals = range(-int(self.y_radius), int(self.y_radius)+1) for index, vals in enumerate([x_vals, y_vals]): num_pair = [0, 0] for val in vals: @@ -238,10 +239,10 @@ class NumberPlane(VMobject): num.scale_to_fit_height( self.written_coordinate_height ) - vect = DOWN if index == 0 else LEFT - num.next_to(point, vect, buff = SMALL_BUFF) - result.append(num) - return result + num.next_to(point, DOWN+LEFT, buff = SMALL_BUFF) + coordinate_labels.add(num) + self.coordinate_labels = coordinate_labels + return coordinate_labels def get_axes(self): return self.axes diff --git a/topics/numerals.py b/topics/numerals.py index 1c57647c..6bf31774 100644 --- a/topics/numerals.py +++ b/topics/numerals.py @@ -1,6 +1,5 @@ - -from mobject.vectorized_mobject import VMobject, VGroup +from mobject.vectorized_mobject import VMobject, VGroup, VectorizedPoint from mobject.tex_mobject import TexMobject from animation import Animation from scene import Scene @@ -44,61 +43,55 @@ class Integer(VGroup): #Todo, this class is now broken -class RangingValue(Animation): +class ChangingDecimal(Animation): CONFIG = { "num_decimal_points" : 2, - "rate_func" : None, + "spare_parts" : 2, + "position_update_func" : None, "tracked_mobject" : None, - "tracked_mobject_next_to_kwargs" : {}, - "scale_factor" : None, - "color" : WHITE, } - def __init__(self, value_function, **kwargs): - """ - Value function should return a real value - depending on the state of the surrounding scene - """ + def __init__(self, decimal_number, number_update_func, **kwargs): digest_config(self, kwargs, locals()) - self.update_mobject() - Animation.__init__(self, self.mobject, **kwargs) - - def update_mobject(self, alpha = 0): - mobject = DecimalNumber( - self.value_function(alpha), - num_decimal_points = self.num_decimal_points, - color = self.color, + decimal_number.add(*[ + VectorizedPoint(decimal_number.get_corner(DOWN+LEFT)) + for x in range(self.spare_parts)] ) - if not hasattr(self, "mobject"): - self.mobject = mobject - else: - self.mobject.points = mobject.points - self.mobject.submobjects = mobject.submobjects - if self.scale_factor: - self.mobject.scale(self.scale_factor) - elif self.tracked_mobject: - self.mobject.next_to( - self.tracked_mobject, - **self.tracked_mobject_next_to_kwargs - ) - return self + Animation.__init__(self, decimal_number, **kwargs) + + def update_mobject(self, alpha): + self.update_number(alpha) + self.update_position() + + def update_number(self, alpha): + decimal = self.decimal_number + new_decimal = DecimalNumber(self.number_update_func(alpha)) + new_decimal.replace(decimal, dim_to_match = 1) + new_decimal.highlight(decimal.get_color()) + decimal.align_data(new_decimal) + families = [ + mob.family_members_with_points() + for mob in decimal, new_decimal + ] + for sm1, sm2 in zip(*families): + sm1.interpolate(sm1, sm2, 1) + + def update_position(self): + if self.position_update_func is not None: + self.position_update_func(self.decimal_number) + elif self.tracked_mobject is not None: + self.decimal_number.move_to(self.tracked_mobject) + + + + + + + + + -class RangingValueScene(Scene): - CONFIG = { - "ranging_values" : [] - } - def add_ranging_value(self, value_function, **kwargs): - self.ranging_values.append( - RangingValue(value_function, **kwargs) - ) - - def update_frame(self, *args, **kwargs): - for val in self.ranging_values: - self.remove(val.mobject) - val.update_mobject() - self.add(val.mobject) - return Scene.update_frame(self, *args, **kwargs)