mirror of
https://github.com/3b1b/manim.git
synced 2025-09-01 00:48:45 +00:00
Finished large ExplainTrigFunctionDistances scene
This commit is contained in:
parent
e153b169aa
commit
b1eb9a135b
1 changed files with 460 additions and 10 deletions
470
tattoo.py
470
tattoo.py
|
@ -41,7 +41,7 @@ class TrigRepresentationsScene(Scene):
|
|||
def setup(self):
|
||||
self.init_axes()
|
||||
self.init_circle()
|
||||
self.init_theta_mobs()
|
||||
self.init_theta_group()
|
||||
|
||||
def init_axes(self):
|
||||
self.axes = Axes(
|
||||
|
@ -57,9 +57,9 @@ class TrigRepresentationsScene(Scene):
|
|||
)
|
||||
self.add(self.circle)
|
||||
|
||||
def init_theta_mobs(self):
|
||||
self.theta_mobs = self.get_theta_mobs()
|
||||
self.add(self.theta_mobs)
|
||||
def init_theta_group(self):
|
||||
self.theta_group = self.get_theta_group()
|
||||
self.add(self.theta_group)
|
||||
|
||||
def add_trig_lines(self, *funcs, **kwargs):
|
||||
lines = VGroup(*[
|
||||
|
@ -68,7 +68,7 @@ class TrigRepresentationsScene(Scene):
|
|||
])
|
||||
self.add(*lines)
|
||||
|
||||
def get_theta_mobs(self):
|
||||
def get_theta_group(self):
|
||||
arc = Arc(
|
||||
self.theta_value,
|
||||
radius = self.arc_radius,
|
||||
|
@ -147,7 +147,7 @@ class IntroduceCSC(TrigRepresentationsScene):
|
|||
csc_of_theta.next_to, brace, LEFT,
|
||||
path_arc = np.pi/2,
|
||||
)
|
||||
self.play(Write(self.theta_mobs, run_time = 1))
|
||||
self.play(Write(self.theta_group, run_time = 1))
|
||||
self.play(ShowCreation(cot_line))
|
||||
self.play(
|
||||
ShowCreation(csc_line),
|
||||
|
@ -155,10 +155,460 @@ class IntroduceCSC(TrigRepresentationsScene):
|
|||
)
|
||||
self.dither(3)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class TeachObscureTrigFunctions(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.teacher_says(
|
||||
"$\\sec(\\theta)$, ",
|
||||
"$\\csc(\\theta)$, ",
|
||||
"$\\cot(\\theta)$",
|
||||
)
|
||||
content = self.teacher.bubble.content.copy()
|
||||
self.change_student_modes(*["confused"]*3)
|
||||
self.student_says(
|
||||
"But why?",
|
||||
target_mode = "pleading",
|
||||
added_anims = [content.to_corner, UP+RIGHT]
|
||||
)
|
||||
self.dither()
|
||||
self.play(self.get_teacher().change_mode, "pondering")
|
||||
self.dither(3)
|
||||
|
||||
class CanYouExplainTheTattoo(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.student_says("""
|
||||
Wait, can you explain
|
||||
the actual tattoo here?
|
||||
""")
|
||||
self.random_blink()
|
||||
self.play(self.get_teacher().change_mode, "hooray")
|
||||
self.dither()
|
||||
|
||||
class ExplainTrigFunctionDistances(TrigRepresentationsScene, PiCreatureScene):
|
||||
CONFIG = {
|
||||
"use_morty" : False,
|
||||
"alt_theta_val" : 2*np.pi/5,
|
||||
}
|
||||
def setup(self):
|
||||
PiCreatureScene.setup(self)
|
||||
TrigRepresentationsScene.setup(self)
|
||||
|
||||
def construct(self):
|
||||
self.introduce_angle()
|
||||
self.show_sine_and_cosine()
|
||||
self.show_tangent_and_cotangent()
|
||||
self.show_secant_and_cosecant()
|
||||
self.explain_cosecant()
|
||||
self.summarize_full_group()
|
||||
|
||||
def introduce_angle(self):
|
||||
self.remove(self.circle)
|
||||
self.remove(self.theta_group)
|
||||
line, arc, theta, dot = self.theta_group
|
||||
line.rotate(-self.theta_value)
|
||||
brace = Brace(line, UP, buff = SMALL_BUFF)
|
||||
one = brace.get_text("1", buff = SMALL_BUFF)
|
||||
VGroup(line, brace, one).rotate(self.theta_value)
|
||||
one.rotate_in_place(-self.theta_value)
|
||||
self.circle.rotate(self.theta_value)
|
||||
|
||||
words = TextMobject("Corresponding point")
|
||||
words.next_to(dot, UP+RIGHT, buff = 1.5*LARGE_BUFF)
|
||||
words.shift_onto_screen()
|
||||
arrow = Arrow(words.get_bottom(), dot, buff = SMALL_BUFF)
|
||||
|
||||
self.play(
|
||||
ShowCreation(line),
|
||||
ShowCreation(arc),
|
||||
)
|
||||
self.play(Write(theta))
|
||||
self.play(self.pi_creature.change_mode, "pondering")
|
||||
self.play(
|
||||
ShowCreation(self.circle),
|
||||
Rotating(line, rate_func = smooth, in_place = False),
|
||||
run_time = 2
|
||||
)
|
||||
self.play(
|
||||
Write(words),
|
||||
ShowCreation(arrow),
|
||||
ShowCreation(dot)
|
||||
)
|
||||
self.dither()
|
||||
self.play(
|
||||
GrowFromCenter(brace),
|
||||
Write(one)
|
||||
)
|
||||
self.dither(2)
|
||||
self.play(*map(FadeOut, [
|
||||
words, arrow, brace, one
|
||||
]))
|
||||
self.radial_line_label = VGroup(brace, one)
|
||||
|
||||
def show_sine_and_cosine(self):
|
||||
sin_line, sin_brace, sin_text = sin_group = self.get_line_brace_text("sin")
|
||||
cos_line, cos_brace, cos_text = cos_group = self.get_line_brace_text("cos")
|
||||
|
||||
self.play(ShowCreation(sin_line))
|
||||
self.play(
|
||||
GrowFromCenter(sin_brace),
|
||||
Write(sin_text),
|
||||
)
|
||||
self.play(self.pi_creature.change_mode, "happy")
|
||||
self.play(ShowCreation(cos_line))
|
||||
self.play(
|
||||
GrowFromCenter(cos_brace),
|
||||
Write(cos_text),
|
||||
)
|
||||
self.dither()
|
||||
self.change_mode("well")
|
||||
|
||||
original_theta_value = self.theta_value
|
||||
self.theta_value = self.alt_theta_val
|
||||
sin_group.target = self.get_line_brace_text("sin")
|
||||
cos_group.target = self.get_line_brace_text("cos")
|
||||
self.theta_group.target = self.get_theta_group()
|
||||
self.play(
|
||||
*map(MoveToTarget,
|
||||
[sin_group, cos_group, self.theta_group]
|
||||
),
|
||||
path_arc = self.theta_value - original_theta_value,
|
||||
rate_func = there_and_back,
|
||||
run_time = 5
|
||||
)
|
||||
self.theta_value = original_theta_value
|
||||
self.change_mode("happy")
|
||||
self.dither()
|
||||
self.sin_group, self.cos_group = sin_group, cos_group
|
||||
|
||||
def show_tangent_and_cotangent(self):
|
||||
tan_group = self.get_line_brace_text("tan")
|
||||
cot_group = self.get_line_brace_text("cot")
|
||||
tan_text = tan_group[-1]
|
||||
cot_text = cot_group[-1]
|
||||
line = Line(UP, DOWN).scale(SPACE_HEIGHT)
|
||||
line.rotate(self.theta_value)
|
||||
line.move_to(self.theta_group[-1])
|
||||
line.set_stroke(width = 2)
|
||||
|
||||
sin_tex = "{\\sin(\\theta)}"
|
||||
cos_tex = "{\\cos(\\theta)}"
|
||||
tan_frac = TexMobject("= \\frac" + sin_tex + cos_tex)
|
||||
cot_frac = TexMobject("= \\frac" + cos_tex + sin_tex)
|
||||
tan_frac.to_corner(UP+LEFT)
|
||||
tan_frac.shift(2*RIGHT)
|
||||
cot_frac.next_to(tan_frac, DOWN)
|
||||
|
||||
|
||||
self.change_mode("pondering")
|
||||
for frac, text in (tan_frac, tan_text), (cot_frac, cot_text):
|
||||
VGroup(frac[5], frac[-2]).highlight(YELLOW)
|
||||
frac.scale_in_place(0.7)
|
||||
text.save_state()
|
||||
text.next_to(frac, LEFT)
|
||||
self.play(Write(VGroup(text, frac)))
|
||||
self.dither()
|
||||
self.change_mode("confused")
|
||||
self.dither()
|
||||
self.play(*map(FadeOut, [
|
||||
tan_frac, cot_frac, self.sin_group, self.cos_group
|
||||
]))
|
||||
self.dither()
|
||||
|
||||
self.play(
|
||||
self.theta_group[-1].highlight, YELLOW,
|
||||
ShowCreation(line),
|
||||
self.pi_creature.change_mode, 'pondering'
|
||||
)
|
||||
small_lines = VGroup()
|
||||
for group in tan_group, cot_group:
|
||||
small_line, brace, text = group
|
||||
self.play(
|
||||
ShowCreation(small_line),
|
||||
GrowFromCenter(brace),
|
||||
text.restore,
|
||||
)
|
||||
self.dither()
|
||||
small_lines.add(small_line)
|
||||
self.play(FadeOut(line), Animation(small_lines))
|
||||
|
||||
original_theta_value = self.theta_value
|
||||
self.theta_value = self.alt_theta_val
|
||||
tan_group.target = self.get_line_brace_text("tan")
|
||||
cot_group.target = self.get_line_brace_text("cot")
|
||||
self.theta_group.target = self.get_theta_group()
|
||||
self.play(
|
||||
*map(MoveToTarget,
|
||||
[tan_group, cot_group, self.theta_group]
|
||||
),
|
||||
path_arc = self.theta_value - original_theta_value,
|
||||
rate_func = there_and_back,
|
||||
run_time = 5
|
||||
)
|
||||
self.theta_value = original_theta_value
|
||||
self.change_mode("happy")
|
||||
self.dither(2)
|
||||
|
||||
self.tangent_line = self.get_tangent_line()
|
||||
self.add(self.tangent_line)
|
||||
self.play(*it.chain(*[
|
||||
map(FadeOut, [tan_group, cot_group]),
|
||||
[Animation(self.theta_group[-1])]
|
||||
]))
|
||||
|
||||
def show_secant_and_cosecant(self):
|
||||
sec_group = self.get_line_brace_text("sec")
|
||||
csc_group = self.get_line_brace_text("csc")
|
||||
sec_line, sec_brace, sec_text = sec_group
|
||||
csc_line, csc_brace, csc_text = csc_group
|
||||
|
||||
sec_frac = TexMobject("= \\frac{1}{\\cos(\\theta)}")
|
||||
sec_frac.to_corner(UP+LEFT).shift(2*RIGHT)
|
||||
csc_frac = TexMobject("= \\frac{1}{\\sin(\\theta)}")
|
||||
csc_frac.next_to(sec_frac, DOWN)
|
||||
|
||||
sec_dot, csc_dot = [
|
||||
Dot(line.get_end(), color = line.get_color())
|
||||
for line in sec_line, csc_line
|
||||
]
|
||||
sec_group.add(sec_dot)
|
||||
csc_group.add(csc_dot)
|
||||
|
||||
for text, frac in (sec_text, sec_frac), (csc_text, csc_frac):
|
||||
frac[-2].highlight(YELLOW)
|
||||
frac.scale_in_place(0.7)
|
||||
text.save_state()
|
||||
text.next_to(frac, LEFT)
|
||||
frac.add_to_back(text.copy())
|
||||
self.play(
|
||||
Write(frac),
|
||||
self.pi_creature.change_mode, "erm"
|
||||
)
|
||||
self.dither()
|
||||
self.dither()
|
||||
for group in sec_group, csc_group:
|
||||
line, brace, text, dot = group
|
||||
dot.save_state()
|
||||
dot.move_to(text)
|
||||
dot.set_fill(opacity = 0)
|
||||
self.play(dot.restore)
|
||||
self.dither()
|
||||
self.play(
|
||||
ShowCreation(line),
|
||||
GrowFromCenter(brace),
|
||||
text.restore,
|
||||
self.pi_creature.change_mode, "pondering"
|
||||
)
|
||||
self.dither()
|
||||
|
||||
|
||||
original_theta_value = self.theta_value
|
||||
self.theta_value = self.alt_theta_val
|
||||
sec_group.target = self.get_line_brace_text("sec")
|
||||
csc_group.target = self.get_line_brace_text("csc")
|
||||
for group in sec_group, csc_group:
|
||||
line = group.target[0]
|
||||
group.target.add(
|
||||
Dot(line.get_end(), color = line.get_color())
|
||||
)
|
||||
self.theta_group.target = self.get_theta_group()
|
||||
self.tangent_line.target = self.get_tangent_line()
|
||||
self.play(
|
||||
*map(MoveToTarget,
|
||||
[sec_group, csc_group, self.tangent_line, self.theta_group]
|
||||
),
|
||||
path_arc = self.theta_value - original_theta_value,
|
||||
rate_func = there_and_back,
|
||||
run_time = 5
|
||||
)
|
||||
self.theta_value = original_theta_value
|
||||
self.change_mode("confused")
|
||||
self.dither(2)
|
||||
|
||||
self.play(*map(FadeOut, [
|
||||
sec_group, sec_frac
|
||||
]))
|
||||
self.csc_group = csc_group
|
||||
self.csc_frac =csc_frac
|
||||
|
||||
def explain_cosecant(self):
|
||||
sin_group = self.get_line_brace_text("sin")
|
||||
sin_line, sin_brace, sin_text = sin_group
|
||||
csc_line, csc_brace, csc_text, csc_dot = self.csc_group
|
||||
csc_subgroup = VGroup(csc_brace, csc_text)
|
||||
|
||||
arc_theta = VGroup(*self.theta_group[1:3]).copy()
|
||||
arc_theta.rotate(-np.pi/2)
|
||||
arc_theta.shift(csc_line.get_end())
|
||||
arc_theta[1].rotate_in_place(np.pi/2)
|
||||
|
||||
radial_line = self.theta_group[0]
|
||||
|
||||
tri1 = Polygon(
|
||||
ORIGIN, radial_line.get_end(), sin_line.get_end(),
|
||||
color = GREEN
|
||||
)
|
||||
tri2 = Polygon(
|
||||
csc_line.get_end(), ORIGIN, radial_line.get_end(),
|
||||
color = GREEN
|
||||
)
|
||||
|
||||
opp_over_hyp = TexMobject(
|
||||
"\\frac{\\text{Opposite}}{\\text{Hypotenuse}} ="
|
||||
)
|
||||
frac1 = TexMobject("\\frac{\\sin(\\theta)}{1}")
|
||||
frac1.next_to(opp_over_hyp)
|
||||
frac1[-4].highlight(YELLOW)
|
||||
frac2 = TexMobject("= \\frac{1}{\\csc(\\theta)}")
|
||||
frac2.next_to(frac1)
|
||||
frac2[-2].highlight(YELLOW)
|
||||
frac_group = VGroup(opp_over_hyp, frac1, frac2)
|
||||
frac_group.scale_to_fit_width(SPACE_WIDTH-1)
|
||||
frac_group.next_to(ORIGIN, RIGHT).to_edge(UP)
|
||||
|
||||
one_brace, one = self.radial_line_label
|
||||
one.move_to(one_brace.get_center_of_mass())
|
||||
|
||||
self.play(ShowCreation(tri1))
|
||||
self.play(
|
||||
ApplyMethod(tri1.rotate_in_place, np.pi/12, rate_func = wiggle),
|
||||
self.pi_creature.change_mode, "thinking"
|
||||
)
|
||||
self.dither()
|
||||
tri1.save_state()
|
||||
self.play(Transform(tri1, tri2, path_arc = np.pi/2))
|
||||
self.play(Write(arc_theta))
|
||||
self.dither(2)
|
||||
|
||||
self.play(Write(opp_over_hyp))
|
||||
self.dither()
|
||||
csc_subgroup.save_state()
|
||||
self.play(
|
||||
tri1.restore,
|
||||
csc_subgroup.fade, 0.7
|
||||
)
|
||||
self.play(
|
||||
ShowCreation(sin_line),
|
||||
GrowFromCenter(sin_brace),
|
||||
Write(sin_text)
|
||||
)
|
||||
self.dither()
|
||||
self.play(Write(one))
|
||||
self.dither()
|
||||
self.play(Write(frac1))
|
||||
self.dither()
|
||||
self.play(
|
||||
Transform(tri1, tri2),
|
||||
FadeOut(sin_group)
|
||||
)
|
||||
self.play(
|
||||
radial_line.rotate_in_place, np.pi/12,
|
||||
rate_func = wiggle
|
||||
)
|
||||
self.dither()
|
||||
self.play(csc_subgroup.restore)
|
||||
self.dither()
|
||||
self.play(Write(frac2))
|
||||
self.change_mode("happy")
|
||||
self.play(FadeOut(opp_over_hyp))
|
||||
self.reciprocate(frac1, frac2)
|
||||
self.play(*map(FadeOut, [
|
||||
one, self.csc_group, tri1,
|
||||
frac1, frac2, self.csc_frac,
|
||||
arc_theta
|
||||
]))
|
||||
|
||||
def reciprocate(self, frac1, frac2):
|
||||
# Not general, meant only for these definitions:
|
||||
# frac1 = TexMobject("\\frac{\\sin(\\theta)}{1}")
|
||||
# frac2 = TexMobject("= \\frac{1}{\\csc(\\theta)}")
|
||||
num1 = VGroup(*frac1[:6])
|
||||
dem1 = frac1[-1]
|
||||
num2 = frac2[1]
|
||||
dem2 = VGroup(*frac2[-6:])
|
||||
group = VGroup(frac1, frac2)
|
||||
|
||||
self.play(
|
||||
group.scale, 1/0.7,
|
||||
group.to_corner, UP+RIGHT,
|
||||
)
|
||||
self.play(
|
||||
num1.move_to, dem1,
|
||||
dem1.move_to, num1,
|
||||
num2.move_to, dem2,
|
||||
dem2.move_to, num2,
|
||||
path_arc = np.pi
|
||||
)
|
||||
self.dither()
|
||||
self.play(
|
||||
dem2.move_to, frac2[-2],
|
||||
VGroup(*frac2[-2:]).highlight, BLACK
|
||||
)
|
||||
|
||||
def summarize_full_group(self):
|
||||
scale_factor = 1.5
|
||||
theta_subgroup = VGroup(self.theta_group[0], self.theta_group[-1])
|
||||
self.play(
|
||||
self.circle.scale, scale_factor,
|
||||
self.axes.scale, scale_factor,
|
||||
theta_subgroup.scale, scale_factor,
|
||||
)
|
||||
self.unit_length *= scale_factor
|
||||
|
||||
to_fade = VGroup()
|
||||
for func_name in ["sin", "tan", "sec", "cos", "cot", "csc"]:
|
||||
line, brace, text = self.get_line_brace_text(func_name)
|
||||
angle = line.get_angle()
|
||||
if np.cos(angle) < 0:
|
||||
angle += np.pi
|
||||
if func_name is "sin":
|
||||
target = line.get_center()+0.2*LEFT+0.1*DOWN
|
||||
else:
|
||||
target = VGroup(brace, line).get_center_of_mass()
|
||||
if func_name in ["sin", "cos"]:
|
||||
text.scale(0.75)
|
||||
text.rotate(angle)
|
||||
text.move_to(target)
|
||||
line.set_stroke(width = 6)
|
||||
self.play(
|
||||
ShowCreation(line),
|
||||
Write(text, run_time = 1)
|
||||
)
|
||||
if func_name is "sec":
|
||||
self.dither()
|
||||
if func_name in ["sec", "csc", "cot"]:
|
||||
to_fade.add(line, text)
|
||||
self.dither()
|
||||
self.change_mode("surprised")
|
||||
self.dither(2)
|
||||
self.remove(self.tangent_line)
|
||||
self.play(
|
||||
FadeOut(to_fade),
|
||||
self.pi_creature.change_mode, "sassy"
|
||||
)
|
||||
self.dither(2)
|
||||
|
||||
def get_line_brace_text(self, func_name = "sin"):
|
||||
line = self.get_trig_line(func_name)
|
||||
angle = line.get_angle()
|
||||
vect = rotate_vector(UP, angle)
|
||||
vect = np.round(vect, 1)
|
||||
if (vect[1] < 0) ^ (func_name is "sec"):
|
||||
vect = -vect
|
||||
angle += np.pi
|
||||
brace = Brace(line, vect)
|
||||
brace.highlight(line.get_color())
|
||||
text = TexMobject("\\%s(\\theta)"%func_name)
|
||||
text.scale(0.75)
|
||||
text[-2].highlight(self.theta_color)
|
||||
text.add_background_rectangle()
|
||||
text.next_to(brace.get_center(), vect, buff = 1.2*MED_BUFF)
|
||||
return VGroup(line, brace, text)
|
||||
|
||||
def get_tangent_line(self):
|
||||
return Line(
|
||||
self.unit_length*(1./np.sin(self.theta_value))*UP,
|
||||
self.unit_length*(1./np.cos(self.theta_value))*RIGHT,
|
||||
color = GREY
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue