mirror of
https://github.com/3b1b/manim.git
synced 2025-09-01 00:48:45 +00:00
Final tweaks to quaternion animations...I hope
This commit is contained in:
parent
a1e21a4606
commit
b18537b1bb
1 changed files with 419 additions and 31 deletions
|
@ -97,6 +97,12 @@ def stereo_project(mobject, axis=0, r=1, outer_r=10, **kwargs):
|
|||
return mobject
|
||||
|
||||
|
||||
def updating_mobject_from_func(func):
|
||||
mob = func()
|
||||
mob.add_updater(lambda m: mob.become(func()))
|
||||
return mob
|
||||
|
||||
|
||||
class Linus(VGroup):
|
||||
CONFIG = {
|
||||
"body_config": {
|
||||
|
@ -288,6 +294,7 @@ class StereoProjectedSphereFromHypersphere(StereoProjectedSphere):
|
|||
"axis": 0,
|
||||
},
|
||||
"radius": 2,
|
||||
"multiply_from_right": False,
|
||||
}
|
||||
|
||||
def __init__(self, quaternion=None, null_axis=0, **kwargs):
|
||||
|
@ -301,7 +308,10 @@ class StereoProjectedSphereFromHypersphere(StereoProjectedSphere):
|
|||
def q_mult_projection_func(self, u, v):
|
||||
point = list(Sphere.func(self, u, v))
|
||||
point.insert(self.null_axis, 0)
|
||||
post_q_mult = q_mult(self.quaternion, point)
|
||||
if self.multiply_from_right:
|
||||
post_q_mult = q_mult(point, self.quaternion)
|
||||
else:
|
||||
post_q_mult = q_mult(self.quaternion, point)
|
||||
projected = list(self.radius * stereo_project_point(
|
||||
post_q_mult, **self.stereo_project_config
|
||||
))
|
||||
|
@ -316,12 +326,13 @@ class StereoProjectedCircleFromHypersphere(CheckeredCircle):
|
|||
CONFIG = {
|
||||
"n_pieces": 48,
|
||||
"radius": 2,
|
||||
"max_length": 2 * FRAME_WIDTH,
|
||||
"max_r": 20,
|
||||
"max_length": 3 * FRAME_WIDTH,
|
||||
"max_r": 50,
|
||||
"basis_vectors": [
|
||||
[1, 0, 0, 0],
|
||||
[0, 1, 0, 0],
|
||||
]
|
||||
],
|
||||
"multiply_from_right": False,
|
||||
}
|
||||
|
||||
def __init__(self, quaternion=None, **kwargs):
|
||||
|
@ -344,7 +355,10 @@ class StereoProjectedCircleFromHypersphere(CheckeredCircle):
|
|||
def projection(self, point):
|
||||
q1 = self.quaternion
|
||||
q2 = np.dot(self.pre_positioning_matrix, point[:2]).flatten()
|
||||
new_q = q_mult(q1, q2)
|
||||
if self.multiply_from_right:
|
||||
new_q = q_mult(q2, q1)
|
||||
else:
|
||||
new_q = q_mult(q1, q2)
|
||||
projected = stereo_project_point(
|
||||
new_q, axis=0, r=self.radius,
|
||||
)
|
||||
|
@ -1118,6 +1132,74 @@ class RotateCubeThreeTimes(SpecialThreeDScene):
|
|||
self.wait(7)
|
||||
|
||||
|
||||
class QuantumSpin(Scene):
|
||||
def construct(self):
|
||||
title = Title("Two-state system")
|
||||
|
||||
electron = Dot(color=BLUE)
|
||||
electron.set_height(1)
|
||||
electron.set_sheen(0.3, UL)
|
||||
electron.set_fill(opacity=0.8)
|
||||
kwargs = {
|
||||
"use_rectangular_stem": False,
|
||||
"path_arc": PI,
|
||||
}
|
||||
curved_arrows = VGroup(
|
||||
Arrow(RIGHT, LEFT, **kwargs),
|
||||
Arrow(LEFT, RIGHT, **kwargs),
|
||||
)
|
||||
curved_arrows.set_color(LIGHT_GREY)
|
||||
curved_arrows.set_stroke(width=2)
|
||||
|
||||
y_arrow = Vector(UP)
|
||||
y_arrow.set_color(RED)
|
||||
|
||||
y_ca = curved_arrows.copy()
|
||||
y_ca.rotate(70 * DEGREES, LEFT)
|
||||
y_group = VGroup(y_ca[0], y_arrow, electron.copy(), y_ca[1])
|
||||
|
||||
x_arrow = y_arrow.copy().rotate(90 * DEGREES, IN, about_point=ORIGIN)
|
||||
x_arrow.set_color(GREEN)
|
||||
x_ca = curved_arrows.copy()
|
||||
x_ca.rotate(70 * DEGREES, UP)
|
||||
x_group = VGroup(x_ca[0], x_arrow, electron.copy(), x_ca[1])
|
||||
|
||||
z_ca = curved_arrows.copy()
|
||||
z_group = VGroup(electron.copy(), z_ca, Dot(color=BLUE))
|
||||
|
||||
groups = VGroup(x_group, y_group, z_group)
|
||||
groups.arrange_submobjects(RIGHT, buff=1.5)
|
||||
groups.move_to(UP)
|
||||
|
||||
y_ca.rotation = Rotating(
|
||||
y_ca, axis=rotate_vector(OUT, 70 * DEGREES, LEFT)
|
||||
)
|
||||
x_ca.rotation = Rotating(
|
||||
x_ca, axis=rotate_vector(OUT, 70 * DEGREES, UP)
|
||||
)
|
||||
z_ca.rotation = Rotating(z_ca, axis=OUT)
|
||||
rotations = [ca.rotation for ca in [x_ca, y_ca, z_ca]]
|
||||
|
||||
matrices = VGroup(
|
||||
Matrix([["0", "1"], ["1", "0"]]),
|
||||
Matrix([["0", "-i"], ["i", "0"]]),
|
||||
Matrix([["1", "0"], ["0", "-1"]]),
|
||||
)
|
||||
for matrix, group in zip(matrices, groups):
|
||||
matrix.next_to(group, DOWN)
|
||||
for matrix in matrices[1:]:
|
||||
matrix.align_to(matrices[0], DOWN)
|
||||
|
||||
self.add(title, groups)
|
||||
self.play()
|
||||
self.play(
|
||||
LaggedStart(FadeInFromDown, matrices, run_time=3),
|
||||
*rotations
|
||||
)
|
||||
for x in range(2):
|
||||
self.play(*rotations)
|
||||
|
||||
|
||||
class HereWeTackle4d(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
titles = VGroup(
|
||||
|
@ -2252,6 +2334,7 @@ class OneDegreeOfFreedomForRotation(Scene):
|
|||
right_dot = Dot(color=WHITE)
|
||||
right_dot.move_to(circle.get_right())
|
||||
circle.add(moving_r_line, right_dot)
|
||||
center_dot = Dot(color=WHITE)
|
||||
|
||||
def get_angle():
|
||||
return moving_r_line.get_angle() % TAU
|
||||
|
@ -2275,7 +2358,7 @@ class OneDegreeOfFreedomForRotation(Scene):
|
|||
arc = get_arc()
|
||||
arc.add_updater(lambda m: m.become(get_arc()))
|
||||
|
||||
self.add(circle, r_line, angle_label, arc)
|
||||
self.add(circle, center_dot, r_line, angle_label, arc)
|
||||
angles = IntroduceStereographicProjection.CONFIG.get(
|
||||
"example_angles"
|
||||
)
|
||||
|
@ -2572,8 +2655,13 @@ class IntroduceStereographicProjection(MovingCameraScene):
|
|||
def get_sample_circle_points(self):
|
||||
plane = self.plane
|
||||
n = self.n_sample_points
|
||||
rotater = 1
|
||||
if hasattr(self, "circle_shadow"):
|
||||
point = self.circle_shadow[0].points[0]
|
||||
rotater = complex(*point[:2])
|
||||
rotater /= abs(rotater)
|
||||
numbers = [
|
||||
np.exp(complex(0, TAU * x / n))
|
||||
rotater * np.exp(complex(0, TAU * x / n))
|
||||
for x in range(-(n // 2) + 1, n // 2)
|
||||
]
|
||||
return [
|
||||
|
@ -2591,11 +2679,9 @@ class IntroduceStereographicProjection(MovingCameraScene):
|
|||
for point in circle_points
|
||||
])
|
||||
for line in lines:
|
||||
line.scale(
|
||||
20 / line.get_length(),
|
||||
about_point=neg_one_point
|
||||
)
|
||||
line.set_stroke(YELLOW, 1)
|
||||
length = line.get_length()
|
||||
line.scale(20 / length, about_point=neg_one_point)
|
||||
line.set_stroke(YELLOW, np.clip(length, 0, 1))
|
||||
return lines
|
||||
|
||||
def project(self, point):
|
||||
|
@ -2835,7 +2921,7 @@ class ShowRotationUnderStereographicProjection(IntroduceStereographicProjection)
|
|||
neg_one_dot = Dot(neg_one_point)
|
||||
neg_one_dot.set_fill(YELLOW)
|
||||
|
||||
lines = self.get_lines()
|
||||
lines = updating_mobject_from_func(self.get_lines)
|
||||
|
||||
def generate_dot_updater(circle_piece):
|
||||
return lambda d: d.move_to(circle_piece.points[0])
|
||||
|
@ -3146,13 +3232,23 @@ class IntroduceThreeDNumbers(SpecialThreeDScene):
|
|||
|
||||
plane = self.plane
|
||||
|
||||
x_line = Line(LEFT, RIGHT).set_width(FRAME_WIDTH)
|
||||
colored_ = Line(LEFT, RIGHT).set_width(FRAME_WIDTH)
|
||||
y_line = Line(DOWN, UP).set_height(FRAME_WIDTH)
|
||||
z_line = Line(IN, OUT).set_depth(FRAME_WIDTH)
|
||||
x_line.set_stroke(GREEN, 5)
|
||||
colored_.set_stroke(GREEN, 5)
|
||||
y_line.set_stroke(RED, 5)
|
||||
z_line.set_stroke(YELLOW, 5)
|
||||
coord_lines = VGroup(x_line, y_line, z_line)
|
||||
colored_coord_lines = VGroup(colored_, y_line, z_line)
|
||||
|
||||
coord_lines = VGroup(
|
||||
plane.axes[0], plane.axes[1], z_axis.main_line,
|
||||
)
|
||||
for i1, i2 in [(0, 2), (1, 0), (2, 1)]:
|
||||
coord_lines[i1].target = coord_lines[i2].copy()
|
||||
|
||||
new_title = TextMobject("Imaginary plane")
|
||||
new_title.replace(self.title)
|
||||
new_title.move_to(self.title)
|
||||
|
||||
self.add(z_axis, plane, z_axis_top)
|
||||
self.move_camera(
|
||||
|
@ -3184,13 +3280,17 @@ class IntroduceThreeDNumbers(SpecialThreeDScene):
|
|||
label.target.next_to(
|
||||
2 * y * UP, RIGHT, 2 * SMALL_BUFF
|
||||
)
|
||||
self.remove(z_axis_top)
|
||||
self.play(
|
||||
LaggedStart(MoveToTarget, group, lag_ratio=0.8),
|
||||
LaggedStart(MoveToTarget, coord_lines, lag_ratio=0.8),
|
||||
FadeOut(self.title),
|
||||
FadeIn(new_title),
|
||||
run_time=3
|
||||
)
|
||||
self.add(z_axis_top)
|
||||
self.wait(3)
|
||||
for line, wait in zip(coord_lines, [False, True, True]):
|
||||
for line, wait in zip(colored_coord_lines, [False, True, True]):
|
||||
self.play(
|
||||
ShowCreationThenDestruction(line),
|
||||
run_time=2
|
||||
|
@ -3264,7 +3364,7 @@ class MentionImpossibilityOf3dNumbers(TeacherStudentsScene):
|
|||
why.next_to(self.students[1], UP)
|
||||
|
||||
self.teacher_says(
|
||||
"Such 3d number \\\\ have no good \\\\ multiplication rule",
|
||||
"Such 3d numbers \\\\ have no good \\\\ multiplication rule",
|
||||
bubble_kwargs={"width": 4, "height": 3},
|
||||
)
|
||||
self.change_all_student_modes("confused")
|
||||
|
@ -3360,6 +3460,7 @@ class TwoDStereographicProjection(IntroduceFelix):
|
|||
0, TAU, TAU / 16,
|
||||
),
|
||||
"n_sample_rotation_cycles": 2,
|
||||
"lift_labels": True,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
|
@ -3376,7 +3477,7 @@ class TwoDStereographicProjection(IntroduceFelix):
|
|||
sphere = self.sphere = self.get_sphere()
|
||||
|
||||
c2p = axes.coords_to_point
|
||||
labels = VGroup(
|
||||
labels = self.labels = VGroup(
|
||||
TexMobject("i").next_to(c2p(1, 0, 0), DR, SMALL_BUFF),
|
||||
TexMobject("-i").next_to(c2p(-1, 0, 0), DL, SMALL_BUFF),
|
||||
TexMobject("j").next_to(c2p(0, 1, 0), UL, SMALL_BUFF),
|
||||
|
@ -3388,10 +3489,11 @@ class TwoDStereographicProjection(IntroduceFelix):
|
|||
90 * DEGREES, RIGHT,
|
||||
).next_to(c2p(0, 0, -1), RIGHT + IN, SMALL_BUFF),
|
||||
)
|
||||
for sm in labels[:4].family_members_with_points():
|
||||
sm.add(VectorizedPoint(
|
||||
0.25 * DOWN + 0.25 * OUT
|
||||
))
|
||||
if self.lift_labels:
|
||||
for sm in labels[:4].family_members_with_points():
|
||||
sm.add(VectorizedPoint(
|
||||
0.25 * DOWN + 0.25 * OUT
|
||||
))
|
||||
labels.set_stroke(width=0, background=True)
|
||||
for submob in labels.get_family():
|
||||
submob.shade_in_3d = True
|
||||
|
@ -3811,9 +3913,10 @@ class FelixViewOfProjection(TwoDStereographicProjection):
|
|||
TexMobject("-i"),
|
||||
TexMobject("j"),
|
||||
TexMobject("-j"),
|
||||
TexMobject("1"),
|
||||
)
|
||||
coords = [(1, 0), (-1, 0), (0, 1), (0, -1)]
|
||||
vects = [DOWN, DOWN, RIGHT, RIGHT]
|
||||
coords = [(1, 0), (-1, 0), (0, 1), (0, -1), (0, 0)]
|
||||
vects = [DOWN, DOWN, RIGHT, RIGHT, 0.25 * DR]
|
||||
for label, coords, vect in zip(labels, coords, vects):
|
||||
point = axes.coords_to_point(*coords)
|
||||
label.next_to(point, vect, buff=MED_SMALL_BUFF)
|
||||
|
@ -3890,6 +3993,10 @@ class FelixViewOfProjection(TwoDStereographicProjection):
|
|||
|
||||
|
||||
class ShowRotationsJustWithReferenceCircles(TwoDStereographicProjection):
|
||||
CONFIG = {
|
||||
"flat_view": False,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.add_parts(run_time=1)
|
||||
self.begin_ambient_camera_rotation(rate=0.03)
|
||||
|
@ -3925,6 +4032,8 @@ class ShowRotationsJustWithReferenceCircles(TwoDStereographicProjection):
|
|||
|
||||
labels = VGroup(*map(TexMobject, ["0", "2i", "3i"]))
|
||||
labels.set_shade_in_3d(True)
|
||||
if self.flat_view:
|
||||
labels.fade(1)
|
||||
for label, x in zip(labels, [0, 2, 3]):
|
||||
label.next_to(
|
||||
axes.coords_to_point(x, 0, 0), DR, SMALL_BUFF
|
||||
|
@ -4086,6 +4195,8 @@ class ShowRotationsJustWithReferenceCircles(TwoDStereographicProjection):
|
|||
circle = CheckeredCircle(colors=colors, n_pieces=48)
|
||||
circle.set_shade_in_3d(True)
|
||||
circle.match_width(sphere)
|
||||
if self.flat_view:
|
||||
circle[::2].fade(1)
|
||||
|
||||
return circle
|
||||
|
||||
|
@ -4101,6 +4212,40 @@ class ShowRotationsJustWithReferenceCircles(TwoDStereographicProjection):
|
|||
return result
|
||||
|
||||
|
||||
class ReferernceSpheresFelixView(ShowRotationsJustWithReferenceCircles):
|
||||
CONFIG = {
|
||||
"flat_view": True,
|
||||
"lift_labels": False,
|
||||
}
|
||||
|
||||
def add_parts(self, **kwargs):
|
||||
ShowRotationsJustWithReferenceCircles.add_parts(self, **kwargs)
|
||||
one = TexMobject("1")
|
||||
one.next_to(ORIGIN, DR, SMALL_BUFF)
|
||||
self.add(one)
|
||||
|
||||
def get_default_camera_position(self):
|
||||
return {}
|
||||
|
||||
def move_camera(self, **kwargs):
|
||||
kwargs["phi"] = 0
|
||||
kwargs["theta"] = -90 * DEGREES
|
||||
ShowRotationsJustWithReferenceCircles.move_camera(self, **kwargs)
|
||||
|
||||
def begin_ambient_camera_rotation(self, rate):
|
||||
self.ambient_camera_rotation = ContinualAnimation(VectorizedPoint())
|
||||
|
||||
def capture_mobjects_in_camera(self, mobjects, **kwargs):
|
||||
mobs_on_xy = [
|
||||
sm
|
||||
for sm in self.camera.extract_mobject_family_members(
|
||||
mobjects, only_those_with_points=True
|
||||
)
|
||||
if abs(sm.get_center()[2]) < 0.001
|
||||
]
|
||||
return Scene.capture_mobjects_in_camera(self, mobs_on_xy, **kwargs)
|
||||
|
||||
|
||||
class IntroduceQuaternions(Scene):
|
||||
def construct(self):
|
||||
self.compare_three_number_systems()
|
||||
|
@ -4786,12 +4931,29 @@ class HypersphereStereographicProjection(SpecialThreeDScene):
|
|||
|
||||
def show_quaternions_with_nonzero_real_part(self):
|
||||
# Positive real part
|
||||
self.set_quat([1, 1, 2, 0])
|
||||
self.set_quat(
|
||||
[1, 1, 2, 0],
|
||||
added_anims=[
|
||||
ApplyMethod(
|
||||
self.sphere.copy().scale, 0,
|
||||
remover=True
|
||||
)
|
||||
]
|
||||
)
|
||||
self.wait(2)
|
||||
self.set_quat([4, 0, -1, -1])
|
||||
self.wait(2)
|
||||
# Negative real part
|
||||
self.set_quat([-1, 1, 2, 0])
|
||||
self.set_quat(
|
||||
[-1, 1, 2, 0],
|
||||
added_anims=[
|
||||
ApplyFunction(
|
||||
lambda s: s.scale(10).fade(1),
|
||||
self.sphere.copy(),
|
||||
remover=True
|
||||
)
|
||||
]
|
||||
)
|
||||
self.wait(2)
|
||||
self.set_quat([-2, 0, -1, 1])
|
||||
self.wait(2)
|
||||
|
@ -5035,6 +5197,18 @@ class HypersphereStereographicProjection(SpecialThreeDScene):
|
|||
# return sphere
|
||||
|
||||
|
||||
class MissingLabels(Scene):
|
||||
def construct(self):
|
||||
labels = VGroup(
|
||||
TexMobject("i").move_to(UR),
|
||||
TexMobject("1").move_to(0.3 * DOWN),
|
||||
TexMobject("-i").move_to(DOWN + 1.2 * LEFT),
|
||||
TexMobject("-j").move_to(1.7 * RIGHT + 0.8 * DOWN),
|
||||
)
|
||||
labels.set_background_stroke(width=0)
|
||||
self.add(labels)
|
||||
|
||||
|
||||
class RuleOfQuaternionMultiplicationOverlay(Scene):
|
||||
def construct(self):
|
||||
q_mob, times_mob, p_mob = q_times_p = TexMobject(
|
||||
|
@ -5664,18 +5838,18 @@ class ShowJMultiplication(ShowMultiplicationBy135Example):
|
|||
circle = self.circle_ik.deepcopy()
|
||||
circle.clear_updaters()
|
||||
self.play(FadeInFromLarge(circle, remover=True))
|
||||
m_tracker.set_value([1, 0, 0, 0])
|
||||
m_tracker.set_value([-1, 0, 0, 0])
|
||||
q_tracker.set_value([0, 1, 0, 0])
|
||||
self.wait()
|
||||
self.play(
|
||||
m_tracker.set_value, [0, 0, 1, 0],
|
||||
m_tracker.set_value, [0, 0, -1, 0],
|
||||
q_tracker.set_value, [0, 0, 0, -1],
|
||||
*updates,
|
||||
run_time=run_time,
|
||||
)
|
||||
self.wait(2)
|
||||
self.play(
|
||||
m_tracker.set_value, [-1, 0, 1e-3, 0],
|
||||
m_tracker.set_value, [1, 0, -1e-3, 0],
|
||||
q_tracker.set_value, [0, -1, 0, 0],
|
||||
*updates,
|
||||
run_time=run_time,
|
||||
|
@ -5913,6 +6087,220 @@ class RotationsOfCube(SpecialThreeDScene):
|
|||
self.wait(5)
|
||||
|
||||
|
||||
class OneFinalPoint(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.teacher_says("One final point!")
|
||||
self.change_student_modes("happy", "tease", "thinking")
|
||||
self.wait(3)
|
||||
|
||||
|
||||
class MultiplicationFromTheRight(Scene):
|
||||
def construct(self):
|
||||
i, dot, j = product = TexMobject("i", "\\cdot", "j")
|
||||
product.set_height(1.5)
|
||||
product.to_edge(UP, buff=LARGE_BUFF)
|
||||
i.set_color(GREEN)
|
||||
j.set_color(RED)
|
||||
i_rect = SurroundingRectangle(i)
|
||||
j_rect = SurroundingRectangle(j)
|
||||
i_rect.match_height(j_rect, about_edge=UP, stretch=True)
|
||||
VGroup(i_rect, j_rect).set_color(WHITE)
|
||||
action_words = TextMobject("Think of as \\\\ an action")
|
||||
point_words = TextMobject("Think of as \\\\ a point")
|
||||
action_words.next_to(i_rect, LEFT)
|
||||
point_words.next_to(j_rect, RIGHT)
|
||||
|
||||
arrow = Arrow(
|
||||
i.get_top(),
|
||||
j.get_top(),
|
||||
path_arc=-PI,
|
||||
use_rectangular_stem=False,
|
||||
)
|
||||
arrow.set_stroke(width=2)
|
||||
|
||||
self.add(product)
|
||||
self.play(ShowCreation(arrow))
|
||||
self.play(
|
||||
FadeIn(i_rect),
|
||||
Write(action_words)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeIn(j_rect),
|
||||
Write(point_words)
|
||||
)
|
||||
self.wait(2)
|
||||
self.play(arrow.flip)
|
||||
self.play(Swap(point_words, action_words))
|
||||
|
||||
|
||||
class MultiplicationByJFromRight(ShowJMultiplication):
|
||||
def show_multiplication(self):
|
||||
self.set_camera_orientation(theta=-80 * DEGREES)
|
||||
|
||||
q_tracker = self.q_tracker
|
||||
m_tracker = self.multiplier_tracker
|
||||
|
||||
def normalize_tracker(t):
|
||||
t.set_value(normalize(t.get_value()))
|
||||
|
||||
updates = [
|
||||
UpdateFromFunc(tracker, normalize_tracker)
|
||||
for tracker in (q_tracker, m_tracker)
|
||||
]
|
||||
|
||||
run_time = self.run_time_per_rotation
|
||||
|
||||
m_values = [[1, 0, 0, 0]]
|
||||
q_values = [[0, 1, 0, 0]]
|
||||
for values in m_values, q_values:
|
||||
for x in range(4):
|
||||
values.append(
|
||||
q_mult(values[-1], [0, 0, 1, 0])
|
||||
)
|
||||
|
||||
for m_val, q_val in zip(m_values, q_values):
|
||||
self.play(
|
||||
m_tracker.set_value, m_val,
|
||||
q_tracker.set_value, q_val,
|
||||
*updates,
|
||||
run_time=run_time,
|
||||
)
|
||||
self.wait(2)
|
||||
|
||||
def get_projected_sphere(self, *args, **kwargs):
|
||||
kwargs["multiply_from_right"] = True
|
||||
return ShowJMultiplication.get_projected_sphere(
|
||||
self, *args, **kwargs
|
||||
)
|
||||
|
||||
def get_projected_circle(self, *args, **kwargs):
|
||||
kwargs["multiply_from_right"] = True
|
||||
return ShowJMultiplication.get_projected_circle(
|
||||
self, *args, **kwargs
|
||||
)
|
||||
|
||||
|
||||
class HowQuaternionsRotate3dPoints(Scene):
|
||||
def construct(self):
|
||||
title = TextMobject(
|
||||
"Coming up:\\\\",
|
||||
"How quaternions act on 3d points"
|
||||
)
|
||||
title.to_edge(UP)
|
||||
|
||||
expression = TexMobject(
|
||||
"q", "\\cdot", "p", "\\cdot", "q^{-1}"
|
||||
)
|
||||
expression.scale(2)
|
||||
expression.set_color_by_tex("q", PINK)
|
||||
expression.set_color_by_tex("p", YELLOW)
|
||||
|
||||
right_arrow = Arrow(
|
||||
expression[0].get_top(),
|
||||
expression[2].get_top(),
|
||||
path_arc=-PI,
|
||||
use_rectangular_stem=False,
|
||||
color=WHITE,
|
||||
)
|
||||
right_arrow.set_stroke(width=4)
|
||||
left_arrow = right_arrow.copy()
|
||||
left_arrow.flip(about_point=expression[2].get_top())
|
||||
left_arrow.shift(SMALL_BUFF * RIGHT)
|
||||
|
||||
self.add(title)
|
||||
self.play(Write(expression))
|
||||
self.play(ShowCreation(right_arrow))
|
||||
self.play(ShowCreation(left_arrow))
|
||||
self.wait()
|
||||
|
||||
|
||||
class HoldUpQuanta(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
logo = ImageMobject("Quanta logo")
|
||||
logo.set_width(6)
|
||||
logo.next_to(self.teacher, UR)
|
||||
logo.to_edge(RIGHT, buff=2)
|
||||
|
||||
words = TextMobject("Associated quaternion post")
|
||||
words.to_edge(UP, buff=LARGE_BUFF)
|
||||
arrow = Arrow(logo.get_top(), words.get_bottom())
|
||||
|
||||
self.play(
|
||||
FadeInFromDown(logo),
|
||||
self.teacher.change, "raise_right_hand"
|
||||
)
|
||||
self.change_all_student_modes("hooray")
|
||||
self.play(
|
||||
GrowArrow(arrow),
|
||||
GrowFromPoint(words, arrow.get_start())
|
||||
)
|
||||
self.wait(3)
|
||||
|
||||
|
||||
class ShareWithFriends(PiCreatureScene):
|
||||
def construct(self):
|
||||
pi1, pi2 = self.pi_creatures
|
||||
|
||||
self.pi_creature_says(
|
||||
pi1, "Come learn about \\\\ quaternions!",
|
||||
bubble_kwargs={
|
||||
"direction": LEFT,
|
||||
"width": 4,
|
||||
"height": 3,
|
||||
},
|
||||
target_mode="hooray",
|
||||
look_at_arg=pi2.eyes,
|
||||
added_anims=[
|
||||
ApplyMethod(
|
||||
pi2.change, "confused",
|
||||
run_time=1.5,
|
||||
rate_func=squish_rate_func(smooth, 0.3, 1)
|
||||
)
|
||||
]
|
||||
)
|
||||
bubble = ThoughtBubble(
|
||||
direction=RIGHT,
|
||||
width=4,
|
||||
height=4,
|
||||
)
|
||||
bubble.pin_to(pi2)
|
||||
bubble.write("What's that, some\\\\kind of particle?")
|
||||
bubble.resize_to_content()
|
||||
VGroup(bubble, bubble.content).shift_onto_screen(buff=SMALL_BUFF)
|
||||
self.play(
|
||||
pi2.look_at, pi1.eyes,
|
||||
pi1.look_at, pi2.eyes,
|
||||
ShowCreation(bubble),
|
||||
Write(bubble.content),
|
||||
)
|
||||
self.wait(1)
|
||||
self.play(
|
||||
RemovePiCreatureBubble(pi1, target_mode="raise_right_hand")
|
||||
)
|
||||
self.wait()
|
||||
|
||||
time_words = TextMobject("Oh man...\\\\30 minutes")
|
||||
time_words.move_to(bubble.content)
|
||||
self.play(
|
||||
Animation(VectorizedPoint().next_to(pi1, UL, LARGE_BUFF)),
|
||||
pi2.change, "sad",
|
||||
FadeOutAndShift(bubble.content, DOWN),
|
||||
FadeInFromDown(time_words, DOWN),
|
||||
)
|
||||
self.wait(7)
|
||||
|
||||
def create_pi_creatures(self):
|
||||
pi1 = PiCreature(color=BLUE)
|
||||
pi1.to_edge(DOWN)
|
||||
pi1.flip()
|
||||
pi1.shift(2.5 * RIGHT)
|
||||
pi2 = PiCreature(color=RED)
|
||||
pi2.to_edge(DOWN)
|
||||
pi2.shift(2 * LEFT)
|
||||
return [pi1, pi2]
|
||||
|
||||
|
||||
class QuaternionEndscreen(PatreonEndScreen):
|
||||
CONFIG = {
|
||||
"specific_patrons": [
|
||||
|
@ -6000,7 +6388,7 @@ class QuaternionEndscreen(PatreonEndScreen):
|
|||
"Dave B",
|
||||
"Delton Ding",
|
||||
"Thomas Tarler",
|
||||
"1st",
|
||||
"1stViewMaths",
|
||||
"Jacob Magnuson",
|
||||
"Clark Gaebel",
|
||||
"Mathias Jansson",
|
||||
|
|
Loading…
Add table
Reference in a new issue