From 0835d52bb4f3bebe8701b53549034ea6fe02697a Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Mon, 16 Jan 2017 13:26:46 -0800 Subject: [PATCH] Initial zoom in on diamond fractal --- constants.py | 3 +- fractal_dimension.py | 141 ++++++++++++++++++++++++++++--------------- helpers.py | 2 + mobject/mobject.py | 11 ++++ topics/fractals.py | 10 ++- 5 files changed, 114 insertions(+), 53 deletions(-) diff --git a/constants.py b/constants.py index 426f8ffa..9fb20e83 100644 --- a/constants.py +++ b/constants.py @@ -6,7 +6,8 @@ DEFAULT_WIDTH = 1920 LOW_QUALITY_FRAME_DURATION = 1./20 MEDIUM_QUALITY_FRAME_DURATION = 1./30 -PRODUCTION_QUALITY_FRAME_DURATION = 1./60 +# PRODUCTION_QUALITY_FRAME_DURATION = 1./60 +PRODUCTION_QUALITY_FRAME_DURATION = 1./30 #There might be other configuration than pixel_shape later... PRODUCTION_QUALITY_CAMERA_CONFIG = { diff --git a/fractal_dimension.py b/fractal_dimension.py index e794d1cd..c4094ca6 100644 --- a/fractal_dimension.py +++ b/fractal_dimension.py @@ -57,70 +57,111 @@ class SierpinskiTest(Scene): class ZoomInOnFractal(PiCreatureScene): CONFIG = { "fractal_order" : 6, - "num_zooms" : 4, - "fractal_class" : Sierpinski, + "num_zooms" : 5, + "fractal_class" : DiamondFractal, "index_to_replace" : 0, } def construct(self): morty = self.pi_creature - fractal = self.get_zoomable_fractal() - fractal.show() - - self.play( - ShowCreation( - fractal, - run_time = 4, - rate_func = rush_from - ), - morty.change_mode, "hooray", - ) - self.dither() - self.play( - ApplyMethod( - fractal.scale, 2**self.num_zooms, - self.zoom_in_about_point, - run_time = 8 - ), - morty.change_mode, "thinking", - morty.look_at, fractal.get_corner(self.zoom_in_about_point), - ) - self.play(Blink(morty)) - self.dither() - - def get_zoomable_fractal(self): fractal = self.fractal_class(order = self.fractal_order) + fractal.show() - to_be_tweaked = fractal - for x in range(self.num_zooms): - new_corner = self.fractal_class(order = self.fractal_order) - new_corner.replace(to_be_tweaked[self.index_to_replace]) - self.tweak_subpart(new_corner) - to_be_tweaked.submobjects[self.index_to_replace] = new_corner - to_be_tweaked = new_corner - self.zoom_in_about_point = to_be_tweaked.get_center() + fractal = self.introduce_fractal() + self.change_mode("thinking") + self.blink() + self.zoom_in(fractal) + + def introduce_fractal(self): + fractal = self.fractal_class(order = 0) + self.play(FadeIn(fractal)) + for order in range(1, self.fractal_order+1): + new_fractal = self.fractal_class(order = order) + self.play( + Transform(fractal, new_fractal, run_time = 2), + self.pi_creature.change_mode, "hooray" + ) return fractal - def tweak_subpart(self, subpart): - pass + def zoom_in(self, fractal): + grower = fractal[self.index_to_replace] + grower_target = fractal.copy() + + for x in range(self.num_zooms): + self.tweak_fractal_subpart(grower_target) + grower_family = grower.family_members_with_points() + everything = VGroup(*[ + submob + for submob in fractal.family_members_with_points() + if not submob.is_off_screen() + if submob not in grower_family + ]) + everything.generate_target() + everything.target.shift( + grower_target.get_center()-grower.get_center() + ) + everything.target.scale( + grower_target.get_height()/grower.get_height() + ) + + self.play( + Transform(grower, grower_target), + MoveToTarget(everything), + self.pi_creature.change_mode, "thinking", + run_time = 2 + ) + self.dither() + grower_target = grower.copy() + grower = grower[self.index_to_replace] -class ZoomInOnDiamondFractal(ZoomInOnFractal): - CONFIG = { - "fractal_order" : 5, - "fractal_class" : DiamondFractal, - } + def tweak_fractal_subpart(self, subpart): + subpart.rotate_in_place(np.pi/4) + +class WhatAreFractals(TeacherStudentsScene): def construct(self): - high_res_fractal = self.fractal_class(order = self.fractal_order) - low_res_fractal = self.fractal_class(order = self.fractal_order-1) - - high_res_fractal.scale(3, high_res_fractal.get_top()) - - self.add(low_res_fractal) + self.student_says( + "But what \\emph{is} a fractal", + student_index = 2, + width = 6 + ) + self.change_student_modes("thinking", "pondering", None) self.dither() - self.play(Transform(low_res_fractal, high_res_fractal)) - self.dither(3) + + name = TextMobject("Benoit Mandelbrot") + name.to_corner(UP+LEFT) + # picture = Rectangle(height = 4, width = 3) + picture = ImageMobject("Mandelbrot") + picture.scale_to_fit_height(4) + picture.next_to(name, DOWN) + self.play( + Write(name, run_time = 2), + FadeIn(picture), + *[ + ApplyMethod(pi.look_at, name) + for pi in self.get_everyone() + ] + ) + self.dither(2) + question = TextMobject("Aren't they", "self-similar", "shapes?") + question.highlight_by_tex("self-similar", YELLOW) + self.student_says(question) + self.play(self.get_teacher().change_mode, "happy") + self.dither(2) + + + + + + + + + + + + + diff --git a/helpers.py b/helpers.py index dd7fa057..f17e1f36 100644 --- a/helpers.py +++ b/helpers.py @@ -116,6 +116,8 @@ def color_to_int_rgb(color): return (255*color_to_rgb(color)).astype('uint8') def color_gradient(reference_colors, length_of_output): + if length_of_output == 0: + return reference_colors[0] rgbs = map(color_to_rgb, reference_colors) alphas = np.linspace(0, (len(rgbs) - 1), length_of_output) floors = alphas.astype('int') diff --git a/mobject/mobject.py b/mobject/mobject.py index a9966e0f..e6cd04d5 100644 --- a/mobject/mobject.py +++ b/mobject/mobject.py @@ -270,6 +270,17 @@ class Mobject(object): self.to_edge(vect, **kwargs) return self + def is_off_screen(self): + if self.get_left()[0] > SPACE_WIDTH: + return True + if self.get_right()[0] < -SPACE_WIDTH: + return True + if self.get_bottom()[1] > SPACE_HEIGHT: + return True + if self.get_top()[1] < -SPACE_HEIGHT: + return True + return False + def stretch_in_place(self, factor, dim): self.do_in_place(self.stretch, factor, dim) return self diff --git a/topics/fractals.py b/topics/fractals.py index d8756fee..d42f1d99 100644 --- a/topics/fractals.py +++ b/topics/fractals.py @@ -30,7 +30,12 @@ class SelfSimilarFractal(VMobject): self.gradient_highlight(*self.colors) def generate_points(self): - self.submobjects = self.get_order_n_self(self.order).submobjects + order_n_self = self.get_order_n_self(self.order) + if self.order == 0: + self.submobjects = [order_n_self] + else: + self.submobjects = order_n_self.submobjects + return self def get_order_n_self(self, order): if order == 0: @@ -69,7 +74,8 @@ class Sierpinski(SelfSimilarFractal): class DiamondFractal(SelfSimilarFractal): CONFIG = { "num_subparts" : 4, - "height" : 6, + "height" : 4, + "colors" : [GREEN_E, YELLOW], } def get_seed_shape(self): return RegularPolygon(n = 4)