mirror of
https://github.com/3b1b/manim.git
synced 2025-04-13 09:47:07 +00:00
Finished cube animation for eoc/chapter3
This commit is contained in:
parent
55a9819ac3
commit
b097620389
7 changed files with 151 additions and 38 deletions
|
@ -321,8 +321,8 @@ class Succession(Animation):
|
||||||
#require leveraging implementation details of
|
#require leveraging implementation details of
|
||||||
#Animations, and knowing about the different
|
#Animations, and knowing about the different
|
||||||
#struction of Transform?
|
#struction of Transform?
|
||||||
if hasattr(curr_anim, "ending_mobject"):
|
if hasattr(curr_anim, "target_mobject"):
|
||||||
curr_anim.mobject.align_data(curr_anim.ending_mobject)
|
curr_anim.mobject.align_data(curr_anim.target_mobject)
|
||||||
curr_anim.starting_mobject = curr_anim.mobject.copy()
|
curr_anim.starting_mobject = curr_anim.mobject.copy()
|
||||||
curr_anim.update(scaled_alpha - index)
|
curr_anim.update(scaled_alpha - index)
|
||||||
self.last_index = index
|
self.last_index = index
|
||||||
|
|
|
@ -15,16 +15,18 @@ class Transform(Animation):
|
||||||
"path_arc" : 0,
|
"path_arc" : 0,
|
||||||
"path_func" : None,
|
"path_func" : None,
|
||||||
"submobject_mode" : "all_at_once",
|
"submobject_mode" : "all_at_once",
|
||||||
|
"replace_mobject_with_target_in_scene" : False,
|
||||||
}
|
}
|
||||||
def __init__(self, mobject, ending_mobject, **kwargs):
|
def __init__(self, mobject, target_mobject, **kwargs):
|
||||||
#Copy ending_mobject so as to not mess with caller
|
#Copy target_mobject so as to not mess with caller
|
||||||
ending_mobject = ending_mobject.copy()
|
self.original_target_mobject = target_mobject
|
||||||
|
target_mobject = target_mobject.copy()
|
||||||
digest_config(self, kwargs, locals())
|
digest_config(self, kwargs, locals())
|
||||||
mobject.align_data(ending_mobject)
|
mobject.align_data(target_mobject)
|
||||||
self.init_path_func()
|
self.init_path_func()
|
||||||
|
|
||||||
Animation.__init__(self, mobject, **kwargs)
|
Animation.__init__(self, mobject, **kwargs)
|
||||||
self.name += "To" + str(ending_mobject)
|
self.name += "To" + str(target_mobject)
|
||||||
|
|
||||||
def update_config(self, **kwargs):
|
def update_config(self, **kwargs):
|
||||||
Animation.update_config(self, **kwargs)
|
Animation.update_config(self, **kwargs)
|
||||||
|
@ -42,7 +44,7 @@ class Transform(Animation):
|
||||||
def get_all_families_zipped(self):
|
def get_all_families_zipped(self):
|
||||||
return zip(*map(
|
return zip(*map(
|
||||||
Mobject.submobject_family,
|
Mobject.submobject_family,
|
||||||
[self.mobject, self.starting_mobject, self.ending_mobject]
|
[self.mobject, self.starting_mobject, self.target_mobject]
|
||||||
))
|
))
|
||||||
|
|
||||||
def update_submobject(self, submob, start, end, alpha):
|
def update_submobject(self, submob, start, end, alpha):
|
||||||
|
@ -235,13 +237,13 @@ class TransformAnimations(Transform):
|
||||||
if start_anim.starting_mobject.get_num_points() != end_anim.starting_mobject.get_num_points():
|
if start_anim.starting_mobject.get_num_points() != end_anim.starting_mobject.get_num_points():
|
||||||
start_anim.starting_mobject.align_data(end_anim.starting_mobject)
|
start_anim.starting_mobject.align_data(end_anim.starting_mobject)
|
||||||
for anim in start_anim, end_anim:
|
for anim in start_anim, end_anim:
|
||||||
if hasattr(anim, "ending_mobject"):
|
if hasattr(anim, "target_mobject"):
|
||||||
anim.starting_mobject.align_data(anim.ending_mobject)
|
anim.starting_mobject.align_data(anim.target_mobject)
|
||||||
|
|
||||||
Transform.__init__(self, start_anim.mobject, end_anim.mobject, **kwargs)
|
Transform.__init__(self, start_anim.mobject, end_anim.mobject, **kwargs)
|
||||||
#Rewire starting and ending mobjects
|
#Rewire starting and ending mobjects
|
||||||
start_anim.mobject = self.starting_mobject
|
start_anim.mobject = self.starting_mobject
|
||||||
end_anim.mobject = self.ending_mobject
|
end_anim.mobject = self.target_mobject
|
||||||
|
|
||||||
def update(self, alpha):
|
def update(self, alpha):
|
||||||
self.start_anim.update(alpha)
|
self.start_anim.update(alpha)
|
||||||
|
|
|
@ -101,7 +101,7 @@ class Car(SVGMobject):
|
||||||
class MoveCar(ApplyMethod):
|
class MoveCar(ApplyMethod):
|
||||||
def __init__(self, car, target_point, **kwargs):
|
def __init__(self, car, target_point, **kwargs):
|
||||||
ApplyMethod.__init__(self, car.move_to, target_point, **kwargs)
|
ApplyMethod.__init__(self, car.move_to, target_point, **kwargs)
|
||||||
displacement = self.ending_mobject.get_right()-self.starting_mobject.get_right()
|
displacement = self.target_mobject.get_right()-self.starting_mobject.get_right()
|
||||||
distance = np.linalg.norm(displacement)
|
distance = np.linalg.norm(displacement)
|
||||||
tire_radius = car.get_tires()[0].get_width()/2
|
tire_radius = car.get_tires()[0].get_width()/2
|
||||||
self.total_tire_radians = -distance/tire_radius
|
self.total_tire_radians = -distance/tire_radius
|
||||||
|
|
149
eoc/chapter3.py
149
eoc/chapter3.py
|
@ -621,12 +621,21 @@ class NudgeSideLengthOfCube(Scene):
|
||||||
"pose_angle" : np.pi/12,
|
"pose_angle" : np.pi/12,
|
||||||
"pose_axis" : UP+RIGHT,
|
"pose_axis" : UP+RIGHT,
|
||||||
"small_piece_scaling_factor" : 0.7,
|
"small_piece_scaling_factor" : 0.7,
|
||||||
"is_recursing" : False,
|
"allow_recursion" : True,
|
||||||
}
|
}
|
||||||
def construct(self):
|
def construct(self):
|
||||||
|
self.states = dict()
|
||||||
|
if self.allow_recursion:
|
||||||
|
self.alt_scene = self.__class__(
|
||||||
|
skip_animations = True,
|
||||||
|
allow_recursion = False,
|
||||||
|
dx = self.alt_dx,
|
||||||
|
)
|
||||||
|
|
||||||
self.add_title()
|
self.add_title()
|
||||||
self.introduce_cube()
|
self.introduce_cube()
|
||||||
self.write_df_equation()
|
self.write_df_equation()
|
||||||
|
self.write_derivative()
|
||||||
|
|
||||||
def add_title(self):
|
def add_title(self):
|
||||||
title = TexMobject("f(x) = x^3")
|
title = TexMobject("f(x) = x^3")
|
||||||
|
@ -671,6 +680,8 @@ class NudgeSideLengthOfCube(Scene):
|
||||||
self.add(dv_pieces)
|
self.add(dv_pieces)
|
||||||
self.play(GrowFromCenter(dx_brace))
|
self.play(GrowFromCenter(dx_brace))
|
||||||
self.dither()
|
self.dither()
|
||||||
|
for piece in dv_pieces:
|
||||||
|
piece.on_cube_state = piece.copy()
|
||||||
self.play(*[
|
self.play(*[
|
||||||
ApplyMethod(
|
ApplyMethod(
|
||||||
piece.shift,
|
piece.shift,
|
||||||
|
@ -683,6 +694,7 @@ class NudgeSideLengthOfCube(Scene):
|
||||||
self.dither()
|
self.dither()
|
||||||
|
|
||||||
self.cube = cube
|
self.cube = cube
|
||||||
|
self.dx_brace = dx_brace
|
||||||
self.faces, self.bars, self.corner_cube = [
|
self.faces, self.bars, self.corner_cube = [
|
||||||
VGroup(*[
|
VGroup(*[
|
||||||
piece
|
piece
|
||||||
|
@ -713,7 +725,7 @@ class NudgeSideLengthOfCube(Scene):
|
||||||
df_equation.to_edge(UP)
|
df_equation.to_edge(UP)
|
||||||
|
|
||||||
faces_brace = Brace(faces, DOWN)
|
faces_brace = Brace(faces, DOWN)
|
||||||
faces_brace_text = faces_brace.get_text("$3x^2", "\\, dx$")
|
derivative = faces_brace.get_text("$3x^2", "\\, dx$")
|
||||||
extras_brace = Brace(VGroup(bars, corner_cube), DOWN)
|
extras_brace = Brace(VGroup(bars, corner_cube), DOWN)
|
||||||
ignore_text = extras_brace.get_text(
|
ignore_text = extras_brace.get_text(
|
||||||
"Multiple \\\\ of $dx^2$"
|
"Multiple \\\\ of $dx^2$"
|
||||||
|
@ -725,19 +737,26 @@ class NudgeSideLengthOfCube(Scene):
|
||||||
self.play(*map(Write, [df, equals]))
|
self.play(*map(Write, [df, equals]))
|
||||||
self.grab_pieces(self.faces, faces)
|
self.grab_pieces(self.faces, faces)
|
||||||
self.dither()
|
self.dither()
|
||||||
# self.shrink_dx()
|
self.shrink_dx("Faces are introduced")
|
||||||
face = self.faces[0]
|
face = self.faces[0]
|
||||||
face.save_state()
|
face.save_state()
|
||||||
self.play(face.shift, SPACE_WIDTH*RIGHT)
|
self.play(face.shift, SPACE_WIDTH*RIGHT)
|
||||||
x_squared_dx.move_to(self.faces[0])
|
x_squared_dx.next_to(face, LEFT)
|
||||||
self.play(Write(x_squared_dx, run_time = 1))
|
self.play(Write(x_squared_dx, run_time = 1))
|
||||||
for submob in x_squared_dx:
|
|
||||||
self.play(submob.highlight, RED, rate_func = there_and_back)
|
|
||||||
self.play(submob.highlight, RED, rate_func = there_and_back)
|
|
||||||
self.dither()
|
self.dither()
|
||||||
|
for submob, sides in zip(x_squared_dx, [face[0], VGroup(*face[1:])]):
|
||||||
|
self.play(
|
||||||
|
submob.highlight, RED,
|
||||||
|
sides.highlight, RED,
|
||||||
|
rate_func = there_and_back
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
self.play(
|
self.play(
|
||||||
face.restore,
|
face.restore,
|
||||||
Transform(x_squared_dx, faces_brace_text),
|
Transform(
|
||||||
|
x_squared_dx, derivative,
|
||||||
|
replace_mobject_with_target_in_scene = True
|
||||||
|
),
|
||||||
GrowFromCenter(faces_brace)
|
GrowFromCenter(faces_brace)
|
||||||
)
|
)
|
||||||
self.dither()
|
self.dither()
|
||||||
|
@ -757,6 +776,79 @@ class NudgeSideLengthOfCube(Scene):
|
||||||
])
|
])
|
||||||
self.dither()
|
self.dither()
|
||||||
|
|
||||||
|
self.df_equation = df_equation
|
||||||
|
self.derivative = derivative
|
||||||
|
|
||||||
|
def write_derivative(self):
|
||||||
|
df, equals, faces, plus1, bars, plus2, corner_cube = self.df_equation
|
||||||
|
df = df.copy()
|
||||||
|
equals = equals.copy()
|
||||||
|
df_equals = VGroup(df, equals)
|
||||||
|
|
||||||
|
derivative = self.derivative.copy()
|
||||||
|
dx = derivative[1]
|
||||||
|
|
||||||
|
extra_stuff = TexMobject("+(\\dots)", "dx^2")
|
||||||
|
dx_squared = extra_stuff[1]
|
||||||
|
|
||||||
|
derivative.generate_target()
|
||||||
|
derivative.target.shift(2*DOWN)
|
||||||
|
extra_stuff.next_to(derivative.target)
|
||||||
|
self.play(
|
||||||
|
MoveToTarget(derivative),
|
||||||
|
df_equals.next_to, derivative.target[0], LEFT,
|
||||||
|
df_equals.shift, 0.07*DOWN
|
||||||
|
)
|
||||||
|
self.play(Write(extra_stuff))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
frac_line = TexMobject("-")
|
||||||
|
frac_line.replace(df)
|
||||||
|
extra_stuff.generate_target()
|
||||||
|
extra_stuff.target.next_to(derivative[0])
|
||||||
|
frac_line2 = TexMobject("-")
|
||||||
|
frac_line2.stretch_to_fit_width(
|
||||||
|
extra_stuff.target[1].get_width()
|
||||||
|
)
|
||||||
|
frac_line2.move_to(extra_stuff.target[1])
|
||||||
|
extra_stuff.target[1].next_to(frac_line2, UP, buff = SMALL_BUFF)
|
||||||
|
dx_below_dx_squared = TexMobject("dx")
|
||||||
|
dx_below_dx_squared.next_to(frac_line2, DOWN, buff = SMALL_BUFF)
|
||||||
|
self.play(
|
||||||
|
FadeIn(frac_line),
|
||||||
|
FadeIn(frac_line2),
|
||||||
|
df.next_to, frac_line, UP, SMALL_BUFF,
|
||||||
|
dx.next_to, frac_line, DOWN, SMALL_BUFF,
|
||||||
|
MoveToTarget(extra_stuff),
|
||||||
|
Write(dx_below_dx_squared),
|
||||||
|
path_arc = -np.pi
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
inner_dx = VGroup(*dx_squared[:-1])
|
||||||
|
self.play(
|
||||||
|
FadeOut(frac_line2),
|
||||||
|
FadeOut(dx_below_dx_squared),
|
||||||
|
dx_squared[-1].highlight, BLACK,
|
||||||
|
inner_dx.next_to, extra_stuff[0], RIGHT, SMALL_BUFF
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
self.shrink_dx("Derivative is written", restore = False)
|
||||||
|
self.play(*[
|
||||||
|
ApplyMethod(mob.fade, 0.7)
|
||||||
|
for mob in extra_stuff, inner_dx
|
||||||
|
])
|
||||||
|
self.dither(2)
|
||||||
|
|
||||||
|
anims = []
|
||||||
|
for mob in list(self.faces)+list(self.bars)+list(self.corner_cube):
|
||||||
|
vect = mob.get_center()-self.cube.get_center()
|
||||||
|
anims += [
|
||||||
|
mob.shift, -(1./3)*vect
|
||||||
|
]
|
||||||
|
anims += self.dx_brace.shift, 0.7*DOWN
|
||||||
|
self.play(*anims)
|
||||||
|
self.dither()
|
||||||
|
|
||||||
def grab_pieces(self, start_pieces, end_pices, to_write = None):
|
def grab_pieces(self, start_pieces, end_pices, to_write = None):
|
||||||
for piece in start_pieces:
|
for piece in start_pieces:
|
||||||
piece.generate_target()
|
piece.generate_target()
|
||||||
|
@ -774,29 +866,38 @@ class NudgeSideLengthOfCube(Scene):
|
||||||
*added_anims
|
*added_anims
|
||||||
)
|
)
|
||||||
|
|
||||||
def shrink_dx(self):
|
def shrink_dx(self, state_name, restore = True):
|
||||||
self.mobjects_at_start_of_shrink_dx = self.get_mobjects()
|
mobjects = self.get_mobjects()
|
||||||
if self.is_recursing:
|
mobjects_with_points = [
|
||||||
|
m for m in mobjects
|
||||||
|
if m.get_num_points() > 0
|
||||||
|
]
|
||||||
|
#Alt_scene will reach this point, and save copy of self
|
||||||
|
#in states dict
|
||||||
|
self.states[state_name] = [
|
||||||
|
mob.copy() for mob in mobjects_with_points
|
||||||
|
]
|
||||||
|
if not self.allow_recursion:
|
||||||
return
|
return
|
||||||
alt_scene = self.__class__(
|
if restore:
|
||||||
dx = self.alt_dx,
|
movers = self.states[state_name]
|
||||||
skip_animations = True,
|
for mob in movers:
|
||||||
is_recursing = True
|
mob.save_state()
|
||||||
)
|
self.remove(*mobjects)
|
||||||
for mob in self.get_mobjects():
|
else:
|
||||||
mob.save_state()
|
movers = mobjects_with_points
|
||||||
self.play(*[
|
self.play(*[
|
||||||
Transform(*pair)
|
Transform(*pair)
|
||||||
for pair in zip(
|
for pair in zip(
|
||||||
self.get_mobjects(),
|
movers,
|
||||||
alt_scene.mobjects_at_start_of_shrink_dx
|
self.alt_scene.states[state_name]
|
||||||
)
|
)
|
||||||
])
|
])
|
||||||
self.dither()
|
self.dither()
|
||||||
self.play(*[
|
if restore:
|
||||||
mob.restore
|
self.play(*[m.restore for m in movers])
|
||||||
for mob in self.get_mobjects()
|
self.remove(*movers)
|
||||||
])
|
self.mobjects = mobjects
|
||||||
|
|
||||||
def get_cube(self):
|
def get_cube(self):
|
||||||
cube = self.get_prism(self.x, self.x, self.x)
|
cube = self.get_prism(self.x, self.x, self.x)
|
||||||
|
|
|
@ -16,7 +16,7 @@ from camera import Camera
|
||||||
from tk_scene import TkSceneRoot
|
from tk_scene import TkSceneRoot
|
||||||
from mobject import Mobject, VMobject
|
from mobject import Mobject, VMobject
|
||||||
from animation import Animation
|
from animation import Animation
|
||||||
from animation.transform import MoveToTarget
|
from animation.transform import MoveToTarget, Transform
|
||||||
|
|
||||||
class Scene(object):
|
class Scene(object):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
|
@ -241,6 +241,7 @@ class Scene(object):
|
||||||
def play(self, *args, **kwargs):
|
def play(self, *args, **kwargs):
|
||||||
if len(args) == 0:
|
if len(args) == 0:
|
||||||
warnings.warn("Called Scene.play with no animations")
|
warnings.warn("Called Scene.play with no animations")
|
||||||
|
return
|
||||||
if self.skip_animations:
|
if self.skip_animations:
|
||||||
kwargs["run_time"] = 0
|
kwargs["run_time"] = 0
|
||||||
|
|
||||||
|
@ -267,6 +268,10 @@ class Scene(object):
|
||||||
animation.clean_up()
|
animation.clean_up()
|
||||||
if animation.is_remover():
|
if animation.is_remover():
|
||||||
self.remove(animation.mobject)
|
self.remove(animation.mobject)
|
||||||
|
if isinstance(animation, Transform) :
|
||||||
|
if animation.replace_mobject_with_target_in_scene:
|
||||||
|
self.remove(animation.mobject)
|
||||||
|
self.add(animation.original_target_mobject)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def get_mobjects_from_last_animation(self):
|
def get_mobjects_from_last_animation(self):
|
||||||
|
|
|
@ -317,7 +317,7 @@ class PiCreatureScene(Scene):
|
||||||
last_anim = animations[-1]
|
last_anim = animations[-1]
|
||||||
if last_anim.mobject is self.pi_creature and isinstance(last_anim, Transform):
|
if last_anim.mobject is self.pi_creature and isinstance(last_anim, Transform):
|
||||||
if isinstance(animations[-1], Transform):
|
if isinstance(animations[-1], Transform):
|
||||||
animations[-1].ending_mobject.look_at(point_of_interest)
|
animations[-1].target_mobject.look_at(point_of_interest)
|
||||||
return animations
|
return animations
|
||||||
new_anim = ApplyMethod(self.pi_creature.look_at, point_of_interest)
|
new_anim = ApplyMethod(self.pi_creature.look_at, point_of_interest)
|
||||||
return list(animations) + [new_anim]
|
return list(animations) + [new_anim]
|
||||||
|
|
|
@ -587,6 +587,11 @@ class QuadraticKoch(LindenmayerCurve):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class QuadraticKochIsland(QuadraticKoch):
|
||||||
|
CONFIG = {
|
||||||
|
"axiom" : "A+A+A+A"
|
||||||
|
}
|
||||||
|
|
||||||
class StellarCurve(LindenmayerCurve):
|
class StellarCurve(LindenmayerCurve):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"start_color" : RED,
|
"start_color" : RED,
|
||||||
|
|
Loading…
Add table
Reference in a new issue