diff --git a/bell.py b/bell.py index eb85abcc..55b80082 100644 --- a/bell.py +++ b/bell.py @@ -34,131 +34,7 @@ from waves import * #force_skipping #revert_to_original_skipping_status -class FilterScene(ThreeDScene): - CONFIG = { - "filter_x_coordinates" : [0], - "pol_filter_configs" : [{}], - "EMWave_config" : { - "start_point" : SPACE_WIDTH*LEFT + DOWN+OUT - }, - "start_phi" : 0.8*np.pi/2, - "start_theta" : -0.6*np.pi, - "ambient_rotation_rate" : 0.01, - } - def setup(self): - self.axes = ThreeDAxes() - self.add(self.axes) - for x in range(len(self.filter_x_coordinates) - len(self.pol_filter_configs)): - self.pol_filter_configs.append({}) - self.pol_filters = VGroup(*[ - PolarizingFilter(**config) - for config in self.pol_filter_configs - ]) - self.pol_filters.rotate(np.pi/2, RIGHT) - self.pol_filters.rotate(-np.pi/2, OUT) - self.pol_filters.shift(DOWN+OUT) - for x, pf in zip(self.filter_x_coordinates, self.pol_filters): - pf.shift(x*RIGHT) - self.add(self.pol_filters) - self.pol_filter = self.pol_filters[0] - - self.set_camera_position(self.start_phi, self.start_theta) - if self.ambient_rotation_rate > 0: - self.begin_ambient_camera_rotation(self.ambient_rotation_rate) - - def get_filter_absorbtion_animation(self, pol_filter, photon): - x = pol_filter.get_center()[0] - alpha = (x + SPACE_WIDTH) / (2*SPACE_WIDTH) - return ApplyMethod( - pol_filter.set_fill, RED, - run_time = photon.run_time, - rate_func = squish_rate_func(there_and_back, alpha - 0.1, alpha + 0.1) - ) - -class DirectionOfPolarization(FilterScene): - CONFIG = { - "pol_filter_configs" : [{ - "include_arrow_label" : False, - }], - "target_theta" : -0.97*np.pi, - "target_phi" : 0.9*np.pi/2, - "ambient_rotation_rate" : 0.005, - "apply_filter" : False, - } - def setup(self): - self.reference_line = Line(ORIGIN, RIGHT) - self.reference_line.set_stroke(width = 0) - self.em_wave = EMWave(**self.EMWave_config) - self.add(self.em_wave) - - FilterScene.setup(self) - - def construct(self): - self.remove(self.pol_filter) - words = TextMobject("Polarization direction") - words.next_to(ORIGIN, UP+RIGHT, LARGE_BUFF) - words.shift(2*UP) - words.rotate(np.pi/2, RIGHT) - words.rotate(-np.pi/2, OUT) - - em_wave = self.em_wave - - self.add(em_wave) - self.dither(2) - self.move_camera( - phi = self.target_phi, - theta = self.target_theta - ) - self.play(Write(words, run_time = 1)) - self.change_polarization_direction( - 2*np.pi/3, - run_time = 6, - rate_func = there_and_back - ) - self.dither(2) - - def change_polarization_direction(self, angle, **kwargs): - added_anims = kwargs.get("added_anims", []) - self.play( - ApplyMethod( - self.reference_line.rotate, angle, - **kwargs - ), - *added_anims - ) - - def continual_update(self): - reference_angle = self.reference_line.get_angle() - self.em_wave.rotation = reference_angle - FilterScene.continual_update(self) - vect_groups = [self.em_wave.E_vects, self.em_wave.M_vects] - if self.apply_filter: - filters = sorted( - self.pol_filters, - lambda pf1, pf2 : cmp( - pf1.get_center()[0], - pf2.get_center()[0], - ) - ) - for pol_filter in filters: - filter_x = pol_filter.get_center()[0] - for vect_group, angle in zip(vect_groups, [0, -np.pi/2]): - proj_vect = rotate_vector( - OUT, pol_filter.filter_angle + angle, RIGHT, - ) - proj_matrix = np.array([RIGHT] + [ - proj_vect*np.dot(proj_vect, basis) - for basis in UP, OUT - ]).T - for vect in vect_group: - start, end = vect.get_start_and_end() - if start[0] > filter_x: - vect.apply_matrix(proj_matrix) - vect.shift(start - vect.get_start()) - vect.set_tip_points(vect.tip) - vect.set_rectangular_stem_points() - -class PhotonPassesCompletelyOrNotAtAll(DirectionOfPolarization): +class PhotonPassesCompletelyOrNotAtAll(DirectionOfPolarizationScene): CONFIG = { "pol_filter_configs" : [{ "include_arrow_label" : False, @@ -236,6 +112,31 @@ class PhotonPassesCompletelyOrNotAtAll(DirectionOfPolarization): ) self.dither() +class DirectionOfPolarization(DirectionOfPolarizationScene): + def construct(self): + self.remove(self.pol_filter) + words = TextMobject("Polarization direction") + words.next_to(ORIGIN, UP+RIGHT, LARGE_BUFF) + words.shift(2*UP) + words.rotate(np.pi/2, RIGHT) + words.rotate(-np.pi/2, OUT) + + em_wave = self.em_wave + + self.add(em_wave) + self.dither(2) + self.move_camera( + phi = self.target_phi, + theta = self.target_theta + ) + self.play(Write(words, run_time = 1)) + self.change_polarization_direction( + 2*np.pi/3, + run_time = 6, + rate_func = there_and_back + ) + self.dither(2) + class PhotonsThroughPerpendicularFilters(PhotonPassesCompletelyOrNotAtAll): CONFIG = { "filter_x_coordinates" : [-2, 2], @@ -515,7 +416,7 @@ class SecondVideoWrapper(Scene): self.play(ShowCreation(screen_rect)) self.dither(3) -class BasicsOfPolarization(DirectionOfPolarization): +class BasicsOfPolarization(DirectionOfPolarizationScene): CONFIG = { "apply_filter" : True, } @@ -648,8 +549,8 @@ class BasicsOfPolarization(DirectionOfPolarization): for index in 1, 0, 0, 1: self.play(*anim_sets[index]) - def continual_update(self): - DirectionOfPolarization.continual_update(self) + def continual_update(self, *args, **kwargs): + DirectionOfPolarization.continual_update(self, *args, **kwargs) if self.rectangles not in self.mobjects: return diff --git a/topics/number_line.py b/topics/number_line.py index 7564142a..cdf25c15 100644 --- a/topics/number_line.py +++ b/topics/number_line.py @@ -164,8 +164,8 @@ class Axes(VGroup): self.add(self.x_axis, self.y_axis) if self.three_d: self.z_axis = NumberLine( - x_min = self.min, - x_max = self.max, + x_min = self.z_min, + x_max = self.z_max, **self.number_line_config ) self.z_axis.rotate(-np.pi/2, UP) @@ -177,7 +177,7 @@ class ThreeDAxes(Axes): "x_min" : -5.5, "x_max" : 5.5, "y_min" : -4.5, - "y_max" : -4.5, + "y_max" : 4.5, "three_d" : True, } diff --git a/waves.py b/waves.py index 3ec38550..c3b2904e 100644 --- a/waves.py +++ b/waves.py @@ -296,6 +296,110 @@ class PolarizingFilter(Circle): ################ + +class FilterScene(ThreeDScene): + CONFIG = { + "filter_x_coordinates" : [0], + "pol_filter_configs" : [{}], + "EMWave_config" : { + "start_point" : SPACE_WIDTH*LEFT + DOWN+OUT + }, + "start_phi" : 0.8*np.pi/2, + "start_theta" : -0.6*np.pi, + "ambient_rotation_rate" : 0.01, + } + def setup(self): + self.axes = ThreeDAxes() + self.add(self.axes) + for x in range(len(self.filter_x_coordinates) - len(self.pol_filter_configs)): + self.pol_filter_configs.append({}) + self.pol_filters = VGroup(*[ + PolarizingFilter(**config) + for config in self.pol_filter_configs + ]) + self.pol_filters.rotate(np.pi/2, RIGHT) + self.pol_filters.rotate(-np.pi/2, OUT) + self.pol_filters.shift(DOWN+OUT) + for x, pf in zip(self.filter_x_coordinates, self.pol_filters): + pf.shift(x*RIGHT) + self.add(self.pol_filters) + self.pol_filter = self.pol_filters[0] + + self.set_camera_position(self.start_phi, self.start_theta) + if self.ambient_rotation_rate > 0: + self.begin_ambient_camera_rotation(self.ambient_rotation_rate) + + def get_filter_absorbtion_animation(self, pol_filter, photon): + x = pol_filter.get_center()[0] + alpha = (x + SPACE_WIDTH) / (2*SPACE_WIDTH) + return ApplyMethod( + pol_filter.set_fill, RED, + run_time = photon.run_time, + rate_func = squish_rate_func(there_and_back, alpha - 0.1, alpha + 0.1) + ) + +class DirectionOfPolarizationScene(FilterScene): + CONFIG = { + "pol_filter_configs" : [{ + "include_arrow_label" : False, + }], + "target_theta" : -0.97*np.pi, + "target_phi" : 0.9*np.pi/2, + "ambient_rotation_rate" : 0.005, + "apply_filter" : False, + } + def setup(self): + self.reference_line = Line(ORIGIN, RIGHT) + self.reference_line.set_stroke(width = 0) + self.em_wave = EMWave(**self.EMWave_config) + self.add(self.em_wave) + + FilterScene.setup(self) + + def change_polarization_direction(self, angle, **kwargs): + added_anims = kwargs.get("added_anims", []) + self.play( + ApplyMethod( + self.reference_line.rotate, angle, + **kwargs + ), + *added_anims + ) + + def continual_update(self, *args, **kwargs): + reference_angle = self.reference_line.get_angle() + self.em_wave.rotation = reference_angle + FilterScene.continual_update(self, *args, **kwargs) + vect_groups = [self.em_wave.E_vects, self.em_wave.M_vects] + if self.apply_filter: + filters = sorted( + self.pol_filters, + lambda pf1, pf2 : cmp( + pf1.get_center()[0], + pf2.get_center()[0], + ) + ) + for pol_filter in filters: + filter_x = pol_filter.get_center()[0] + for vect_group, angle in zip(vect_groups, [0, -np.pi/2]): + proj_vect = rotate_vector( + OUT, pol_filter.filter_angle + angle, RIGHT, + ) + proj_matrix = np.array([RIGHT] + [ + proj_vect*np.dot(proj_vect, basis) + for basis in UP, OUT + ]).T + for vect in vect_group: + start, end = vect.get_start_and_end() + if start[0] > filter_x: + vect.apply_matrix(proj_matrix) + vect.shift(start - vect.get_start()) + vect.set_tip_points(vect.tip) + vect.set_rectangular_stem_points() + + +################ + class IntroduceElectricField(PiCreatureScene): CONFIG = { "vector_field_colors" : [BLUE_B, BLUE_D], @@ -412,8 +516,8 @@ class IntroduceElectricField(PiCreatureScene): ### - def continual_update(self): - Scene.continual_update(self) + def continual_update(self, *args, **kwargs): + Scene.continual_update(self, *args, **kwargs) if hasattr(self, "moving_particles"): dt = self.frame_duration for p in self.moving_particles: @@ -574,8 +678,8 @@ class IntroduceMagneticField(IntroduceElectricField, ThreeDScene): ### - def continual_update(self): - Scene.continual_update(self) + def continual_update(self, *args, **kwargs): + Scene.continual_update(self, *args, **kwargs) if hasattr(self, "moving_particles"): dt = self.frame_duration for p in self.moving_particles: @@ -854,8 +958,6 @@ class ShowVectorEquation(Scene): "A_color" : GREEN, } def construct(self): - self.force_skipping() - self.add_vector() self.add_plane() self.write_horizontally_polarized() @@ -894,7 +996,10 @@ class ShowVectorEquation(Scene): self.dither(2) def write_horizontally_polarized(self): - words = TextMobject("``Horizontally polarized''") + words = TextMobject( + "``", "Horizontally", " polarized", "''", + arg_separator = "" + ) words.next_to(ORIGIN, LEFT) words.to_edge(UP) words.add_background_rectangle() @@ -907,7 +1012,7 @@ class ShowVectorEquation(Scene): def write_components(self): x, y = components = VGroup( TexMobject("\\cos(", "2\\pi", "f_x", "t", "+ ", "\\phi_x", ")"), - TexMobject("0") + TexMobject("0", "") ) components.arrange_submobjects(DOWN) lb, rb = brackets = TexMobject("[]") @@ -1131,7 +1236,6 @@ class ShowVectorEquation(Scene): 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), @@ -1142,6 +1246,8 @@ class ShowVectorEquation(Scene): corner_cos.next_to, corner_A, RIGHT, SMALL_BUFF, FadeIn(all_As) ) + x.add(A) + corner_cos.add(corner_A) self.dither() factor = 0.5 self.play( @@ -1156,11 +1262,122 @@ class ShowVectorEquation(Scene): ) self.dither(4) + self.h_brace = h_brace + self.v_brace = v_brace def add_kets(self): - pass + x, y = self.components + E_equals = self.E_equals + for mob in x, y, E_equals: + mob.add_background_rectangle() + mob.generate_target() + + right_ket = TexMobject("|\\rightarrow\\rangle") + up_ket = TexMobject("|\\uparrow\\rangle") + kets = VGroup(right_ket, up_ket) + kets.highlight(YELLOW) + for ket in kets: + ket.add_background_rectangle() + plus = TextMobject("+") + group = VGroup( + E_equals.target, + x.target, right_ket, plus, + y.target, up_ket, + ) + group.arrange_submobjects(RIGHT) + E_equals.target.shift(SMALL_BUFF*UP) + group.scale(0.8) + group.move_to(self.brackets, DOWN) + group.to_edge(LEFT, buff = MED_SMALL_BUFF) + + kets_word = TextMobject("``kets''") + kets_word.next_to(kets, DOWN, buff = 0.8) + arrows = VGroup(*[ + Arrow(kets_word.get_top(), ket, color = ket.get_color()) + for ket in kets + ]) + ket_rects = VGroup(*map(SurroundingRectangle, kets)) + ket_rects.highlight(WHITE) + unit_vectors = VGroup(*[Vector(2*vect) for vect in RIGHT, UP]) + unit_vectors.set_fill(YELLOW) + + self.play( + FadeOut(self.brackets), + *map(MoveToTarget, [E_equals, x, y]) + ) + self.play(*map(Write, [right_ket, plus, up_ket]), run_time = 1) + self.play( + Write(kets_word), + LaggedStart(ShowCreation, arrows, lag_ratio = 0.7), + run_time = 2, + ) + self.dither() + for ket, ket_rect, unit_vect in zip(kets, ket_rects, unit_vectors): + self.play(ShowCreation(ket_rect)) + self.play(FadeOut(ket_rect)) + self.play(ReplacementTransform(ket[1][1].copy(), unit_vect)) + self.dither() + self.play(FadeOut(unit_vectors)) + self.play(*map(FadeOut, [kets_word, arrows])) + + self.kets = kets + self.plus = plus def switch_to_vertically_polarized_light(self): + x, y = self.components + x_ket, y_ket = self.kets + plus = self.plus + + x.target = TexMobject("0", "").add_background_rectangle() + y.target = TexMobject( + "A_y", "\\cos(", "2\\pi", "f_y", "t", "+", "\\phi_y", ")" + ) + y.target.highlight_by_tex_to_color_map({ + "A" : self.A_color, + "f" : self.f_color, + "phi" : self.phi_color, + }) + y.target.add_background_rectangle() + VGroup(x.target, y.target).scale(0.8) + for mob in [plus] + list(self.kets): + mob.generate_target() + + movers = x, x_ket, plus, y, y_ket + group = VGroup(*[m.target for m in movers]) + group.arrange_submobjects(RIGHT) + group.move_to(x, LEFT) + + vector_A_vect = np.array(self.oscillating_vector.A_vect) + def update_vect(vect, alpha): + self.oscillating_vector.A_vect = rotate_vector( + vector_A_vect, alpha*np.pi/2 + ) + return vect + + new_h_brace = Brace(Line(ORIGIN, UP), RIGHT) + + words = TextMobject( + "``", "Vertically", " polarized", "''", + arg_separator = "", + ) + words.add_background_rectangle() + words.move_to(self.horizontally_polarized_words) + + self.play( + UpdateFromAlphaFunc(self.vector, update_vect), + Transform(self.h_brace, new_h_brace), + self.h_brace.A.next_to, new_h_brace, RIGHT, SMALL_BUFF, + Transform(self.horizontally_polarized_words, words), + *map(FadeOut, [ + self.corner_group, self.v_brace, + self.v_brace.A, self.low_f_graph, + ]) + ) + self.play(*map(MoveToTarget, movers)) + self.dither(5) + +class ChangeFromHorizontalToVerticallyPolarized(Scene): + def construct(self): pass @@ -1183,6 +1400,8 @@ class ShowVectorEquation(Scene): + +