mirror of
https://github.com/3b1b/manim.git
synced 2025-08-05 16:49:03 +00:00
Added QuaternionHistory Scene
This commit is contained in:
parent
5b9ae8ddb3
commit
a1e21a4606
1 changed files with 324 additions and 26 deletions
|
@ -32,7 +32,7 @@ def get_three_d_scene_config(high_quality=True):
|
||||||
"num_axis_pieces": 1,
|
"num_axis_pieces": 1,
|
||||||
},
|
},
|
||||||
"sphere_config": {
|
"sphere_config": {
|
||||||
# "resolution": (4, 12),
|
"resolution": (12, 24),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if high_quality:
|
if high_quality:
|
||||||
|
@ -396,8 +396,12 @@ class QuaternionTracker(ValueTracker):
|
||||||
class RubiksCube(VGroup):
|
class RubiksCube(VGroup):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"colors": [
|
"colors": [
|
||||||
"#C41E3A", "#009E60", "#0051BA",
|
"#FFD500", # Yellow
|
||||||
"#FF5800", "#FFD500", "#FFFFFF"
|
"#C41E3A", # Orange
|
||||||
|
"#009E60", # Green
|
||||||
|
"#FF5800", # Red
|
||||||
|
"#0051BA", # Blue
|
||||||
|
"#FFFFFF" # White
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -711,37 +715,328 @@ class IntroduceHamilton(Scene):
|
||||||
|
|
||||||
class QuaternionHistory(Scene):
|
class QuaternionHistory(Scene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
self.show_dot_product_and_cross_product() # With date
|
self.show_dot_product_and_cross_product()
|
||||||
self.teaching_students_quaternions()
|
self.teaching_students_quaternions()
|
||||||
self.show_anti_quaternion_quote()
|
self.show_anti_quaternion_quote()
|
||||||
self.mad_hatter()
|
self.mad_hatter()
|
||||||
self.vestiges_in_modern_notation()
|
|
||||||
|
|
||||||
|
|
||||||
def show_dot_product_and_cross_product(self):
|
def show_dot_product_and_cross_product(self):
|
||||||
date = TexMobject("1843")
|
date = TexMobject("1843")
|
||||||
|
date.scale(2)
|
||||||
date.to_edge(UP)
|
date.to_edge(UP)
|
||||||
|
|
||||||
|
t2c = self.t2c = {
|
||||||
|
"x_1": GREEN,
|
||||||
|
"x_2": GREEN,
|
||||||
|
"y_1": RED,
|
||||||
|
"y_2": RED,
|
||||||
|
"z_1": BLUE,
|
||||||
|
"z_2": BLUE,
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_colored_tex_mobject(tex):
|
||||||
|
return TexMobject(tex, tex_to_color_map=t2c)
|
||||||
|
|
||||||
v1, v2 = [
|
v1, v2 = [
|
||||||
Matrix([
|
Matrix([
|
||||||
["{}_{}".format(c, i)]
|
["{}_{}".format(c, i)]
|
||||||
for c in "xyz"
|
for c in "xyz"
|
||||||
])
|
], element_to_mobject=get_colored_tex_mobject)
|
||||||
for i in (1, 2)
|
for i in (1, 2)
|
||||||
]
|
]
|
||||||
|
dot_rhs = get_colored_tex_mobject(
|
||||||
|
"x_1 x_2 + y_1 y_2 + z_1 z_2",
|
||||||
|
)
|
||||||
|
cross_rhs = Matrix([
|
||||||
|
["y_1 z_2 - z_1 y_2"],
|
||||||
|
["z_1 x_2 - x_1 z_2"],
|
||||||
|
["x_1 y_2 - y_1 x_2"],
|
||||||
|
], element_to_mobject=get_colored_tex_mobject)
|
||||||
|
|
||||||
|
dot_product = VGroup(
|
||||||
|
v1.copy(), TexMobject("\\cdot").scale(2),
|
||||||
|
v2.copy(), TexMobject("="),
|
||||||
|
dot_rhs
|
||||||
|
)
|
||||||
|
cross_product = VGroup(
|
||||||
|
v1.copy(), TexMobject("\\times"),
|
||||||
|
v2.copy(), TexMobject("="),
|
||||||
|
cross_rhs
|
||||||
|
)
|
||||||
|
for product in dot_product, cross_product:
|
||||||
|
product.arrange_submobjects(RIGHT, buff=2 * SMALL_BUFF)
|
||||||
|
product.set_height(1.5)
|
||||||
|
dot_product.next_to(date, DOWN, buff=MED_LARGE_BUFF)
|
||||||
|
dot_product.to_edge(LEFT, buff=LARGE_BUFF)
|
||||||
|
cross_product.next_to(
|
||||||
|
dot_product, DOWN,
|
||||||
|
buff=MED_LARGE_BUFF,
|
||||||
|
aligned_edge=LEFT,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.play(FadeInFrom(dot_product, 2 * RIGHT))
|
||||||
|
self.play(FadeInFrom(cross_product, 2 * LEFT))
|
||||||
|
self.wait()
|
||||||
|
self.play(FadeInFromDown(date))
|
||||||
|
self.play(ApplyMethod(dot_product.fade, 0.7))
|
||||||
|
self.play(ApplyMethod(cross_product.fade, 0.7))
|
||||||
|
self.wait()
|
||||||
|
self.play(
|
||||||
|
FadeOutAndShift(dot_product, 2 * LEFT),
|
||||||
|
FadeOutAndShift(cross_product, 2 * RIGHT),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.date = date
|
||||||
|
|
||||||
def teaching_students_quaternions(self):
|
def teaching_students_quaternions(self):
|
||||||
pass
|
hamilton = ImageMobject("Hamilton")
|
||||||
|
hamilton.set_height(4)
|
||||||
|
hamilton.pixel_array = hamilton.pixel_array[:, ::-1, :]
|
||||||
|
hamilton.to_corner(UR)
|
||||||
|
hamilton.shift(MED_SMALL_BUFF * DOWN)
|
||||||
|
|
||||||
|
colors = color_gradient([BLUE_E, GREY_BROWN, BLUE_B], 7)
|
||||||
|
random.shuffle(colors)
|
||||||
|
students = VGroup(*[
|
||||||
|
PiCreature(color=color)
|
||||||
|
for color in colors
|
||||||
|
])
|
||||||
|
students.set_height(2)
|
||||||
|
students.arrange_submobjects(RIGHT)
|
||||||
|
students.set_width(FRAME_WIDTH - hamilton.get_width() - 1)
|
||||||
|
students.to_corner(DL)
|
||||||
|
|
||||||
|
equation = TexMobject("""
|
||||||
|
(x_1 i + y_1 j + z_1 k)
|
||||||
|
(x_2 i + y_2 j + z_2 k)
|
||||||
|
=
|
||||||
|
(-x_1 x_2 - y_1 y_2 - z_1 z_2) +
|
||||||
|
(y_1 z_2 - z_1 y_2)i +
|
||||||
|
(z_1 x_2 - x_1 z_2)j +
|
||||||
|
(x_1 y_2 - y_1 x_2)k
|
||||||
|
""", tex_to_color_map=self.t2c)
|
||||||
|
equation.set_width(FRAME_WIDTH - 1)
|
||||||
|
equation.to_edge(UP, buff=MED_SMALL_BUFF)
|
||||||
|
|
||||||
|
images = Group()
|
||||||
|
image_labels = VGroup()
|
||||||
|
images_with_labels = Group()
|
||||||
|
names = ["Peter Tait", "Robert Ball", "Macfarlane Alexander"]
|
||||||
|
for name in names:
|
||||||
|
image = ImageMobject(name)
|
||||||
|
image.set_height(3)
|
||||||
|
label = TextMobject(name)
|
||||||
|
label.scale(0.5)
|
||||||
|
label.next_to(image, DOWN)
|
||||||
|
image.label = label
|
||||||
|
image_labels.add(label)
|
||||||
|
images.add(image)
|
||||||
|
images_with_labels.add(Group(image, label))
|
||||||
|
images_with_labels.arrange_submobjects(RIGHT)
|
||||||
|
images_with_labels.next_to(hamilton, LEFT, LARGE_BUFF)
|
||||||
|
images_with_labels.shift(MED_LARGE_BUFF * DOWN)
|
||||||
|
society_title = TextMobject("Quaternion society")
|
||||||
|
society_title.next_to(images, UP, MED_LARGE_BUFF, UP)
|
||||||
|
|
||||||
|
def blink_wait(n_loops):
|
||||||
|
for x in range(n_loops):
|
||||||
|
self.play(Blink(random.choice(students)))
|
||||||
|
self.wait(random.random())
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
FadeInFromDown(hamilton),
|
||||||
|
Write(
|
||||||
|
self.date,
|
||||||
|
rate_func=lambda t: smooth(1 - t),
|
||||||
|
remover=True
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.play(LaggedStart(
|
||||||
|
FadeInFrom, students,
|
||||||
|
lambda m: (m, LEFT),
|
||||||
|
))
|
||||||
|
self.play(
|
||||||
|
LaggedStart(
|
||||||
|
ApplyMethod, students,
|
||||||
|
lambda pi: (
|
||||||
|
pi.change,
|
||||||
|
random.choice(["confused", "maybe", "erm"]),
|
||||||
|
3 * LEFT + 2 * UP,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Write(equation),
|
||||||
|
)
|
||||||
|
blink_wait(3)
|
||||||
|
self.play(
|
||||||
|
LaggedStart(FadeInFromDown, images),
|
||||||
|
LaggedStart(FadeInFromLarge, image_labels),
|
||||||
|
Write(society_title)
|
||||||
|
)
|
||||||
|
blink_wait(3)
|
||||||
|
self.play(
|
||||||
|
FadeOutAndShift(hamilton, RIGHT),
|
||||||
|
LaggedStart(
|
||||||
|
FadeOutAndShift, images_with_labels,
|
||||||
|
lambda m: (m, UP)
|
||||||
|
),
|
||||||
|
FadeOutAndShift(students, DOWN),
|
||||||
|
FadeOut(society_title),
|
||||||
|
run_time=1
|
||||||
|
)
|
||||||
|
|
||||||
|
self.equation = equation
|
||||||
|
|
||||||
def show_anti_quaternion_quote(self):
|
def show_anti_quaternion_quote(self):
|
||||||
pass
|
names_and_quotes = [
|
||||||
|
(
|
||||||
|
"Oliver Heaviside",
|
||||||
|
"""``As far as the vector analysis I required was
|
||||||
|
concerned, the quaternion was not only not
|
||||||
|
required, but was a positive evil of no
|
||||||
|
inconsiderable magnitude.''"""
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Lord Kelvin",
|
||||||
|
"""``Quaternions... though beautifully \\\\ ingenious,
|
||||||
|
have been an unmixed evil to those who have
|
||||||
|
touched them in any way, including Clerk Maxwell.''"""
|
||||||
|
),
|
||||||
|
]
|
||||||
|
images = Group()
|
||||||
|
quotes = VGroup()
|
||||||
|
names = VGroup()
|
||||||
|
images_with_quotes = Group()
|
||||||
|
for name, quote_text in names_and_quotes:
|
||||||
|
image = Group(ImageMobject(name))
|
||||||
|
image.set_height(4)
|
||||||
|
label = TextMobject(name)
|
||||||
|
label.next_to(image, DOWN)
|
||||||
|
names.add(label)
|
||||||
|
quote = TextMobject(
|
||||||
|
"\\huge " + quote_text,
|
||||||
|
tex_to_color_map={
|
||||||
|
"positive evil": RED,
|
||||||
|
"unmixed evil": RED,
|
||||||
|
},
|
||||||
|
alignment=""
|
||||||
|
)
|
||||||
|
quote.scale(0.3)
|
||||||
|
quote.next_to(image, UP)
|
||||||
|
images.add(image)
|
||||||
|
quotes.add(quote)
|
||||||
|
images_with_quotes.add(Group(image, label, quote))
|
||||||
|
|
||||||
|
images_with_quotes.arrange_submobjects(RIGHT, buff=LARGE_BUFF)
|
||||||
|
images_with_quotes.to_edge(DOWN, MED_LARGE_BUFF)
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
LaggedStart(FadeInFromDown, images),
|
||||||
|
LaggedStart(FadeInFromLarge, names),
|
||||||
|
lag_ratio=0.75,
|
||||||
|
run_time=2,
|
||||||
|
)
|
||||||
|
for quote in quotes:
|
||||||
|
self.play(LaggedStart(
|
||||||
|
FadeIn, VGroup(*quote.family_members_with_points()),
|
||||||
|
lag_ratio=0.3
|
||||||
|
))
|
||||||
|
self.wait()
|
||||||
|
self.play(FadeOut(images_with_quotes))
|
||||||
|
|
||||||
def mad_hatter(self):
|
def mad_hatter(self):
|
||||||
pass
|
title = TextMobject(
|
||||||
|
"Lewis Carroll's", "``Alice in wonderland''"
|
||||||
|
)
|
||||||
|
title.to_edge(UP, buff=LARGE_BUFF)
|
||||||
|
author_brace = Brace(title[0], DOWN)
|
||||||
|
aka = TextMobject("a.k.a. Mathematician Charles Dodgson")
|
||||||
|
aka.scale(0.8)
|
||||||
|
aka.set_color(BLUE)
|
||||||
|
aka.next_to(author_brace, DOWN)
|
||||||
|
|
||||||
def vestiges_in_modern_notation(self):
|
quote = TextMobject(
|
||||||
pass
|
"""
|
||||||
|
``Why, you might just as well say that\\\\
|
||||||
|
‘I see what I eat’ is the same thing as\\\\
|
||||||
|
‘I eat what I see’!''
|
||||||
|
""",
|
||||||
|
tex_to_color_map={
|
||||||
|
"I see what I eat": BLUE,
|
||||||
|
"I eat what I see": YELLOW,
|
||||||
|
},
|
||||||
|
alignment=""
|
||||||
|
)
|
||||||
|
quote.to_edge(UP, buff=LARGE_BUFF)
|
||||||
|
|
||||||
|
hatter = PiCreature(color=RED, mode="surprised")
|
||||||
|
hat = SVGMobject(file_name="hat")
|
||||||
|
hat_back = hat.copy()
|
||||||
|
hat_back[0].remove(*[
|
||||||
|
sm for sm in hat_back[0] if sm.is_subpath
|
||||||
|
])
|
||||||
|
hat_back.set_fill(DARK_GREY)
|
||||||
|
hat.add_to_back(hat_back)
|
||||||
|
hat.set_height(1.25)
|
||||||
|
hat.next_to(hatter.body, UP, buff=-MED_SMALL_BUFF)
|
||||||
|
hatter.add(hat)
|
||||||
|
hatter.look(DL)
|
||||||
|
hatter.pupils[1].save_state()
|
||||||
|
hatter.look(UL)
|
||||||
|
hatter.pupils[1].restore()
|
||||||
|
hatter.set_height(2)
|
||||||
|
|
||||||
|
hare = SVGMobject(file_name="bunny")
|
||||||
|
mouse = SVGMobject(file_name="mouse")
|
||||||
|
for mob in hare, mouse:
|
||||||
|
mob.set_color(LIGHT_GREY)
|
||||||
|
mob.set_sheen(0.2, UL)
|
||||||
|
mob.set_height(1.5)
|
||||||
|
|
||||||
|
characters = VGroup(hatter, hare, mouse)
|
||||||
|
for mob, p in zip(characters, [UP, DL, DR]):
|
||||||
|
mob.move_to(p)
|
||||||
|
hare.shift(MED_SMALL_BUFF * LEFT)
|
||||||
|
|
||||||
|
characters.space_out_submobjects(1.5)
|
||||||
|
characters.to_edge(DOWN)
|
||||||
|
|
||||||
|
def change_single_place(char, **kwargs):
|
||||||
|
i = characters.submobjects.index(char)
|
||||||
|
target = characters[(i + 1) % 3]
|
||||||
|
return ApplyMethod(
|
||||||
|
char.move_to, target,
|
||||||
|
path_arc=-90 * DEGREES,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_change_places():
|
||||||
|
return LaggedStart(
|
||||||
|
change_single_place, characters,
|
||||||
|
lag_ratio=0.6
|
||||||
|
)
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
Write(title),
|
||||||
|
LaggedStart(FadeInFromDown, characters)
|
||||||
|
)
|
||||||
|
self.play(
|
||||||
|
get_change_places(),
|
||||||
|
GrowFromCenter(author_brace),
|
||||||
|
FadeIn(aka)
|
||||||
|
)
|
||||||
|
for x in range(4):
|
||||||
|
self.play(get_change_places())
|
||||||
|
self.play(
|
||||||
|
FadeOutAndShift(VGroup(title, author_brace, aka)),
|
||||||
|
FadeInFromDown(quote),
|
||||||
|
)
|
||||||
|
self.play(get_change_places())
|
||||||
|
self.play(
|
||||||
|
get_change_places(),
|
||||||
|
VFadeOut(characters, run_time=2)
|
||||||
|
)
|
||||||
|
self.remove(characters)
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
|
||||||
class QuaternionRotationOverlay(Scene):
|
class QuaternionRotationOverlay(Scene):
|
||||||
|
@ -3199,7 +3494,6 @@ class TwoDStereographicProjection(IntroduceFelix):
|
||||||
|
|
||||||
def get_sphere_dot(sphere_point):
|
def get_sphere_dot(sphere_point):
|
||||||
dot = Dot()
|
dot = Dot()
|
||||||
dot.rotate(90 * DEGREES)
|
|
||||||
dot.set_shade_in_3d(True)
|
dot.set_shade_in_3d(True)
|
||||||
dot.set_fill(PINK)
|
dot.set_fill(PINK)
|
||||||
dot.shift(OUT)
|
dot.shift(OUT)
|
||||||
|
@ -4722,19 +5016,23 @@ class HypersphereStereographicProjection(SpecialThreeDScene):
|
||||||
return self.q_tracker.get_value()
|
return self.q_tracker.get_value()
|
||||||
|
|
||||||
def specially_color_sphere(self, sphere):
|
def specially_color_sphere(self, sphere):
|
||||||
for submob in sphere:
|
sphere.set_color_by_gradient(BLUE, GREEN, PINK)
|
||||||
u, v = submob.u1, submob.v1
|
|
||||||
x = np.cos(v) * np.sin(u)
|
|
||||||
y = np.sin(v) * np.sin(u)
|
|
||||||
z = np.cos(u)
|
|
||||||
rgb = sum([
|
|
||||||
(x**2) * hex_to_rgb(GREEN),
|
|
||||||
(y**2) * hex_to_rgb(RED),
|
|
||||||
(z**2) * hex_to_rgb(BLUE),
|
|
||||||
])
|
|
||||||
clip_in_place(rgb, 0, 1)
|
|
||||||
submob.set_fill(rgb_to_hex(rgb))
|
|
||||||
return sphere
|
return sphere
|
||||||
|
# for submob in sphere:
|
||||||
|
# u, v = submob.u1, submob.v1
|
||||||
|
# x = np.cos(v) * np.sin(u)
|
||||||
|
# y = np.sin(v) * np.sin(u)
|
||||||
|
# z = np.cos(u)
|
||||||
|
# # rgb = sum([
|
||||||
|
# # (x**2) * hex_to_rgb(GREEN),
|
||||||
|
# # (y**2) * hex_to_rgb(RED),
|
||||||
|
# # (z**2) * hex_to_rgb(BLUE),
|
||||||
|
# # ])
|
||||||
|
# # clip_in_place(rgb, 0, 1)
|
||||||
|
# # color = rgb_to_hex(rgb)
|
||||||
|
# color = interpolate_color(BLUE, RED, ((z**3) + 1) / 2)
|
||||||
|
# submob.set_fill(color)
|
||||||
|
# return sphere
|
||||||
|
|
||||||
|
|
||||||
class RuleOfQuaternionMultiplicationOverlay(Scene):
|
class RuleOfQuaternionMultiplicationOverlay(Scene):
|
||||||
|
@ -5179,7 +5477,7 @@ class ShowMultiplicationBy135Example(RuleOfQuaternionMultiplication):
|
||||||
solid=False,
|
solid=False,
|
||||||
stroke_width=0.5,
|
stroke_width=0.5,
|
||||||
stroke_opacity=0.2,
|
stroke_opacity=0.2,
|
||||||
fill_opacity=0.1,
|
fill_opacity=0.2,
|
||||||
)
|
)
|
||||||
self.specially_color_sphere(result)
|
self.specially_color_sphere(result)
|
||||||
return result
|
return result
|
||||||
|
|
Loading…
Add table
Reference in a new issue