mirror of
https://github.com/3b1b/manim.git
synced 2026-04-26 03:00:23 -04:00
First wave animations for Bell's project
This commit is contained in:
531
bell.py
531
bell.py
@@ -27,25 +27,518 @@ from camera import Camera
|
||||
from mobject.svg_mobject import *
|
||||
from mobject.tex_mobject import *
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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 PhotonPassesCompletelyOrNotAtAll(FilterScene):
|
||||
CONFIG = {
|
||||
"pol_filter_configs" : [{
|
||||
"include_arrow_label" : False,
|
||||
"label_tex" : "\\text{Filter}",
|
||||
}],
|
||||
"start_theta" : -0.9*np.pi,
|
||||
"target_theta" : -0.6*np.pi,
|
||||
}
|
||||
def construct(self):
|
||||
pol_filter = self.pol_filter
|
||||
label = pol_filter.label
|
||||
pol_filter.remove(label)
|
||||
label.shift(SMALL_BUFF*IN)
|
||||
|
||||
passing_words = TextMobject("Photon", "passes through")
|
||||
passing_words.highlight(GREEN)
|
||||
filtered_words = TextMobject("Photon", "is blocked")
|
||||
filtered_words.highlight(RED)
|
||||
for words in passing_words, filtered_words:
|
||||
words.next_to(ORIGIN, UP+LEFT)
|
||||
words.shift(2*UP)
|
||||
words.add_background_rectangle()
|
||||
words.rotate(np.pi/2, RIGHT)
|
||||
|
||||
passing_photon = WavePacket(
|
||||
run_time = 3,
|
||||
get_filtered = False,
|
||||
EMWave_config = self.EMWave_config
|
||||
)
|
||||
new_em_wave_config = dict(self.EMWave_config)
|
||||
new_em_wave_config["A_x"] = 0
|
||||
new_em_wave_config["A_y"] = 1
|
||||
filtered_photon = WavePacket(
|
||||
run_time = 3,
|
||||
get_filtered = True,
|
||||
EMWave_config = new_em_wave_config
|
||||
)
|
||||
|
||||
|
||||
self.play(
|
||||
DrawBorderThenFill(pol_filter),
|
||||
Write(label, run_time = 2)
|
||||
)
|
||||
self.move_camera(theta = self.target_theta)
|
||||
self.play(Write(passing_words, run_time = 1))
|
||||
self.play(passing_photon)
|
||||
self.play(Transform(passing_words, filtered_words))
|
||||
self.play(
|
||||
filtered_photon,
|
||||
ApplyMethod(
|
||||
pol_filter.set_fill, RED,
|
||||
rate_func = squish_rate_func(there_and_back, 0.4, 0.6),
|
||||
run_time = filtered_photon.run_time
|
||||
)
|
||||
)
|
||||
self.dither(3)
|
||||
|
||||
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" : True,
|
||||
}
|
||||
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):
|
||||
FilterScene.continual_update(self)
|
||||
wave = self.em_wave.mobject
|
||||
angle = self.reference_line.get_angle()
|
||||
wave.rotate(
|
||||
angle, self.em_wave.propogation_direction,
|
||||
about_point = self.em_wave.start_point,
|
||||
)
|
||||
if self.apply_filter:
|
||||
filter_x = self.pol_filter.get_center()[0]
|
||||
for vect_group, angle in (self.em_wave.E_vects, 0), (self.em_wave.M_vects, np.pi/2):
|
||||
proj_vect = rotate_vector(
|
||||
OUT, self.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())
|
||||
|
||||
|
||||
class PhotonsThroughPerpendicularFilters(DirectionOfPolarization):
|
||||
CONFIG = {
|
||||
"filter_x_coordinates" : [-2, 2],
|
||||
"pol_filter_configs" : [
|
||||
{"filter_angle" : 0},
|
||||
{"filter_angle" : np.pi/2},
|
||||
],
|
||||
"start_theta" : -0.9*np.pi,
|
||||
"target_theta" : -0.6*np.pi,
|
||||
"EMWave_config" : {
|
||||
"wave_number" : 0,
|
||||
}
|
||||
}
|
||||
def setup(self):
|
||||
DirectionOfPolarization.setup(self)
|
||||
self.remove(self.em_wave)
|
||||
|
||||
def construct(self):
|
||||
photons = self.get_photons()[:2]
|
||||
prob_text = self.get_probability_text()
|
||||
self.pol_filters = VGroup(*reversed(self.pol_filters))
|
||||
|
||||
self.play(LaggedStart(DrawBorderThenFill, self.pol_filters))
|
||||
self.move_camera(
|
||||
theta = self.target_theta,
|
||||
added_anims = [
|
||||
FadeIn(prob_text)
|
||||
]
|
||||
)
|
||||
for x in range(4):
|
||||
pairs = zip(photons, self.pol_filters)
|
||||
random.shuffle(pairs)
|
||||
for photon, pol_filter in pairs:
|
||||
self.play(
|
||||
photon,
|
||||
self.get_filter_absorbtion_animation(
|
||||
pol_filter, photon
|
||||
)
|
||||
)
|
||||
|
||||
def get_photons(self):
|
||||
self.reference_line.rotate(np.pi/4)
|
||||
self.continual_update()
|
||||
return [
|
||||
WavePacket(
|
||||
filter_distance = SPACE_WIDTH + x,
|
||||
get_filtered = True,
|
||||
em_wave = self.em_wave.copy(),
|
||||
run_time = 1.5,
|
||||
)
|
||||
for x in 2, -2, 10
|
||||
]
|
||||
|
||||
def get_probability_text(self, prob = 0):
|
||||
prob_text = TexMobject(
|
||||
"P(", "\\substack", "{\\text{photons that make it} \\\\ ",
|
||||
" \\text{here } ", "\\text{make it}",
|
||||
" \\text{ here} }", ")", "=", str(int(prob*100)), "\\%",
|
||||
arg_separator = ""
|
||||
)
|
||||
here1, here2 = prob_text.get_parts_by_tex("here")
|
||||
here1.highlight(GREEN)
|
||||
here2.highlight(RED)
|
||||
prob_text.add_background_rectangle()
|
||||
prob_text.next_to(ORIGIN, UP+RIGHT)
|
||||
prob_text.shift(2.5*UP+LEFT)
|
||||
prob_text.rotate(np.pi/2, RIGHT)
|
||||
arrows = [
|
||||
Arrow(
|
||||
here.get_edge_center(IN),
|
||||
DOWN+OUT + x*RIGHT,
|
||||
color = here.get_color(),
|
||||
normal_vector = DOWN+OUT,
|
||||
)
|
||||
for here, x in (here1, 0), (here2, 4)
|
||||
]
|
||||
prob_text.add(*arrows)
|
||||
|
||||
return prob_text
|
||||
|
||||
class AngryPiCreature(PiCreatureScene):
|
||||
def construct(self):
|
||||
self.pi_creature_says(
|
||||
"No, \\emph{locality} \\\\ must be wrong!",
|
||||
target_mode = "angry",
|
||||
look_at_arg = 2*RIGHT,
|
||||
run_time = 1
|
||||
)
|
||||
self.dither(3)
|
||||
|
||||
def create_pi_creature(self):
|
||||
return Randolph().shift(DOWN+3*LEFT)
|
||||
|
||||
class ShowALittleMath(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
expression = TexMobject(
|
||||
"\\alpha", "| \\! \\uparrow \\rangle", "+",
|
||||
"\\beta", "| \\! \\rightarrow \\rangle",
|
||||
)
|
||||
expression.highlight_by_tex("uparrow", GREEN)
|
||||
expression.highlight_by_tex("rightarrow", RED)
|
||||
expression.next_to(self.teacher, UP+LEFT, LARGE_BUFF)
|
||||
|
||||
prob = TexMobject("\\text{Probability}", "=", "|", "\\alpha", "|^2")
|
||||
prob.next_to(expression, UP, LARGE_BUFF)
|
||||
|
||||
self.play(
|
||||
Write(expression),
|
||||
self.teacher.change, "raise_right_hand"
|
||||
)
|
||||
target_alpha = prob.get_part_by_tex("alpha")
|
||||
prob.remove(target_alpha)
|
||||
self.play(
|
||||
ReplacementTransform(
|
||||
expression.get_part_by_tex("alpha").copy(),
|
||||
target_alpha,
|
||||
),
|
||||
Write(prob)
|
||||
)
|
||||
self.change_student_modes(
|
||||
*["pondering"]*3,
|
||||
look_at_arg = prob
|
||||
)
|
||||
self.dither(2)
|
||||
|
||||
class SecondVideoWrapper(Scene):
|
||||
def construct(self):
|
||||
title = TextMobject("Some light quantum mechanics")
|
||||
title.to_edge(UP)
|
||||
self.add(title)
|
||||
|
||||
screen_rect = ScreenRectangle(height = 6)
|
||||
screen_rect.next_to(title, DOWN)
|
||||
self.play(ShowCreation(screen_rect))
|
||||
self.dither(3)
|
||||
|
||||
class BasicsOfPolarization(DirectionOfPolarization):
|
||||
def construct(self):
|
||||
self.show_continual_wave()
|
||||
self.show_photons()
|
||||
|
||||
def show_continual_wave(self):
|
||||
em_wave = self.em_wave
|
||||
em_wave.M_vects.set_fill(opacity = 0.5)
|
||||
|
||||
title = TextMobject("Waves in the ``electromagnetic field''")
|
||||
title.to_edge(UP)
|
||||
subtitle = TextMobject("Polarization = Direction of", "wiggling")
|
||||
subtitle.highlight_by_tex("wiggling", YELLOW)
|
||||
subtitle.next_to(title, DOWN)
|
||||
for words in title, subtitle:
|
||||
words.add_background_rectangle()
|
||||
words.rotate(np.pi/2, RIGHT)
|
||||
|
||||
self.play(Write(title))
|
||||
self.dither(2)
|
||||
self.play(Write(subtitle, run_time = 2))
|
||||
self.change_polarization_direction(np.pi/2, run_time = 3)
|
||||
self.dither(2)
|
||||
self.change_polarization_direction(-np.pi/12, run_time = 2)
|
||||
self.dither()
|
||||
self.move_camera(theta = -0.95*np.pi)
|
||||
self.dither()
|
||||
self.change_polarization_direction(-np.pi/6, run_time = 2)
|
||||
self.dither()
|
||||
self.move_camera(theta = -0.6*np.pi)
|
||||
self.dither()
|
||||
self.play(FadeOut(em_wave.mobject))
|
||||
self.remove(em_wave)
|
||||
self.reference_line.put_start_and_end_on(ORIGIN, RIGHT)
|
||||
|
||||
def show_photons(self):
|
||||
quantum_left_words = TextMobject(
|
||||
"Quantum", "$\\Rightarrow$",
|
||||
)
|
||||
quantum_left_words.next_to(ORIGIN, UP+RIGHT)
|
||||
quantum_left_words.shift(UP)
|
||||
quantum_right_words = TextMobject(
|
||||
"Completely through", "or \\\\",
|
||||
"Completely blocked",
|
||||
)
|
||||
quantum_right_words.scale(0.8)
|
||||
quantum_right_words.next_to(quantum_left_words, buff = 0)
|
||||
quantum_right_words.highlight_by_tex("through", GREEN)
|
||||
quantum_right_words.highlight_by_tex("blocked", RED)
|
||||
quantum_words = VGroup(quantum_left_words, quantum_right_words)
|
||||
quantum_words.rotate(np.pi/2, RIGHT)
|
||||
|
||||
config = dict(self.EMWave_config)
|
||||
config.update({
|
||||
"wave_number" : 0,
|
||||
"A_x" : -1,
|
||||
"A_y" : 1,
|
||||
})
|
||||
self.em_wave = EMWave(**config)
|
||||
self.continual_update()
|
||||
passing_photon = WavePacket(
|
||||
em_wave = self.em_wave.copy(),
|
||||
run_time = 2,
|
||||
)
|
||||
filtered_photon = WavePacket(
|
||||
em_wave = self.em_wave.copy(),
|
||||
get_filtered = True,
|
||||
run_time = 2,
|
||||
)
|
||||
|
||||
self.play(FadeIn(
|
||||
quantum_words,
|
||||
run_time = 2,
|
||||
submobject_mode = "lagged_start"
|
||||
))
|
||||
anim_sets = [
|
||||
[passing_photon],
|
||||
[
|
||||
filtered_photon,
|
||||
self.get_filter_absorbtion_animation(
|
||||
self.pol_filter,
|
||||
filtered_photon
|
||||
)
|
||||
],
|
||||
]
|
||||
for index in 0, 1, 0, 0, 1:
|
||||
self.play(*anim_sets[index])
|
||||
|
||||
class AngleToProbabilityChart(Scene):
|
||||
def construct(self):
|
||||
TextMobject("Angle between filters")
|
||||
TextMobject(
|
||||
"Probability that one"
|
||||
)
|
||||
|
||||
class ShowVariousFilterPairs(PhotonsThroughPerpendicularFilters):
|
||||
CONFIG = {
|
||||
"filter_x_coordinates" : [-2, 2, 2, 2, 2],
|
||||
"pol_filter_configs" : [
|
||||
{"filter_angle" : angle}
|
||||
for angle in 0, 0, np.pi/2, np.pi/4, np.pi/8
|
||||
],
|
||||
}
|
||||
def construct(self):
|
||||
self.photons = self.get_photons()
|
||||
|
||||
self.add_filters()
|
||||
self.add_probability_text()
|
||||
self.show_photons()
|
||||
self.revert_to_original_skipping_status()
|
||||
for pol_filter in self.pol_filters[2:]:
|
||||
self.change_to_new_filter(pol_filter)
|
||||
self.show_photons()
|
||||
|
||||
def add_filters(self):
|
||||
self.remove(*self.pol_filters[1:])
|
||||
self.dither()
|
||||
self.play(ReplacementTransform(
|
||||
self.pol_filters[0].copy().set_fill(BLACK, 1),
|
||||
self.pol_filters[1]
|
||||
))
|
||||
self.move_camera(
|
||||
theta = -0.6*np.pi,
|
||||
added_anims = list(it.chain(*[
|
||||
[
|
||||
pf.arrow_label.rotate_in_place, np.pi/2, OUT,
|
||||
pf.arrow_label.next_to, pf.arrow, RIGHT
|
||||
]
|
||||
for pf in self.pol_filters[:2]
|
||||
]))
|
||||
)
|
||||
for pf in self.pol_filters[2:]:
|
||||
pf.arrow_label.rotate_in_place(np.pi/2, OUT)
|
||||
pf.arrow_label.next_to(pf.arrow, RIGHT)
|
||||
|
||||
self.second_filter = self.pol_filters[1]
|
||||
self.add_foreground_mobject(self.second_filter)
|
||||
|
||||
def add_probability_text(self):
|
||||
prob_text = self.get_probability_text(self.get_prob())
|
||||
self.play(FadeIn(prob_text))
|
||||
self.prob_text = prob_text
|
||||
|
||||
def show_photons(self, n_photons = 5):
|
||||
p = self.get_prob()
|
||||
photons = [
|
||||
copy.deepcopy(self.photons[2 if random.random() < p else 0])
|
||||
for x in range(n_photons)
|
||||
]
|
||||
for photon in photons:
|
||||
added_anims = []
|
||||
if photon.filter_distance == 2:
|
||||
added_anims.append(self.get_filter_absorbtion_animation(
|
||||
self.second_filter, photon
|
||||
))
|
||||
self.play(photon, *added_anims, run_time = 1.5)
|
||||
self.dither()
|
||||
|
||||
def change_to_new_filter(self, pol_filter):
|
||||
self.play(Transform(self.second_filter, pol_filter))
|
||||
self.second_filter.filter_angle = pol_filter.filter_angle
|
||||
new_prob_text = self.get_probability_text(self.get_prob())
|
||||
new_prob_text[1][-2].highlight(YELLOW)
|
||||
self.play(Transform(self.prob_text, new_prob_text))
|
||||
|
||||
####
|
||||
|
||||
def get_prob(self):
|
||||
return np.cos(self.second_filter.filter_angle)**2
|
||||
|
||||
|
||||
class ForgetPreviousActions(PhotonsThroughPerpendicularFilters):
|
||||
CONFIG = {
|
||||
"filter_x_coordinates" : [-6, -2, 2],
|
||||
"pol_filter_configs" : [
|
||||
{"filter_angle" : angle}
|
||||
for angle in np.pi/4, 0, np.pi/4
|
||||
],
|
||||
"start_theta" : -0.6*np.pi
|
||||
}
|
||||
def construct(self):
|
||||
for pf in self.pol_filters:
|
||||
pf.arrow_label.rotate_in_place(np.pi/2, OUT)
|
||||
pf.arrow_label.next_to(pf.arrow, RIGHT)
|
||||
|
||||
rect = SurroundingRectangle(VGroup(*self.pol_filters[1:]))
|
||||
rect.rotate_in_place(np.pi/2, RIGHT)
|
||||
rect.stretch_
|
||||
words = TextMobject(
|
||||
"Probabilities depend only\\\\",
|
||||
"on this angle difference"
|
||||
)
|
||||
words.rotate(np.pi/2, RIGHT)
|
||||
words.next_to(rect, OUT)
|
||||
self.add(rect, words)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -82,14 +82,15 @@ class Mobject(object):
|
||||
setattr(self, attr, func(getattr(self, attr)))
|
||||
return self
|
||||
|
||||
def get_image(self):
|
||||
from camera import Camera
|
||||
camera = Camera()
|
||||
def get_image(self, camera = None):
|
||||
if camera is None:
|
||||
from camera import Camera
|
||||
camera = Camera()
|
||||
camera.capture_mobject(self)
|
||||
return Image.fromarray(camera.get_image())
|
||||
|
||||
def show(self):
|
||||
self.get_image().show()
|
||||
def show(self, camera = None):
|
||||
self.get_image(camera = camera).show()
|
||||
|
||||
def save_image(self, name = None):
|
||||
self.get_image().save(
|
||||
|
||||
@@ -82,6 +82,8 @@ class TexMobject(SVGMobject):
|
||||
tex += "\\,"
|
||||
if tex == "\\sqrt":
|
||||
tex += "{\\quad}"
|
||||
if tex == "\\substack":
|
||||
tex = ""
|
||||
for t1, t2 in ("\\left", "\\right"), ("\\right", "\\left"):
|
||||
should_replace = reduce(op.and_, [
|
||||
t1 in tex,
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
\usepackage{calligra}
|
||||
\usepackage{wasysym}
|
||||
\usepackage{ragged2e}
|
||||
\usepackage{physics}
|
||||
|
||||
\begin{document}
|
||||
|
||||
|
||||
@@ -182,7 +182,8 @@ class Arrow(Line):
|
||||
"color" : YELLOW_C,
|
||||
"tip_length" : 0.25,
|
||||
"tip_width_to_length_ratio" : 1,
|
||||
"max_tip_length_to_length_ratio" : 0.25,
|
||||
"max_tip_length_to_length_ratio" : 0.35,
|
||||
"max_stem_width_to_tip_width_ratio" : 0.3,
|
||||
"buff" : MED_SMALL_BUFF,
|
||||
"propogate_style_to_family" : False,
|
||||
"preserve_tip_size_when_scaling" : True,
|
||||
@@ -229,8 +230,12 @@ class Arrow(Line):
|
||||
tip_base = center_of_mass(tip_base_points)
|
||||
tbp1, tbp2 = tip_base_points
|
||||
perp_vect = tbp2 - tbp1
|
||||
perp_vect /= np.linalg.norm(perp_vect)
|
||||
width = self.rectangular_stem_width
|
||||
tip_base_width = np.linalg.norm(perp_vect)
|
||||
perp_vect /= tip_base_width
|
||||
width = min(
|
||||
self.rectangular_stem_width,
|
||||
self.max_stem_width_to_tip_width_ratio*tip_base_width,
|
||||
)
|
||||
self.rect.set_points_as_corners([
|
||||
tip_base + perp_vect*width/2,
|
||||
start + perp_vect*width/2,
|
||||
|
||||
@@ -144,7 +144,7 @@ class ThreeDScene(Scene):
|
||||
def set_camera_position(self, phi = None, theta = None, distance = None):
|
||||
self.camera.set_position(phi, theta, distance)
|
||||
|
||||
def begin_ambient_camera_rotation(self, rate = -0.01*np.pi):
|
||||
def begin_ambient_camera_rotation(self, rate = 0.01):
|
||||
self.ambient_camera_rotation = AmbientRotation(
|
||||
self.camera.position_mobject,
|
||||
axis = OUT,
|
||||
|
||||
78
waves.py
78
waves.py
@@ -29,7 +29,7 @@ from mobject.svg_mobject import *
|
||||
from mobject.tex_mobject import *
|
||||
|
||||
E_COLOR = BLUE
|
||||
M_COLOR = RED
|
||||
M_COLOR = YELLOW
|
||||
|
||||
class OscillatingVector(ContinualAnimation):
|
||||
CONFIG = {
|
||||
@@ -107,7 +107,7 @@ class OscillatingVectorComponents(ContinualAnimationGroup):
|
||||
|
||||
class EMWave(ContinualAnimationGroup):
|
||||
CONFIG = {
|
||||
"wave_number" : 3,
|
||||
"wave_number" : 1,
|
||||
"frequency" : 0.25,
|
||||
"n_vectors" : 40,
|
||||
"propogation_direction" : RIGHT,
|
||||
@@ -134,7 +134,7 @@ class EMWave(ContinualAnimationGroup):
|
||||
|
||||
for alpha in np.linspace(0, 1, self.n_vectors):
|
||||
tail = interpolate(ORIGIN, self.length*OUT, alpha)
|
||||
phase = alpha*self.length*self.wave_number
|
||||
phase = -alpha*self.length*self.wave_number
|
||||
E_ov = OscillatingVector(
|
||||
Vector(UP, color = E_COLOR),
|
||||
tail = np.array(tail),
|
||||
@@ -163,10 +163,6 @@ class EMWave(ContinualAnimationGroup):
|
||||
|
||||
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)
|
||||
@@ -176,7 +172,10 @@ class WavePacket(Animation):
|
||||
"EMWave_config" : {
|
||||
"wave_number" : 0,
|
||||
"start_point" : SPACE_WIDTH*LEFT,
|
||||
"phi_x" : np.pi/4,
|
||||
"phi_y" : np.pi/4,
|
||||
},
|
||||
"em_wave" : None,
|
||||
"run_time" : 4,
|
||||
"rate_func" : None,
|
||||
"packet_width" : 6,
|
||||
@@ -184,12 +183,15 @@ class WavePacket(Animation):
|
||||
"include_M_vects" : True,
|
||||
"filter_distance" : SPACE_WIDTH,
|
||||
"get_filtered" : False,
|
||||
"remover" : True,
|
||||
}
|
||||
def __init__(self, **kwargs):
|
||||
digest_config(self, kwargs)
|
||||
em_wave = EMWave(**self.EMWave_config)
|
||||
em_wave.update(0)
|
||||
self.em_wave = em_wave
|
||||
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:
|
||||
@@ -219,17 +221,15 @@ class WavePacket(Animation):
|
||||
tail - packet_center,
|
||||
em_wave.propogation_direction
|
||||
)
|
||||
A = em_wave.amplitude*self.func(distance_from_packet)
|
||||
if np.abs(A) < 0.1:
|
||||
A = 0
|
||||
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 func(self, x):
|
||||
return np.sin(x)*np.exp(-0.5*x*x)
|
||||
def E_func(self, x):
|
||||
return np.sin(2*x)*np.exp(-0.25*x*x)
|
||||
|
||||
class FilterLabel(TexMobject):
|
||||
def __init__(self, tex, degrees, **kwargs):
|
||||
@@ -243,6 +243,7 @@ class PolarizingFilter(Circle):
|
||||
"fill_opacity" : 0.5,
|
||||
"label_tex" : None,
|
||||
"filter_angle" : 0,
|
||||
"include_arrow_label" : True,
|
||||
}
|
||||
def __init__(self, **kwargs):
|
||||
Circle.__init__(self, **kwargs)
|
||||
@@ -252,25 +253,31 @@ class PolarizingFilter(Circle):
|
||||
self.label.next_to(self.get_top(), DOWN, SMALL_BUFF)
|
||||
self.add(self.label)
|
||||
|
||||
arrow = Arrow(ORIGIN, MED_LARGE_BUFF*UP, buff = 0)
|
||||
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)
|
||||
|
||||
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
|
||||
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 TestCircularPolarization(ThreeDScene):
|
||||
class TestPhoton(ThreeDScene):
|
||||
def construct(self):
|
||||
self.add(ThreeDAxes())
|
||||
|
||||
@@ -288,20 +295,15 @@ class TestCircularPolarization(ThreeDScene):
|
||||
# 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()
|
||||
self.move_camera(theta = -1.2*np.pi/2)
|
||||
self.play(WavePacket(
|
||||
run_time = 2,
|
||||
# get_filtered = True,
|
||||
EMWave_config = {
|
||||
"start_point" : SPACE_WIDTH*LEFT + DOWN+OUT
|
||||
}
|
||||
))
|
||||
self.dither()
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user