diff --git a/waves.py b/waves.py index 27f0da64..1695a7c4 100644 --- a/waves.py +++ b/waves.py @@ -8,7 +8,7 @@ from mobject.vectorized_mobject import * from animation.animation import Animation from animation.transform import * from animation.simple_animations import * -from animation.continual_animation import ContinualAnimation +from animation.continual_animation import * from animation.playground import * from topics.geometry import * from topics.characters import * @@ -39,6 +39,7 @@ class OscillatingVector(ContinualAnimation): "A_y" : 0, "phi_x" : 0, "phi_y" : 0, + "vector_to_be_added_to" : None, } def setup(self): self.vector = self.mobject @@ -52,35 +53,255 @@ class OscillatingVector(ContinualAnimation): self.A_y*np.exp(complex(0, angle + self.phi_y)), 0, ]).real + self.update_tail() self.vector.put_start_and_end_on(self.tail, self.tail+vect) + def update_tail(self): + if self.vector_to_be_added_to is not None: + self.tail = self.vector_to_be_added_to.get_end() + +class OscillatingVectorComponents(ContinualAnimationGroup): + CONFIG = { + "tip_to_tail" : False, + } + def __init__(self, oscillating_vector, **kwargs): + digest_config(self, kwargs) + vx = Vector(UP, color = GREEN).fade() + vy = Vector(UP, color = RED).fade() + kwargs = { + "frequency" : oscillating_vector.frequency, + "tail" : oscillating_vector.tail, + } + ovx = OscillatingVector( + vx, + A_x = oscillating_vector.A_x, + phi_x = oscillating_vector.phi_x, + A_y = 0, + phi_y = 0, + **kwargs + ) + ovy = OscillatingVector( + vy, + A_x = 0, + phi_x = 0, + A_y = oscillating_vector.A_y, + phi_y = oscillating_vector.phi_y, + **kwargs + ) + components = [ovx, ovy] + self.vectors = VGroup(ovx.vector, ovy.vector) + if self.tip_to_tail: + ovy.vector_to_be_added_to = ovx.vector + else: + self.lines = VGroup() + for ov1, ov2 in (ovx, ovy), (ovy, ovx): + ov_line = ov1.copy() + ov_line.mobject = ov_line.vector = DashedLine( + UP, DOWN, color = ov1.vector.get_color() + ) + ov_line.vector_to_be_added_to = ov2.vector + components.append(ov_line) + self.lines.add(ov_line.line) + + ContinualAnimationGroup.__init__(self, *components, **kwargs) + +class EMWave(ContinualAnimationGroup): + CONFIG = { + "wave_number" : 3, + "frequency" : 0.25, + "n_vectors" : 40, + "propogation_direction" : RIGHT, + "start_point" : SPACE_WIDTH*LEFT, + "length" : 2*SPACE_WIDTH, + "amplitude" : 1, + "rotation" : 0, + "A_x" : 1, + "A_y" : 0, + "phi_x" : 0, + "phi_y" : 0, + } + def __init__(self, **kwargs): + digest_config(self, kwargs) + self.matrix_transform = z_to_vector(self.propogation_direction) + + vector_oscillations = [] + self.E_vects = VGroup() + self.M_vects = VGroup() + + A_multiplier = float(self.amplitude) / (self.A_x**2 + self.A_y**2) + self.A_x *= A_multiplier + self.A_y *= A_multiplier + + for alpha in np.linspace(0, 1, self.n_vectors): + tail = interpolate(ORIGIN, self.length*OUT, alpha) + phase = alpha*self.length*self.wave_number + E_ov = OscillatingVector( + Vector(UP, color = E_COLOR), + tail = np.array(tail), + A_x = self.A_x, + A_y = self.A_y, + phi_x = self.phi_x + phase, + phi_y = self.phi_y + phase, + frequency = self.frequency + ) + M_ov = OscillatingVector( + Vector(UP, color = M_COLOR), + tail = np.array(tail), + A_x = -self.A_y, + A_y = self.A_x, + phi_x = self.phi_y + phase, + phi_y = self.phi_x + phase, + frequency = self.frequency + ) + vector_oscillations += [E_ov, M_ov] + E_ov.vector.normal_vector = UP + M_ov.vector.normal_vector = RIGHT + self.E_vects.add(E_ov.vector) + self.M_vects.add(M_ov.vector) + ContinualAnimationGroup.__init__(self, *vector_oscillations) + # make_3d(self.mobject) + + def update_mobject(self, dt): + ContinualAnimationGroup.update_mobject(self, dt) + # for vect in self.E_vects: + # vect.rotate_in_place(np.pi/2, RIGHT) + # for vect in self.M_vects: + # vect.rotate_in_place(np.pi/2, UP) + self.mobject.rotate(self.rotation, OUT) + self.mobject.apply_matrix(self.matrix_transform) + self.mobject.shift(self.start_point) + +class WavePacket(Animation): + CONFIG = { + "EMWave_config" : { + "wave_number" : 0, + "start_point" : SPACE_WIDTH*LEFT, + }, + "run_time" : 4, + "rate_func" : None, + "packet_width" : 6, + "include_E_vects" : True, + "include_M_vects" : True, + "filter_distance" : SPACE_WIDTH, + "get_filtered" : False, + } + def __init__(self, **kwargs): + digest_config(self, kwargs) + em_wave = EMWave(**self.EMWave_config) + em_wave.update(0) + self.em_wave = em_wave + + self.vects = VGroup() + if self.include_E_vects: + self.vects.add(*em_wave.E_vects) + if self.include_M_vects: + self.vects.add(*em_wave.M_vects) + for vect in self.vects: + vect.save_state() + + u = em_wave.propogation_direction + self.wave_packet_start, self.wave_packet_end = [ + em_wave.start_point - u*self.packet_width/2, + em_wave.start_point + u*(em_wave.length + self.packet_width/2) + ] + Animation.__init__(self, self.vects, **kwargs) + + def update_mobject(self, alpha): + packet_center = interpolate( + self.wave_packet_start, + self.wave_packet_end, + alpha + ) + em_wave = self.em_wave + for vect in self.vects: + tail = vect.get_start() + distance_from_packet = np.dot( + tail - packet_center, + em_wave.propogation_direction + ) + A = em_wave.amplitude*self.func(distance_from_packet) + if np.abs(A) < 0.1: + A = 0 + distance_from_start = np.linalg.norm(tail - em_wave.start_point) + if self.get_filtered and distance_from_start > self.filter_distance: + A = 0 + vect.restore() + vect.scale(A/vect.get_length(), about_point = tail) + + def func(self, x): + return np.sin(x)*np.exp(-0.5*x*x) + +class FilterLabel(TexMobject): + def __init__(self, tex, degrees, **kwargs): + TexMobject.__init__(self, tex + " \\uparrow", **kwargs) + self[-1].rotate(-degrees * np.pi / 180) + +class PolarizingFilter(Circle): + CONFIG = { + "stroke_color" : DARK_GREY, + "fill_color" : LIGHT_GREY, + "fill_opacity" : 0.5, + "label_tex" : None, + "filter_angle" : 0, + } + def __init__(self, **kwargs): + Circle.__init__(self, **kwargs) + + if self.label_tex: + self.label = TexMobject(self.label_tex) + self.label.next_to(self.get_top(), DOWN, SMALL_BUFF) + self.add(self.label) + + arrow = Arrow(ORIGIN, MED_LARGE_BUFF*UP, buff = 0) + arrow.shift(self.get_top()) + arrow.rotate(-self.filter_angle) + self.add(arrow) + self.arrow = arrow + + arrow_label = TexMobject( + "%.1f^\\circ"%(self.filter_angle*180/np.pi) + ) + arrow_label.next_to(arrow.get_tip(), UP) + self.add(arrow_label) + self.arrow_label = arrow_label class EMScene(Scene): def construct(self): pass -class Test(Scene): +class TestCircularPolarization(ThreeDScene): def construct(self): - E_vect = Vector(UP, color = E_COLOR) - wiggle = OscillatingVector( - E_vect, - A_x = 2, - A_y = 1, - phi_x = np.pi/2, - frequency = 0.5, - tail = UP+RIGHT, - ) - randy = Randolph() + self.add(ThreeDAxes()) - self.add(randy) - self.play(ShowCreation(wiggle.mobject)) - self.add(wiggle) - self.dither(4) - self.wind_down(wiggle) - self.dither() - # self.play(FadeOut(E_vect)) - # self.dither(2) + self.set_camera_position(0.8*np.pi/2, -0.6*np.pi) + self.begin_ambient_camera_rotation(rate = 0.01) + + # pol_filter = PolarizingFilter( + # label_tex = "C", + # filter_angle = np.pi/4, + # ) + # pol_filter.rotate(np.pi/2, RIGHT) + # pol_filter.rotate(-np.pi/2, OUT) + # pol_filter.shift(DOWN+OUT) + # pol_filter.arrow_label.rotate_in_place(np.pi/4, OUT) + # shade_in_3d(pol_filter) + # self.add(pol_filter) + + wave = EMWave(wave_number = 1, A_y = 1, phi_y = np.pi/2) + shade_in_3d(wave.mobject) + self.add(wave) + self.dither(20) + # self.dither() + # self.move_camera(theta = -1.2*np.pi/2) + # self.play(WavePacket( + # run_time = 3, + # get_filtered = True, + # EMWave_config = { + # "start_point" : SPACE_WIDTH*LEFT + DOWN+OUT + # } + # )) + # self.dither()