diff --git a/animation/continual_animation.py b/animation/continual_animation.py index 0bb387a5..9b3d5fd7 100644 --- a/animation/continual_animation.py +++ b/animation/continual_animation.py @@ -1,5 +1,6 @@ from helpers import * from mobject import Mobject, Group +from simple_animations import MaintainPositionRelativeTo import copy class ContinualAnimation(object): @@ -63,7 +64,6 @@ class ContinualAnimationGroup(ContinualAnimation): for continual_animation in self.continual_animations: continual_animation.update(dt) - class AmbientRotation(ContinualAnimation): CONFIG = { "axis" : OUT, @@ -73,8 +73,6 @@ class AmbientRotation(ContinualAnimation): def update_mobject(self, dt): self.mobject.rotate(dt*self.rate, axis = self.axis) - - class AmbientMovement(ContinualAnimation): CONFIG = { "direction" : RIGHT, @@ -84,9 +82,21 @@ class AmbientMovement(ContinualAnimation): def update_mobject(self, dt): self.mobject.shift(dt*self.rate*self.direction) - - - +class ContinualUpdateFromFunc(ContinualAnimation): + def __init__(self, mobject, func, **kwargs): + self.func = func + ContinualAnimation.__init__(self, mobject, **kwargs) + + def update_mobject(self, dt): + self.func(self.mobject) + +class ContinualMaintainPositionRelativeTo(ContinualAnimation): + def __init__(self, mobject, tracked_mobject, **kwargs): + self.anim = MaintainPositionRelativeTo(mobject, tracked_mobject, **kwargs) + ContinualAnimation.__init__(self, mobject, **kwargs) + + def update_mobject(self, dt): + self.anim.update(0) diff --git a/scene/scene.py b/scene/scene.py index 3e9601fb..bf39e26d 100644 --- a/scene/scene.py +++ b/scene/scene.py @@ -122,9 +122,11 @@ class Scene(object): self.clear() ### - def continual_update(self): + def continual_update(self, dt = None): + if dt is None: + dt = self.frame_duration for continual_animation in self.continual_animations: - continual_animation.update(self.frame_duration) + continual_animation.update(dt) def wind_down(self, *continual_animations, **kwargs): wind_down_time = kwargs.get("wind_down_time", 1) @@ -384,6 +386,7 @@ class Scene(object): self.add(*moving_mobjects) self.mobjects_from_last_animation = moving_mobjects self.clean_up_animations(*animations) + self.continual_update(0) return self def clean_up_animations(self, *animations): diff --git a/topics/number_line.py b/topics/number_line.py index 5a5590ad..7564142a 100644 --- a/topics/number_line.py +++ b/topics/number_line.py @@ -141,28 +141,31 @@ class Axes(VGroup): "color" : LIGHT_GREY, "include_tip" : True, }, - "x_axis_radius" : SPACE_WIDTH, - "y_axis_radius" : SPACE_HEIGHT, - "z_axis_radius" : 3.5, + "x_min" : -SPACE_WIDTH, + "x_max" : SPACE_WIDTH, + "y_min" : -SPACE_HEIGHT, + "y_max" : SPACE_HEIGHT, + "z_min" : -3.5, + "z_max" : 3.5, } def __init__(self, **kwargs): VGroup.__init__(self, **kwargs) self.x_axis = NumberLine( - x_min = -self.x_axis_radius, - x_max = self.x_axis_radius, + x_min = self.x_min, + x_max = self.x_max, **self.number_line_config ) self.y_axis = NumberLine( - x_min = -self.y_axis_radius, - x_max = self.y_axis_radius, + x_min = self.y_min, + x_max = self.y_max, **self.number_line_config ) self.y_axis.rotate(np.pi/2) self.add(self.x_axis, self.y_axis) if self.three_d: self.z_axis = NumberLine( - x_min = -self.z_axis_radius, - x_max = self.z_axis_radius, + x_min = self.min, + x_max = self.max, **self.number_line_config ) self.z_axis.rotate(-np.pi/2, UP) @@ -171,8 +174,10 @@ class Axes(VGroup): class ThreeDAxes(Axes): CONFIG = { - "x_axis_radius" : 5.5, - "y_axis_radius" : 4.5, + "x_min" : -5.5, + "x_max" : 5.5, + "y_min" : -4.5, + "y_max" : -4.5, "three_d" : True, } diff --git a/waves.py b/waves.py index b1cf2a6f..3ec38550 100644 --- a/waves.py +++ b/waves.py @@ -762,7 +762,7 @@ class ListRelevantWaveIdeas(TeacherStudentsScene): topics = VGroup(*map(TextMobject, [ "- Superposition", "- Amplitudes", - "- Phase influences addition", + "- How phase influences addition", ])) topics.scale(0.8) topics.arrange_submobjects(DOWN, aligned_edge = LEFT) @@ -848,6 +848,11 @@ class DirectWaveOutOfScreen(IntroduceEMWave): self.dither(4) class ShowVectorEquation(Scene): + CONFIG = { + "f_color" : RED, + "phi_color" : MAROON_B, + "A_color" : GREEN, + } def construct(self): self.force_skipping() @@ -869,26 +874,288 @@ class ShowVectorEquation(Scene): frequency = 0.25, ) self.add(self.oscillating_vector) - self.revert_to_original_skipping_status() self.dither(3) def add_plane(self): - pass + xy_plane = NumberPlane( + axes_color = LIGHT_GREY, + color = DARK_GREY, + secondary_color = DARK_GREY, + x_unit_size = 2, + y_unit_size = 2, + ) + xy_plane.add_coordinates() + xy_plane.add(xy_plane.get_axis_labels()) + + self.play( + Write(xy_plane), + Animation(self.vector) + ) + self.dither(2) def write_horizontally_polarized(self): - pass + words = TextMobject("``Horizontally polarized''") + words.next_to(ORIGIN, LEFT) + words.to_edge(UP) + words.add_background_rectangle() + + self.play(Write(words, run_time = 3)) + self.dither() + + self.horizontally_polarized_words = words def write_components(self): - pass + x, y = components = VGroup( + TexMobject("\\cos(", "2\\pi", "f_x", "t", "+ ", "\\phi_x", ")"), + TexMobject("0") + ) + components.arrange_submobjects(DOWN) + lb, rb = brackets = TexMobject("[]") + brackets.scale_to_fit_height(components.get_height() + SMALL_BUFF) + lb.next_to(components, LEFT, buff = 0.3) + rb.next_to(components, RIGHT, buff = 0.3) + E, equals = E_equals = TexMobject( + "\\vec{\\textbf{E}}", "=" + ) + E.highlight(E_COLOR) + E_equals.next_to(brackets, LEFT) + E_equals.add_background_rectangle() + brackets.add_background_rectangle() + group = VGroup(E_equals, brackets, components) + group.next_to( + self.horizontally_polarized_words, + DOWN, MED_LARGE_BUFF, RIGHT + ) + + x_without_phi = TexMobject("\\cos(", "2\\pi", "f_x", "t", ")") + x_without_phi.move_to(x) + for mob in x, x_without_phi: + mob.highlight_by_tex_to_color_map({ + "f_x" : self.f_color, + "phi_x" : self.phi_color, + }) + + def update_brace(brace): + brace.stretch_to_fit_width( + max(self.vector.get_width(), 0.001) + ) + brace.next_to(self.vector.get_center(), DOWN, SMALL_BUFF) + return brace + moving_brace = ContinualUpdateFromFunc( + Brace(Line(LEFT, RIGHT), DOWN), update_brace + ) + moving_x_without_phi = ContinualUpdateFromFunc( + x_without_phi.copy().add_background_rectangle(), + lambda m : m.next_to(moving_brace.mobject, DOWN, SMALL_BUFF) + ) + + self.play(Write(E_equals), Write(brackets)) + y.save_state() + y.move_to(self.horizontally_polarized_words) + y.set_fill(opacity = 0) + self.play(y.restore) + self.dither() + self.add(moving_brace, moving_x_without_phi) + self.play( + FadeIn(moving_brace.mobject), + FadeIn(x_without_phi), + FadeIn(moving_x_without_phi.mobject), + submobject_mode = "lagged_start", + run_time = 2, + ) + self.dither(3) + self.play( + FadeOut(moving_brace.mobject), + FadeOut(moving_x_without_phi.mobject), + ) + self.remove(moving_brace, moving_x_without_phi) + + self.E_equals = E_equals + self.brackets = brackets + self.x_without_phi = x_without_phi + self.components = components def show_graph(self): - pass + axes = Axes( + x_min = -0.5, + x_max = 5.2, + y_min = -1.5, + y_max = 1.5, + ) + axes.x_axis.add_numbers(*range(1, 6)) + t = TexMobject("t") + t.next_to(axes.x_axis, UP, SMALL_BUFF, RIGHT) + cos = self.x_without_phi.copy() + cos.next_to(axes.y_axis, RIGHT, SMALL_BUFF, UP) + cos_arg = VGroup(*cos[1:-1]) + fx_equals_1 = TexMobject("f_x", "= 1") + fx_equals_fourth = TexMobject("f_x", "= 0.25") + fx_group = VGroup(fx_equals_1, fx_equals_fourth) + for fx in fx_group: + fx[0].highlight(self.f_color) + fx.move_to(axes, UP+RIGHT) + high_f_graph, low_f_graph = graphs = VGroup(*[ + FunctionGraph( + lambda x : np.cos(2*np.pi*f*x), + color = E_COLOR, + x_min = 0, + x_max = 4/f, + num_steps = 20/f, + ) + for f in 1, 0.25, + ]) + + group = VGroup(axes, t, cos, high_f_graph, *fx_group) + rect = SurroundingRectangle( + group, + buff = MED_LARGE_BUFF, + stroke_color = WHITE, + stroke_width = 3, + fill_color = BLACK, + fill_opacity = 0.9 + ) + group.add_to_back(rect) + group.scale(0.8) + group.to_corner(UP+RIGHT, buff = -SMALL_BUFF) + group.remove(*it.chain(fx_group, graphs)) + low_f_graph.scale(0.8) + low_f_graph.move_to(high_f_graph, LEFT) + + cos_arg_rect = SurroundingRectangle(cos_arg) + + new_ov = OscillatingVector( + Vector(RIGHT, color = E_COLOR), + A_vect = [2, 0, 0], + frequency = 1, + start_up_time = 0, + ) + + self.play(FadeIn(group)) + self.play( + ReplacementTransform( + self.components[0].get_part_by_tex("f_x").copy(), + fx_equals_1 + ), + ) + self.dither(4 - (self.oscillating_vector.internal_time%4)) + self.remove(self.oscillating_vector) + self.add(new_ov) + self.play(ShowCreation( + high_f_graph, run_time = 4, + rate_func = None, + )) + self.dither() + self.play(FadeOut(new_ov.vector)) + self.remove(new_ov) + self.add(self.oscillating_vector) + self.play( + ReplacementTransform(*fx_group), + ReplacementTransform(*graphs), + FadeOut(new_ov.vector), + FadeIn(self.vector) + ) + self.dither(4) + self.play(ShowCreation(cos_arg_rect)) + self.play(FadeOut(cos_arg_rect)) + self.dither(5) + + self.corner_group = group + self.fx_equals_fourth = fx_equals_fourth + self.corner_cos = cos + self.low_f_graph = low_f_graph + self.graph_axes = axes def add_phi(self): - pass + corner_cos = self.corner_cos + corner_phi = TexMobject("+", "\\phi_x") + corner_phi.highlight_by_tex("phi", self.phi_color) + corner_phi.scale(0.8) + corner_phi.next_to(corner_cos[-2], RIGHT, SMALL_BUFF) + + x, y = self.components + x_without_phi = self.x_without_phi + + words = TextMobject("``Phase shift''") + words.next_to(ORIGIN, UP+LEFT) + words.highlight(self.phi_color) + words.add_background_rectangle() + arrow = Arrow(words.get_top(), x[-2]) + arrow.highlight(WHITE) + + self.play( + ReplacementTransform( + VGroup(*x_without_phi[:-1]), + VGroup(*x[:-3]), + ), + ReplacementTransform(x_without_phi[-1], x[-1]), + Write(VGroup(*x[-3:-1])), + corner_cos[-1].next_to, corner_phi.copy(), RIGHT, SMALL_BUFF, + Write(corner_phi), + FadeOut(self.fx_equals_fourth), + ) + self.play(self.low_f_graph.shift, MED_LARGE_BUFF*LEFT) + self.play( + Write(words, run_time = 1), + ShowCreation(arrow) + ) + self.dither(3) + self.play(*map(FadeOut, [words, arrow])) + + self.corner_cos.add(corner_phi) def add_amplitude(self): - pass + x, y = self.components + corner_cos = self.corner_cos + graph = self.low_f_graph + graph_y_axis = self.graph_axes.y_axis + + A = TexMobject("A_x") + A.highlight(self.A_color) + A.move_to(x.get_left()) + corner_A = A.copy() + corner_A.scale(0.8) + corner_A.move_to(corner_cos, LEFT) + + h_brace = Brace(Line(ORIGIN, 2*RIGHT), UP) + v_brace = Brace(Line( + graph_y_axis.number_to_point(0), + graph_y_axis.number_to_point(1), + ), LEFT, buff = SMALL_BUFF) + for brace in h_brace, v_brace: + brace.A = brace.get_tex("A_x") + brace.A.highlight(self.A_color) + v_brace.A.scale(0.5, about_point = v_brace.get_center()) + all_As = VGroup(A, corner_A, h_brace.A, v_brace.A) + + def update_vect(vect): + self.oscillating_vector.A_vect[0] = h_brace.get_width() + return vect + + self.revert_to_original_skipping_status() + self.play( + GrowFromCenter(h_brace), + GrowFromCenter(v_brace), + ) + self.dither(2) + self.play( + x.next_to, A, RIGHT, SMALL_BUFF, + corner_cos.next_to, corner_A, RIGHT, SMALL_BUFF, + FadeIn(all_As) + ) + self.dither() + factor = 0.5 + self.play( + v_brace.stretch_in_place, factor, 1, + v_brace.move_to, v_brace.copy(), DOWN, + MaintainPositionRelativeTo(v_brace.A, v_brace), + h_brace.stretch_in_place, factor, 0, + h_brace.move_to, h_brace.copy(), LEFT, + MaintainPositionRelativeTo(h_brace.A, h_brace), + UpdateFromFunc(self.vector, update_vect), + graph.stretch_in_place, factor, 1, + ) + self.dither(4) + def add_kets(self): pass