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.continual_animation 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 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 * E_COLOR = BLUE M_COLOR = YELLOW class OscillatingVector(ContinualAnimation): CONFIG = { "tail" : ORIGIN, "frequency" : 1, "A_vect" : [1, 0, 0], "phi_vect" : [0, 0, 0], "vector_to_be_added_to" : None, } def setup(self): self.vector = self.mobject def update_mobject(self, dt): f = self.frequency t = self.internal_time angle = 2*np.pi*f*t vect = np.array([ A*np.exp(complex(0, angle + phi)) for A, phi in zip(self.A_vect, self.phi_vect) ]).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" : 1, "frequency" : 0.25, "n_vectors" : 40, "propogation_direction" : RIGHT, "start_point" : SPACE_WIDTH*LEFT, "length" : 2*SPACE_WIDTH, "amplitude" : 1, "rotation" : 0, "A_vect" : [0, 0, 1], "phi_vect" : [0, 0, 0], } def __init__(self, **kwargs): digest_config(self, kwargs) self.matrix_transform = np.dot( z_to_vector(self.propogation_direction), np.linalg.inv(z_to_vector(RIGHT)), ) vector_oscillations = [] self.E_vects = VGroup() self.M_vects = VGroup() self.A_vect = np.array(self.A_vect)/np.linalg.norm(self.A_vect) self.A_vect *= self.amplitude for alpha in np.linspace(0, 1, self.n_vectors): tail = interpolate(ORIGIN, self.length*RIGHT, alpha) phase = -alpha*self.length*self.wave_number kwargs = { "phi_vect" : np.array(self.phi_vect) + phase, "frequency" : self.frequency, "tail" : np.array(tail), } E_ov = OscillatingVector( Vector( OUT, color = E_COLOR, normal_vector = UP, ), A_vect = self.A_vect, **kwargs ) M_ov = OscillatingVector( Vector( UP, color = M_COLOR, normal_vector = OUT, ), A_vect = rotate_vector(self.A_vect, np.pi/2, RIGHT), **kwargs ) vector_oscillations += [E_ov, M_ov] self.E_vects.add(E_ov.vector) self.M_vects.add(M_ov.vector) ContinualAnimationGroup.__init__(self, *vector_oscillations) def update_mobject(self, dt): ContinualAnimationGroup.update_mobject(self, dt) self.mobject.rotate(self.rotation, RIGHT) 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, "phi_vect" : np.ones(3)*np.pi/4, }, "em_wave" : None, "run_time" : 4, "rate_func" : None, "packet_width" : 6, "include_E_vects" : True, "include_M_vects" : True, "filter_distance" : SPACE_WIDTH, "get_filtered" : False, "remover" : True, } def __init__(self, **kwargs): digest_config(self, kwargs) em_wave = self.em_wave if em_wave is None: 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.E_func(distance_from_packet) 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 E_func(self, x): return np.sin(x)*np.exp(-0.25*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, "include_arrow_label" : True, } 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, 0.7*UP, color = WHITE, buff = 0, ) arrow.shift(self.get_top()) arrow.rotate(-self.filter_angle) self.add(arrow) self.arrow = arrow shade_in_3d(self) if self.include_arrow_label: arrow_label = TexMobject( "%.1f^\\circ"%(self.filter_angle*180/np.pi) ) arrow_label.add_background_rectangle() 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(ThreeDScene): def construct(self): self.add(ThreeDAxes()) self.set_camera_position(0.8*np.pi/2, -0.6*np.pi) self.begin_ambient_camera_rotation(rate = 0.01) self.add(EMWave(A_vect = [0, 1, 1])) self.dither(2) self.move_camera(theta = -1.1*np.pi) self.dither(2) # 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) # photon = WavePacket( # run_time = 2, # # get_filtered = True, # EMWave_config = { # "start_point" : SPACE_WIDTH*LEFT + DOWN+OUT, # "A_vect" : [0, 1, 0], # }, # ) # photon.update(0.5) # photon.mobject.show(self.camera) # self.move_camera(theta = -1.2*np.pi/2) # self.play(photon)