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,
|
||||
},
|
||||
"sphere_config": {
|
||||
# "resolution": (4, 12),
|
||||
"resolution": (12, 24),
|
||||
}
|
||||
}
|
||||
if high_quality:
|
||||
|
@ -396,8 +396,12 @@ class QuaternionTracker(ValueTracker):
|
|||
class RubiksCube(VGroup):
|
||||
CONFIG = {
|
||||
"colors": [
|
||||
"#C41E3A", "#009E60", "#0051BA",
|
||||
"#FF5800", "#FFD500", "#FFFFFF"
|
||||
"#FFD500", # Yellow
|
||||
"#C41E3A", # Orange
|
||||
"#009E60", # Green
|
||||
"#FF5800", # Red
|
||||
"#0051BA", # Blue
|
||||
"#FFFFFF" # White
|
||||
],
|
||||
}
|
||||
|
||||
|
@ -711,37 +715,328 @@ class IntroduceHamilton(Scene):
|
|||
|
||||
class QuaternionHistory(Scene):
|
||||
def construct(self):
|
||||
self.show_dot_product_and_cross_product() # With date
|
||||
self.show_dot_product_and_cross_product()
|
||||
self.teaching_students_quaternions()
|
||||
self.show_anti_quaternion_quote()
|
||||
self.mad_hatter()
|
||||
self.vestiges_in_modern_notation()
|
||||
|
||||
|
||||
def show_dot_product_and_cross_product(self):
|
||||
date = TexMobject("1843")
|
||||
date.scale(2)
|
||||
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 = [
|
||||
Matrix([
|
||||
["{}_{}".format(c, i)]
|
||||
for c in "xyz"
|
||||
])
|
||||
], element_to_mobject=get_colored_tex_mobject)
|
||||
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):
|
||||
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):
|
||||
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):
|
||||
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):
|
||||
pass
|
||||
quote = TextMobject(
|
||||
"""
|
||||
``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):
|
||||
|
@ -3199,7 +3494,6 @@ class TwoDStereographicProjection(IntroduceFelix):
|
|||
|
||||
def get_sphere_dot(sphere_point):
|
||||
dot = Dot()
|
||||
dot.rotate(90 * DEGREES)
|
||||
dot.set_shade_in_3d(True)
|
||||
dot.set_fill(PINK)
|
||||
dot.shift(OUT)
|
||||
|
@ -4722,19 +5016,23 @@ class HypersphereStereographicProjection(SpecialThreeDScene):
|
|||
return self.q_tracker.get_value()
|
||||
|
||||
def specially_color_sphere(self, 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)
|
||||
submob.set_fill(rgb_to_hex(rgb))
|
||||
sphere.set_color_by_gradient(BLUE, GREEN, PINK)
|
||||
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):
|
||||
|
@ -5179,7 +5477,7 @@ class ShowMultiplicationBy135Example(RuleOfQuaternionMultiplication):
|
|||
solid=False,
|
||||
stroke_width=0.5,
|
||||
stroke_opacity=0.2,
|
||||
fill_opacity=0.1,
|
||||
fill_opacity=0.2,
|
||||
)
|
||||
self.specially_color_sphere(result)
|
||||
return result
|
||||
|
|
Loading…
Add table
Reference in a new issue