mirror of
https://github.com/3b1b/manim.git
synced 2025-09-19 04:41:56 +00:00
Preliminary finish to quat3d preamble
This commit is contained in:
parent
e8349f8d0d
commit
9cf4dfac3d
3 changed files with 596 additions and 20 deletions
|
@ -193,22 +193,16 @@ class Introduction(QuaternionHistory):
|
|||
Write(title_equation)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
LaggedStart(
|
||||
FadeInFrom, images,
|
||||
lambda m: (m, 3 * DOWN),
|
||||
lag_ratio=0.75
|
||||
),
|
||||
LaggedStart(FadeInFromLarge, names, lag_ratio=0.75),
|
||||
*[
|
||||
for image, name, quote in zip(images, names, quotes):
|
||||
self.play(
|
||||
FadeInFrom(image, 3 * DOWN),
|
||||
FadeInFromLarge(name),
|
||||
LaggedStart(
|
||||
FadeIn, VGroup(*it.chain(*quote)),
|
||||
lag_ratio=0.3,
|
||||
run_time=3
|
||||
run_time=2
|
||||
)
|
||||
for quote in quotes
|
||||
],
|
||||
)
|
||||
)
|
||||
self.wait(2)
|
||||
self.play(
|
||||
title.shift, 2 * UP,
|
||||
|
@ -251,6 +245,7 @@ class WhoCares(TeacherStudentsScene):
|
|||
target_mode="sassy",
|
||||
added_anims=[self.teacher.change, "guilty"]
|
||||
)
|
||||
self.change_student_modes("angry", "sassy", "sad")
|
||||
self.wait(2)
|
||||
self.play(
|
||||
RemovePiCreatureBubble(self.students[1]),
|
||||
|
@ -362,6 +357,7 @@ class ShowSeveralQuaternionRotations(SpecialThreeDScene):
|
|||
],
|
||||
"start_phi": 70 * DEGREES,
|
||||
"start_theta": -140 * DEGREES,
|
||||
"ambient_rotation_rate": 0.01,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
|
@ -428,7 +424,7 @@ class ShowSeveralQuaternionRotations(SpecialThreeDScene):
|
|||
phi=self.start_phi,
|
||||
theta=self.start_theta,
|
||||
)
|
||||
self.begin_ambient_camera_rotation(0.01)
|
||||
self.begin_ambient_camera_rotation(self.ambient_rotation_rate)
|
||||
|
||||
def add_prism(self):
|
||||
prism = self.prism = self.get_prism()
|
||||
|
@ -623,9 +619,6 @@ class RotationMatrix(ShowSeveralQuaternionRotations):
|
|||
|
||||
|
||||
class EulerAnglesAndGimbal(ShowSeveralQuaternionRotations):
|
||||
CONFIG = {
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.setup_position()
|
||||
self.setup_angle_trackers()
|
||||
|
@ -774,6 +767,590 @@ class EulerAnglesAndGimbal(ShowSeveralQuaternionRotations):
|
|||
return line
|
||||
|
||||
|
||||
class NewSceneName(Scene):
|
||||
class QuaternionInterpolation(ShowSeveralQuaternionRotations):
|
||||
def construct(self):
|
||||
pass
|
||||
self.add_q_tracker()
|
||||
self.setup_camera_position()
|
||||
self.add_prism()
|
||||
self.add_axes()
|
||||
|
||||
self.change_q([1, 1, 1, 0], run_time=0)
|
||||
self.wait(2)
|
||||
self.change_q([1, 0.2, 0.6, -0.5], run_time=4)
|
||||
self.wait(2)
|
||||
self.change_q([1, -0.6, 0.2, -1], run_time=4)
|
||||
self.wait(2)
|
||||
|
||||
|
||||
class QuaternionInterpolationScematic(Scene):
|
||||
def construct(self):
|
||||
title = TextMobject("Slice of a hypersphere")
|
||||
title.to_edge(UP, buff=MED_SMALL_BUFF)
|
||||
self.add(title)
|
||||
|
||||
radius = 3
|
||||
circle = Circle(radius=radius)
|
||||
circle.set_stroke(LIGHT_GREY, 1)
|
||||
qs = [circle.point_from_proportion(p) for p in (0.55, 0.35, 0.15)]
|
||||
colors = [YELLOW, PINK, RED]
|
||||
q_dots = [Dot(q, color=c) for q, c in zip(qs, colors)]
|
||||
q_labels = [
|
||||
TexMobject("q_{}".format(i + 1)).next_to(
|
||||
dot, normalize(dot.get_center()), SMALL_BUFF
|
||||
).match_color(dot)
|
||||
for i, dot in enumerate(q_dots)
|
||||
]
|
||||
|
||||
q1, q2, q3 = qs
|
||||
lines = [
|
||||
DashedLine(q1, q2)
|
||||
for q1, q2 in zip(qs, qs[1:])
|
||||
]
|
||||
for color, line in zip([GREEN, BLUE], lines):
|
||||
line.set_stroke(color, 3)
|
||||
line.proj = line.copy().apply_function(
|
||||
lambda p: radius * normalize(p)
|
||||
)
|
||||
dot = Dot(qs[0], color=WHITE)
|
||||
|
||||
self.add(circle)
|
||||
self.add(dot)
|
||||
self.add(*q_dots + q_labels)
|
||||
|
||||
self.wait(2)
|
||||
for line, q in zip(lines, qs[1:]):
|
||||
self.play(
|
||||
ShowCreation(line),
|
||||
ShowCreation(line.proj),
|
||||
dot.move_to, q,
|
||||
run_time=4
|
||||
)
|
||||
self.wait(2)
|
||||
|
||||
|
||||
class RememberComplexNumbers(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
complex_number = TexMobject(
|
||||
"\\cos(\\theta) + \\sin(\\theta)i",
|
||||
tex_to_color_map={
|
||||
"\\cos(\\theta)": GREEN,
|
||||
"\\sin(\\theta)": RED
|
||||
}
|
||||
)
|
||||
complex_number.scale(1.2)
|
||||
complex_number.next_to(self.students, UP, MED_LARGE_BUFF)
|
||||
|
||||
self.teacher_says(
|
||||
"Remember how \\\\ complex numbers \\\\ compute rotations"
|
||||
)
|
||||
self.change_all_student_modes("pondering")
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeInFromDown(complex_number),
|
||||
self.get_student_changes(
|
||||
"thinking", "confused", "happy",
|
||||
look_at_arg=complex_number.get_center() + UP
|
||||
),
|
||||
run_time=2
|
||||
)
|
||||
self.change_student_modes(
|
||||
)
|
||||
self.wait(5)
|
||||
|
||||
|
||||
class ComplexNumberRotation(Scene):
|
||||
CONFIG = {
|
||||
"angle": 30 * DEGREES,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.add_plane()
|
||||
self.add_number()
|
||||
self.show_complex_unit()
|
||||
self.show_product()
|
||||
|
||||
def add_plane(self):
|
||||
plane = self.plane = ComplexPlane()
|
||||
self.play(Write(plane))
|
||||
|
||||
def add_number(self):
|
||||
plane = self.plane
|
||||
origin = plane.coords_to_point(0, 0)
|
||||
angle = self.angle
|
||||
|
||||
point = plane.coords_to_point(4, 1)
|
||||
dot = Dot(point, color=YELLOW)
|
||||
label = TexMobject("(4, 1)")
|
||||
label.next_to(dot, UR, buff=0)
|
||||
line = DashedLine(origin, point)
|
||||
rotated_line = line.copy().rotate(angle, about_point=origin)
|
||||
rotated_line.set_color(GREY)
|
||||
rotated_dot = dot.copy().rotate(angle, about_point=origin)
|
||||
rotated_dot.set_color(YELLOW_E)
|
||||
mystery_label = TexMobject("(?, ?)")
|
||||
mystery_label.next_to(rotated_dot, UR, buff=0)
|
||||
|
||||
arc = Arc(
|
||||
start_angle=line.get_angle(),
|
||||
angle=angle,
|
||||
radius=0.75
|
||||
)
|
||||
angle_tex = str(int(np.round(angle / DEGREES))) + "^\\circ"
|
||||
angle_label = TexMobject(angle_tex)
|
||||
angle_label.next_to(
|
||||
arc.point_from_proportion(0.3),
|
||||
UR, buff=SMALL_BUFF
|
||||
)
|
||||
|
||||
self.play(
|
||||
FadeInFromDown(label),
|
||||
GrowFromCenter(dot),
|
||||
ShowCreation(line)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
ShowCreation(arc),
|
||||
FadeInFromDown(angle_label),
|
||||
TransformFromCopy(line, rotated_line),
|
||||
TransformFromCopy(dot, rotated_dot),
|
||||
path_arc=angle,
|
||||
)
|
||||
self.play(Write(mystery_label))
|
||||
self.wait()
|
||||
|
||||
self.rotation_mobs = VGroup(
|
||||
arc, angle_label,
|
||||
rotated_line, rotated_dot,
|
||||
mystery_label
|
||||
)
|
||||
self.angle_tex = angle_tex
|
||||
self.number_label = label
|
||||
|
||||
def show_complex_unit(self):
|
||||
plane = self.plane
|
||||
angle = self.angle
|
||||
angle_tex = self.angle_tex
|
||||
complex_coordinate_labels = plane.get_coordinate_labels()
|
||||
unit_circle = Circle(radius=1, color=YELLOW)
|
||||
|
||||
origin = plane.number_to_point(0)
|
||||
z_point = plane.coords_to_point(np.cos(angle), np.sin(angle))
|
||||
one_point = plane.number_to_point(1)
|
||||
z_dot = Dot(z_point, color=WHITE)
|
||||
one_dot = Dot(one_point, color=WHITE)
|
||||
one_dot.fade(1)
|
||||
z_line = Line(origin, z_point)
|
||||
one_line = Line(origin, one_point)
|
||||
VGroup(z_dot, one_dot, z_line, one_line).set_color(BLUE)
|
||||
|
||||
cos_tex = "\\cos(" + angle_tex + ")"
|
||||
sin_tex = "\\sin(" + angle_tex + ")"
|
||||
label = TexMobject(
|
||||
cos_tex, "+", sin_tex, "i",
|
||||
tex_to_color_map={cos_tex: GREEN, sin_tex: RED}
|
||||
)
|
||||
label.add_background_rectangle()
|
||||
label.scale(0.8)
|
||||
label.next_to(plane.coords_to_point(0, 1), UR, SMALL_BUFF)
|
||||
arrow = Arrow(label.get_bottom(), z_point)
|
||||
|
||||
number_label = self.number_label
|
||||
new_number_label = TexMobject(
|
||||
"4 + 1i", tex_to_color_map={"4": GREEN, "1": RED}
|
||||
)
|
||||
new_number_label.move_to(number_label, LEFT)
|
||||
new_number_label.add_background_rectangle()
|
||||
|
||||
self.play(
|
||||
Write(complex_coordinate_labels, run_time=2),
|
||||
FadeOut(self.rotation_mobs)
|
||||
)
|
||||
self.play(ShowCreation(unit_circle))
|
||||
self.play(
|
||||
TransformFromCopy(one_dot, z_dot),
|
||||
TransformFromCopy(one_line, z_line),
|
||||
FadeInFromDown(label),
|
||||
GrowArrow(arrow),
|
||||
)
|
||||
self.wait()
|
||||
self.play(FadeOutAndShiftDown(number_label))
|
||||
self.play(FadeInFromDown(new_number_label))
|
||||
self.wait()
|
||||
|
||||
self.left_z_label = label
|
||||
self.right_z_label = new_number_label
|
||||
self.cos_tex = cos_tex
|
||||
self.sin_tex = sin_tex
|
||||
self.unit_z_group = VGroup(
|
||||
unit_circle, z_line, z_dot, label, arrow
|
||||
)
|
||||
|
||||
def show_product(self):
|
||||
plane = self.plane
|
||||
cos_tex = self.cos_tex
|
||||
sin_tex = self.sin_tex
|
||||
angle = self.angle
|
||||
|
||||
line = Line(
|
||||
FRAME_WIDTH * LEFT / 2 + FRAME_HEIGHT * UP / 2,
|
||||
plane.coords_to_point(-0.5, 1.5)
|
||||
)
|
||||
rect = BackgroundRectangle(line, buff=0)
|
||||
|
||||
left_z = self.left_z_label
|
||||
right_z = self.right_z_label
|
||||
new_left_z = left_z.copy()
|
||||
new_right_z = right_z.copy()
|
||||
|
||||
lp1, rp1, lp2, rp2 = parens = TexMobject("()()")
|
||||
top_line = VGroup(
|
||||
lp1, new_left_z, rp1,
|
||||
lp2, new_right_z, rp2,
|
||||
)
|
||||
top_line.arrange_submobjects(RIGHT, buff=SMALL_BUFF)
|
||||
top_line.set_width(rect.get_width() - 1)
|
||||
top_line.next_to(rect.get_top(), DOWN, MED_SMALL_BUFF)
|
||||
|
||||
mid_line = TexMobject(
|
||||
"\\big(", "4", cos_tex, "-", "1", sin_tex, "\\big)", "+",
|
||||
"\\big(", "1", cos_tex, "+", "4", sin_tex, "\\big)", "i",
|
||||
tex_to_color_map={
|
||||
cos_tex: GREEN,
|
||||
sin_tex: RED,
|
||||
"4": GREEN,
|
||||
"1": RED,
|
||||
}
|
||||
)
|
||||
mid_line.set_width(rect.get_width() - 0.5)
|
||||
mid_line.next_to(top_line, DOWN, MED_LARGE_BUFF)
|
||||
|
||||
new_z = np.exp(angle * complex(0, 1)) * complex(4, 1)
|
||||
low_line = TexMobject(
|
||||
"\\approx",
|
||||
str(np.round(new_z.real, 2)), "+",
|
||||
str(np.round(new_z.imag, 2)), "i",
|
||||
)
|
||||
low_line.next_to(mid_line, DOWN, MED_LARGE_BUFF)
|
||||
|
||||
self.play(FadeIn(rect))
|
||||
self.play(
|
||||
TransformFromCopy(left_z, new_left_z),
|
||||
TransformFromCopy(right_z, new_right_z),
|
||||
Write(parens)
|
||||
)
|
||||
self.wait()
|
||||
self.play(FadeInFrom(mid_line, UP))
|
||||
self.wait()
|
||||
self.play(FadeInFrom(low_line, UP))
|
||||
self.wait(2)
|
||||
self.play(FadeOut(self.unit_z_group))
|
||||
self.rotation_mobs.save_state()
|
||||
self.rotation_mobs.rotate(-angle, about_point=ORIGIN)
|
||||
self.rotation_mobs.fade(1)
|
||||
self.play(self.rotation_mobs.restore)
|
||||
self.wait()
|
||||
|
||||
mystery_label = self.rotation_mobs[-1]
|
||||
result = low_line[1:].copy()
|
||||
result.add_background_rectangle()
|
||||
self.play(
|
||||
result.move_to, mystery_label, LEFT,
|
||||
FadeOutAndShiftDown(mystery_label),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class ISquaredRule(Scene):
|
||||
def construct(self):
|
||||
tex = TextMobject("Use", "$i^2 = -1$")
|
||||
tex[1].set_color(RED)
|
||||
tex.scale(2)
|
||||
self.add(tex)
|
||||
self.play(Write(tex))
|
||||
self.wait()
|
||||
|
||||
|
||||
class RuleForQuaternionRotations(EulerAnglesAndGimbal):
|
||||
CONFIG = {
|
||||
"start_phi": 70 * DEGREES,
|
||||
"start_theta": -120 * DEGREES,
|
||||
"ambient_rotation_rate": 0.015,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.add_q_tracker()
|
||||
self.setup_camera_position()
|
||||
self.add_prism()
|
||||
self.add_axes()
|
||||
|
||||
self.show_axis()
|
||||
self.construct_quaternion()
|
||||
self.add_point_with_coordinates()
|
||||
self.add_inverse()
|
||||
|
||||
def get_axes(self):
|
||||
axes = EulerAnglesAndGimbal.get_axes(self)
|
||||
for axis in axes:
|
||||
vect = normalize(axis.get_vector())
|
||||
perp = rotate_vector(vect, TAU / 3, axis=[1, 1, 1])
|
||||
for i in range(1, 4):
|
||||
tick = Line(-perp, perp).scale(0.1)
|
||||
tick.match_style(axis)
|
||||
tick.move_to(2 * i * vect)
|
||||
axis.add(tick)
|
||||
axes.set_shade_in_3d(True)
|
||||
return axes
|
||||
|
||||
def show_axis(self):
|
||||
vect = normalize([1, -1, -0.5])
|
||||
line = self.get_dotted_line(vect, 0, 4)
|
||||
quat = np.append(0, vect)
|
||||
|
||||
axis_label = TextMobject("Axis of rotation")
|
||||
axis_label.next_to(line.get_corner(DR), DOWN, MED_LARGE_BUFF)
|
||||
axis_label.match_color(line)
|
||||
|
||||
self.add_fixed_orientation_mobjects(axis_label)
|
||||
self.play(
|
||||
ShowCreation(line),
|
||||
Write(axis_label)
|
||||
)
|
||||
self.change_q(quat, run_time=2)
|
||||
self.change_q([1, 0, 0, 0], run_time=2)
|
||||
|
||||
# Unit vector
|
||||
vect_mob = Vector(2 * vect, use_rectangular_stem=False)
|
||||
vect_mob.pointwise_become_partial(vect_mob, 0, 0.95)
|
||||
pieces = VGroup(*vect_mob.get_pieces(25))
|
||||
pieces.set_stroke(vect_mob.get_color(), 2)
|
||||
vect_mob.set_stroke(width=0)
|
||||
vect_mob.add_to_back(pieces)
|
||||
vect_mob.set_shade_in_3d(True)
|
||||
|
||||
vect_label = TexMobject(
|
||||
"{:.2f}".format(vect[0]), "i",
|
||||
"{:+.2f}".format(vect[1]), "j",
|
||||
"{:+.2f}".format(vect[2]), "k",
|
||||
)
|
||||
magnitude_label = TexMobject(
|
||||
"x", "^2 + ",
|
||||
"y", "^2 + ",
|
||||
"z", "^2 = 1",
|
||||
)
|
||||
for label in vect_label, magnitude_label:
|
||||
decimals = label[::2]
|
||||
colors = [I_COLOR, J_COLOR, K_COLOR]
|
||||
for d1, color in zip(decimals, colors):
|
||||
d1.set_color(color)
|
||||
label.rotate(TAU / 4, RIGHT).scale(0.7)
|
||||
label.next_to(vect_mob.get_end(), RIGHT, SMALL_BUFF)
|
||||
|
||||
magnitude_label.next_to(vect_label, IN)
|
||||
|
||||
self.play(
|
||||
FadeOut(line),
|
||||
FadeOutAndShiftDown(axis_label),
|
||||
ShowCreation(vect_mob)
|
||||
)
|
||||
# self.add_fixed_orientation_mobjects(vect_label)
|
||||
self.play(FadeInFromDown(vect_label))
|
||||
self.wait(3)
|
||||
self.play(TransformFromCopy(vect_label, magnitude_label))
|
||||
self.wait(3)
|
||||
|
||||
self.vect = vect
|
||||
self.vect_mob = vect_mob
|
||||
self.vect_label = vect_label
|
||||
self.magnitude_label = magnitude_label
|
||||
|
||||
def construct_quaternion(self):
|
||||
full_angle_q = self.get_quaternion_label("40^\\circ")
|
||||
half_angle_q = self.get_quaternion_label("40^\\circ / 2")
|
||||
for label in full_angle_q, half_angle_q:
|
||||
label.to_corner(UL)
|
||||
brace = Brace(half_angle_q, DOWN)
|
||||
q_label = brace.get_tex("q")
|
||||
full_angle_q.align_data(half_angle_q)
|
||||
rect = SurroundingRectangle(full_angle_q[5])
|
||||
|
||||
for mob in full_angle_q, half_angle_q, brace, q_label, rect:
|
||||
self.add_fixed_in_frame_mobjects(mob)
|
||||
self.remove(mob)
|
||||
self.play(FadeInFromDown(full_angle_q[1]))
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeInFromDown(full_angle_q[0]),
|
||||
LaggedStart(FadeInFromDown, full_angle_q[2:]),
|
||||
)
|
||||
self.play(
|
||||
GrowFromCenter(brace),
|
||||
Write(q_label)
|
||||
)
|
||||
self.wait(2)
|
||||
self.play(ShowCreation(rect))
|
||||
self.play(FadeOut(rect))
|
||||
self.wait(2)
|
||||
self.play(ReplacementTransform(full_angle_q, half_angle_q))
|
||||
self.wait(6)
|
||||
# TODO
|
||||
|
||||
def add_point_with_coordinates(self):
|
||||
prism = self.prism
|
||||
point = prism.get_corner(UR + OUT)
|
||||
template_sphere = Sphere(radius=0.1)
|
||||
template_sphere.set_stroke(width=0)
|
||||
template_sphere.set_color(PINK)
|
||||
ghost_sphere = template_sphere.copy()
|
||||
ghost_sphere.fade(0.8)
|
||||
for face in template_sphere:
|
||||
c = face.get_center()
|
||||
if c[0] < 0 and c[2] < 0:
|
||||
template_sphere.remove(face)
|
||||
template_sphere.move_to(point)
|
||||
ghost_sphere.move_to(point)
|
||||
|
||||
def get_sphere():
|
||||
result = template_sphere.copy()
|
||||
quat = self.q_tracker.get_value()
|
||||
angle, axis = angle_axis_from_quaternion(quat)
|
||||
result.rotate(angle=angle, axis=axis, about_point=ORIGIN)
|
||||
return result
|
||||
|
||||
sphere = updating_mobject_from_func(get_sphere)
|
||||
|
||||
point_label = TexMobject(
|
||||
"p", "=",
|
||||
"{:.2f}".format(point[0]), "i", "+"
|
||||
"{:.2f}".format(point[1]), "j", "+"
|
||||
"{:.2f}".format(point[2]), "k",
|
||||
)
|
||||
colors = [PINK, I_COLOR, J_COLOR, K_COLOR]
|
||||
for part, color in zip(point_label[::2], colors):
|
||||
part.set_color(color)
|
||||
point_label.scale(0.7)
|
||||
point_label.rotate(TAU / 4, RIGHT)
|
||||
point_label.next_to(point, RIGHT)
|
||||
|
||||
self.stop_ambient_camera_rotation()
|
||||
self.begin_ambient_camera_rotation(-0.01)
|
||||
self.play(FadeInFromLarge(sphere))
|
||||
self.play(Write(point_label))
|
||||
self.wait(3)
|
||||
|
||||
# Rotate
|
||||
quat = quaternion_from_angle_axis(40 * DEGREES, self.vect)
|
||||
r = get_norm(point)
|
||||
curved_arrow = Arrow(
|
||||
r * RIGHT, rotate_vector(r * RIGHT, 30 * DEGREES, OUT),
|
||||
buff=0,
|
||||
use_rectangular_stem=False,
|
||||
path_arc=60 * DEGREES,
|
||||
color=LIGHT_GREY,
|
||||
)
|
||||
curved_arrow.pointwise_become_partial(curved_arrow, 0, 0.9)
|
||||
curved_arrow.rotate(150 * DEGREES, about_point=ORIGIN)
|
||||
curved_arrow.apply_matrix(z_to_vector(self.vect))
|
||||
self.add(ghost_sphere, sphere)
|
||||
self.change_q(
|
||||
quat,
|
||||
added_anims=[ShowCreation(curved_arrow)],
|
||||
run_time=3
|
||||
)
|
||||
|
||||
mystery_label = TexMobject("(?, ?, ?)")
|
||||
mystery_label.add_background_rectangle()
|
||||
arrow = Vector(0.5 * DR, color=WHITE)
|
||||
arrow.next_to(mystery_label, DR, buff=0)
|
||||
# mystery_label.add(arrow)
|
||||
mystery_label.rotate(TAU / 4, RIGHT)
|
||||
mystery_label.next_to(sphere, OUT + LEFT, buff=0)
|
||||
self.play(FadeInFromDown(mystery_label))
|
||||
self.wait(5)
|
||||
|
||||
def add_inverse(self):
|
||||
label = TexMobject(
|
||||
"p", "\\rightarrow",
|
||||
"q", "\\cdot", "p", "\\cdot", "q^{-1}",
|
||||
tex_to_color_map={"p": PINK}
|
||||
)
|
||||
label.to_corner(UR)
|
||||
label.shift(2 * LEFT)
|
||||
self.add_fixed_in_frame_mobjects(label)
|
||||
|
||||
self.play(FadeInFromDown(label))
|
||||
self.wait(3)
|
||||
self.change_q(
|
||||
[1, 0, 0, 0],
|
||||
rate_func=there_and_back,
|
||||
run_time=5
|
||||
)
|
||||
self.wait(3)
|
||||
|
||||
#
|
||||
def get_quaternion_label(self, angle_tex):
|
||||
vect_label = self.vect_label.copy()
|
||||
vect_label.rotate(TAU / 4, LEFT)
|
||||
vect_label.replace(TexMobject(vect_label.get_tex_string()))
|
||||
vect_label.add_background_rectangle()
|
||||
result = VGroup(
|
||||
TexMobject("\\big("),
|
||||
TexMobject("\\text{cos}(", angle_tex, ")"),
|
||||
TexMobject("+"),
|
||||
TexMobject("\\text{sin}(", angle_tex, ")"),
|
||||
TexMobject("("),
|
||||
vect_label,
|
||||
TexMobject(")"),
|
||||
TexMobject("\\big)"),
|
||||
)
|
||||
for i in 1, 3:
|
||||
result[i][1].set_color(YELLOW)
|
||||
result.arrange_submobjects(RIGHT, buff=SMALL_BUFF)
|
||||
result.scale(0.7)
|
||||
return result
|
||||
|
||||
|
||||
class ExpandOutFullProduct(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
product = TexMobject(
|
||||
"""
|
||||
(w_0 + x_0 i + y_0 j + z_0 k)
|
||||
(x_1 i + y_1 j + z_1 k)
|
||||
(w_0 - x_0 i - y_0 j - z_0 k)
|
||||
""",
|
||||
tex_to_color_map={
|
||||
"w_0": W_COLOR, "(": WHITE, ")": WHITE,
|
||||
"x_0": I_COLOR, "y_0": J_COLOR, "z_0": K_COLOR,
|
||||
"x_1": I_COLOR, "y_1": J_COLOR, "z_1": K_COLOR,
|
||||
}
|
||||
)
|
||||
product.set_width(FRAME_WIDTH - 1)
|
||||
product.to_edge(UP)
|
||||
|
||||
n = 10
|
||||
q_brace = Brace(product[:n], DOWN)
|
||||
p_brace = Brace(product[n:-n], DOWN)
|
||||
q_inv_brace = Brace(product[-n:], DOWN)
|
||||
braces = VGroup(q_brace, p_brace, q_inv_brace)
|
||||
for brace, tex in zip(braces, ["q", "p", "q^{-1}"]):
|
||||
brace.add(brace.get_tex(tex))
|
||||
|
||||
words = TextMobject("= Rotation of $p$")
|
||||
words.next_to(braces, DOWN)
|
||||
|
||||
self.play(
|
||||
self.teacher.change, "raise_right_hand",
|
||||
FadeInFromDown(product)
|
||||
)
|
||||
self.play(
|
||||
LaggedStart(GrowFromCenter, braces),
|
||||
self.get_student_changes(
|
||||
"confused", "horrified", "confused"
|
||||
)
|
||||
)
|
||||
self.wait(2)
|
||||
self.play(Write(words))
|
||||
self.change_student_modes(
|
||||
"pondering", "confused", "erm",
|
||||
look_at_arg=words
|
||||
)
|
||||
self.wait(5)
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
|
||||
|
||||
from constants import *
|
||||
|
||||
from animation.animation import Animation
|
||||
|
|
|
@ -34,6 +34,7 @@ class ThreeDCamera(Camera):
|
|||
"frame_center": ORIGIN,
|
||||
"should_apply_shading": True,
|
||||
"exponential_projection": False,
|
||||
"max_allowable_norm": 3 * FRAME_WIDTH,
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
|
Loading…
Add table
Reference in a new issue