3b1b-manim/eoc/chapter2.py

426 lines
12 KiB
Python
Raw Normal View History

2016-12-26 07:10:38 -08:00
from helpers import *
from mobject.tex_mobject import TexMobject
from mobject import Mobject
from mobject.image_mobject import ImageMobject
from mobject.vectorized_mobject import *
from animation.animation import Animation
from animation.transform import *
from animation.simple_animations import *
from animation.playground import *
from topics.geometry import *
from topics.characters import *
from topics.functions import *
from topics.fractals import *
from topics.number_line import *
from topics.combinatorics import *
from topics.numerals import *
from topics.three_dimensions import *
from topics.objects import *
from scene import Scene
from scene.zoomed_scene import ZoomedScene
from camera import Camera
from mobject.svg_mobject import *
from mobject.tex_mobject import *
from eoc.chapter1 import OpeningQuote
from eoc.graph_scene import *
class Car(SVGMobject):
CONFIG = {
"file_name" : "Car",
"height" : 1,
"color" : GREY,
}
def __init__(self, **kwargs):
SVGMobject.__init__(self, **kwargs)
self.scale_to_fit_height(self.height)
self.set_stroke(color = WHITE, width = 0)
self.set_fill(self.color, opacity = 1)
randy = Randolph(mode = "happy")
randy.scale_to_fit_height(0.6*self.get_height())
randy.stretch(0.8, 0)
randy.look(RIGHT)
randy.move_to(self)
randy.shift(0.07*self.height*(RIGHT+UP))
self.add_to_back(randy)
orientation_line = Line(self.get_left(), self.get_right())
orientation_line.set_stroke(width = 0)
self.add(orientation_line)
self.orientation_line = orientation_line
self.add_treds_to_tires()
def move_to(self, point_or_mobject):
vect = rotate_vector(
UP+LEFT, self.orientation_line.get_angle()
)
self.next_to(point_or_mobject, vect, buff = 0)
return self
def get_front_line(self):
return DashedLine(
self.get_corner(UP+RIGHT),
self.get_corner(DOWN+RIGHT),
color = YELLOW,
dashed_segment_length = 0.05,
)
def add_treds_to_tires(self):
for tire in self.get_tires():
radius = tire.get_width()/2
center = tire.get_center()
tred = Line(
0.9*radius*RIGHT, 1.4*radius*RIGHT,
stroke_width = 2,
color = BLACK
)
tred.rotate_in_place(np.pi/4)
for theta in np.arange(0, 2*np.pi, np.pi/4):
new_tred = tred.copy()
new_tred.rotate(theta)
new_tred.shift(center)
tire.add(new_tred)
return self
def get_tires(self):
return self[1][1], self[1][3]
class MoveCar(ApplyMethod):
def __init__(self, car, target_point, **kwargs):
ApplyMethod.__init__(self, car.move_to, target_point, **kwargs)
displacement = self.ending_mobject.get_right()-self.starting_mobject.get_right()
distance = np.linalg.norm(displacement)
tire_radius = car.get_tires()[0].get_width()/2
self.total_tire_radians = -distance/tire_radius
def update_mobject(self, alpha):
ApplyMethod.update_mobject(self, alpha)
if alpha == 0:
return
radians = alpha*self.total_tire_radians
for tire in self.mobject.get_tires():
tire.rotate_in_place(radians)
class IncrementNumber(Succession):
CONFIG = {
"start_num" : 0,
"changes_per_second" : 1,
"run_time" : 11,
}
def __init__(self, num_mob, **kwargs):
digest_config(self, kwargs)
n_iterations = int(self.run_time * self.changes_per_second)
new_num_mobs = [
TexMobject(str(num)).move_to(num_mob, LEFT)
for num in range(self.start_num, self.start_num+n_iterations)
]
transforms = [
Transform(
num_mob, new_num_mob,
run_time = 1.0/self.changes_per_second,
rate_func = squish_rate_func(smooth, 0, 0.5)
)
for new_num_mob in new_num_mobs
]
Succession.__init__(
self, *transforms, **{
"rate_func" : None,
"run_time" : self.run_time,
}
)
class IncrementTest(Scene):
def construct(self):
num = TexMobject("0")
num.shift(UP)
self.play(IncrementNumber(num))
self.dither()
############################
class Chapter2OpeningQuote(OpeningQuote):
CONFIG = {
"quote" : [
"So far as the theories of mathematics are about",
"reality,",
"they are not",
"certain;",
"so far as they are",
"certain,",
"they are not about",
"reality.",
],
"highlighted_quote_terms" : {
"reality," : BLUE,
"certain;" : GREEN,
"certain," : GREEN,
"reality." : BLUE,
},
"author" : "Albert Einstein"
}
class Introduction(TeacherStudentsScene):
def construct(self):
self.student_says(
"What is a derivative?"
)
self.play(self.get_teacher().change_mode, "happy")
self.dither()
self.teacher_says(
"It's actually a \\\\",
"very subtle idea",
target_mode = "well"
)
self.change_student_modes(None, "pondering", "thinking")
self.dither()
self.change_student_modes("erm")
self.student_says(
"Doesn't the derivative measure\\\\",
"instantaneous rate of change", "?",
student_index = 0,
)
self.dither()
bubble = self.get_students()[0].bubble
phrase = bubble.content[1]
bubble.content.remove(phrase)
self.play(
phrase.center,
phrase.scale, 1.5,
phrase.to_edge, UP,
FadeOut(bubble),
FadeOut(bubble.content),
*it.chain(*[
[
pi.change_mode, mode,
pi.look_at, SPACE_HEIGHT*UP
]
for pi, mode in zip(self.get_everyone(), [
"speaking", "pondering", "confused", "confused",
])
])
)
self.dither()
change = VGroup(*phrase[-len("change"):])
instantaneous = VGroup(*phrase[:len("instantaneous")])
change_brace = Brace(change)
change_description = change_brace.get_text(
"Requires multiple \\\\ points in time"
)
instantaneous_brace = Brace(instantaneous)
instantaneous_description = instantaneous_brace.get_text(
"One point \\\\ in time"
)
clock = Clock()
clock.next_to(change_description, DOWN)
def get_clock_anim(run_time = 3):
return ClockPassesTime(
clock,
hours_passed = 0.4*run_time,
run_time = run_time,
)
self.play(FadeIn(clock))
self.play(
change.gradient_highlight, BLUE, YELLOW,
GrowFromCenter(change_brace),
Write(change_description),
get_clock_anim()
)
self.play(get_clock_anim(1))
stopped_clock = clock.copy()
stopped_clock.next_to(instantaneous_description, DOWN)
self.play(
instantaneous.highlight, BLUE,
GrowFromCenter(instantaneous_brace),
Transform(change_description.copy(), instantaneous_description),
clock.copy().next_to, instantaneous_description, DOWN,
get_clock_anim(3)
)
self.play(get_clock_anim(6))
class FathersOfCalculus(Scene):
CONFIG = {
"names" : [
"Barrow",
"Newton",
"Leibniz",
"Cauchy",
"Weierstrass",
],
"picture_height" : 2.5,
}
def construct(self):
title = TextMobject("(A few) Fathers of Calculus")
title.to_edge(UP)
self.add(title)
men = Mobject()
for name in self.names:
image = ImageMobject(name, invert = False)
image.scale_to_fit_height(self.picture_height)
title = TextMobject(name)
title.scale(0.8)
title.next_to(image, DOWN)
image.add(title)
men.add(image)
men.arrange_submobjects(RIGHT, aligned_edge = UP)
men.shift(DOWN)
discover_brace = Brace(Mobject(*men[:3]), UP)
discover = discover_brace.get_text("Discovered it")
VGroup(discover_brace, discover).highlight(BLUE)
rigor_brace = Brace(Mobject(*men[3:]), UP)
rigor = rigor_brace.get_text("Made it rigorous")
rigor.shift(0.1*DOWN)
VGroup(rigor_brace, rigor).highlight(YELLOW)
for man in men:
self.play(FadeIn(man))
self.play(
GrowFromCenter(discover_brace),
Write(discover, run_time = 1)
)
self.play(
GrowFromCenter(rigor_brace),
Write(rigor, run_time = 1)
)
self.dither()
class IntroduceCar(Scene):
def construct(self):
point_A = DOWN+4*LEFT
point_B = DOWN+5*RIGHT
A = Dot(point_A)
B = Dot(point_B)
line = Line(point_A, point_B)
VGroup(A, B, line).highlight(WHITE)
for dot, tex in (A, "A"), (B, "B"):
label = TexMobject(tex).next_to(dot, DOWN)
dot.add(label)
car = Car()
car.move_to(point_A)
front_line = car.get_front_line()
time_label = TextMobject("Time (in seconds):", "0")
time_label.shift(2*UP)
distance_brace = Brace(line, UP)
# distance_brace.set_fill(opacity = 0.5)
distance = distance_brace.get_text("100m")
self.add(A, B, line, car, time_label)
self.play(ShowCreation(front_line))
self.play(FadeOut(front_line))
self.play(
MoveCar(car, point_B, run_time = 10),
IncrementNumber(time_label[1], run_time = 11)
)
front_line = car.get_front_line()
self.play(ShowCreation(front_line))
self.play(FadeOut(front_line))
self.play(
GrowFromCenter(distance_brace),
Write(distance)
)
self.dither()
self.play(
car.move_to, point_A,
FadeOut(time_label),
FadeOut(distance_brace),
FadeOut(distance)
)
graph_scene = GraphCarTrajectory(skip_animations = True)
origin = graph_scene.graph_origin
top = graph_scene.coords_to_point(0, 100)
new_length = np.linalg.norm(top-origin)
new_point_B = point_A + new_length*RIGHT
group = VGroup(car, A, B, line)
for mob in group:
mob.generate_target()
group.target = VGroup(*[m.target for m in group])
B.target.shift(new_point_B - point_B)
line.target.put_start_and_end_on(
point_A, new_point_B
)
group.target.rotate(np.pi/2, about_point = point_A)
group.target.shift(graph_scene.graph_origin - point_A)
self.play(MoveToTarget(group))
self.dither()
class GraphCarTrajectory(GraphScene):
CONFIG = {
"x_min" : 0,
"x_axis_label" : "Time (seconds)",
"y_min" : 0,
"y_max" : 110,
"y_tick_frequency" : 10,
"y_labeled_nums" : range(10, 110, 10),
"y_axis_label" : "Distance traveled \\\\ (meters)",
"graph_origin" : 2.5*DOWN + 5*LEFT,
}
def construct(self):
self.setup_axes(animate = False)
graph = self.graph_function(
lambda t : 100*smooth(t/10.),
)
self.remove(graph)
car = Car()
car.rotate(np.pi/2)
car.move_to(self.coords_to_point(0, 0))
self.add(car)