mirror of
https://github.com/3b1b/manim.git
synced 2025-08-05 16:49:03 +00:00
Merge pull request #104 from 3b1b/WindingNumber
Minor internal changes to Succession
This commit is contained in:
commit
717b3f9b80
3 changed files with 216 additions and 150 deletions
|
@ -201,33 +201,7 @@ class EquationSolver1d(GraphScene, ZoomedScene):
|
||||||
self.solveEquation()
|
self.solveEquation()
|
||||||
|
|
||||||
|
|
||||||
# TODO: Perhaps have bullets (pulses) fade out and in at ends of line, instead of jarringly
|
def rev_to_color(alpha):
|
||||||
# popping out and in?
|
|
||||||
#
|
|
||||||
# TODO: Perhaps have bullets change color corresponding to a function of their coordinates?
|
|
||||||
# This could involve some merging of functoinality with PiWalker
|
|
||||||
class LinePulser(ContinualAnimation):
|
|
||||||
def __init__(self, line, bullet_template, num_bullets, pulse_time, color_func = None, **kwargs):
|
|
||||||
self.line = line
|
|
||||||
self.num_bullets = num_bullets
|
|
||||||
self.pulse_time = pulse_time
|
|
||||||
self.bullets = [bullet_template.copy() for i in range(num_bullets)]
|
|
||||||
self.color_func = color_func
|
|
||||||
ContinualAnimation.__init__(self, VGroup(line, VGroup(*self.bullets)), **kwargs)
|
|
||||||
|
|
||||||
def update_mobject(self, dt):
|
|
||||||
alpha = self.external_time % self.pulse_time
|
|
||||||
start = self.line.get_start()
|
|
||||||
end = self.line.get_end()
|
|
||||||
for i in range(self.num_bullets):
|
|
||||||
position = interpolate(start, end,
|
|
||||||
np.true_divide((i + alpha),(self.num_bullets)))
|
|
||||||
self.bullets[i].move_to(position)
|
|
||||||
if self.color_func:
|
|
||||||
self.bullets.set_color(self.color_func(position))
|
|
||||||
|
|
||||||
|
|
||||||
def color_func(alpha):
|
|
||||||
alpha = alpha % 1
|
alpha = alpha % 1
|
||||||
colors = ["#FF0000", ORANGE, YELLOW, "#00FF00", "#0000FF", "#FF00FF"]
|
colors = ["#FF0000", ORANGE, YELLOW, "#00FF00", "#0000FF", "#FF00FF"]
|
||||||
num_colors = len(colors)
|
num_colors = len(colors)
|
||||||
|
@ -237,91 +211,6 @@ def color_func(alpha):
|
||||||
|
|
||||||
return interpolate_color(colors[start_index], colors[end_index], beta)
|
return interpolate_color(colors[start_index], colors[end_index], beta)
|
||||||
|
|
||||||
class ArrowCircleTest(Scene):
|
|
||||||
def construct(self):
|
|
||||||
circle_radius = 3
|
|
||||||
circle = Circle(radius = circle_radius, color = WHITE)
|
|
||||||
self.add(circle)
|
|
||||||
|
|
||||||
base_arrow = Arrow(circle_radius * 0.7 * RIGHT, circle_radius * 1.3 * RIGHT)
|
|
||||||
|
|
||||||
def rev_rotate(x, revs):
|
|
||||||
x.rotate(revs * TAU, about_point = ORIGIN)
|
|
||||||
x.set_color(color_func(revs))
|
|
||||||
return x
|
|
||||||
|
|
||||||
num_arrows = 8 * 3
|
|
||||||
arrows = [rev_rotate(base_arrow.copy(), (np.true_divide(i, num_arrows))) for i in range(num_arrows)]
|
|
||||||
arrows_vgroup = VGroup(*arrows)
|
|
||||||
|
|
||||||
self.play(ShowCreation(arrows_vgroup), run_time = 2.5, rate_func = None)
|
|
||||||
|
|
||||||
self.wait()
|
|
||||||
|
|
||||||
class FuncRotater(Animation):
|
|
||||||
CONFIG = {
|
|
||||||
"rotate_func" : lambda x : x # Func from alpha to revolutions
|
|
||||||
}
|
|
||||||
|
|
||||||
# Perhaps abstract this out into an "Animation updating from original object" class
|
|
||||||
def update_submobject(self, submobject, starting_submobject, alpha):
|
|
||||||
submobject.points = np.array(starting_submobject.points)
|
|
||||||
|
|
||||||
def update_mobject(self, alpha):
|
|
||||||
Animation.update_mobject(self, alpha)
|
|
||||||
angle_revs = self.rotate_func(alpha)
|
|
||||||
# We do a clockwise rotation
|
|
||||||
self.mobject.rotate(
|
|
||||||
-angle_revs * TAU,
|
|
||||||
about_point = ORIGIN
|
|
||||||
)
|
|
||||||
self.mobject.set_color(color_func(angle_revs))
|
|
||||||
|
|
||||||
class TestRotater(Scene):
|
|
||||||
def construct(self):
|
|
||||||
test_line = Line(ORIGIN, RIGHT)
|
|
||||||
self.play(FuncRotater(
|
|
||||||
test_line,
|
|
||||||
rotate_func = lambda x : x % 0.25,
|
|
||||||
run_time = 10))
|
|
||||||
|
|
||||||
# TODO: Be careful about clockwise vs. counterclockwise convention throughout!
|
|
||||||
# Make sure this is correct everywhere in resulting video.
|
|
||||||
class OdometerScene(Scene):
|
|
||||||
CONFIG = {
|
|
||||||
"rotate_func" : lambda x : np.sin(x * TAU),
|
|
||||||
"run_time" : 5,
|
|
||||||
"dashed_line_angle" : None,
|
|
||||||
"biased_display_start" : None
|
|
||||||
}
|
|
||||||
|
|
||||||
def construct(self):
|
|
||||||
radius = 1.3
|
|
||||||
circle = Circle(center = ORIGIN, radius = radius)
|
|
||||||
self.add(circle)
|
|
||||||
|
|
||||||
if self.dashed_line_angle:
|
|
||||||
dashed_line = DashedLine(ORIGIN, radius * RIGHT)
|
|
||||||
# Clockwise rotation
|
|
||||||
dashed_line.rotate(-self.dashed_line_angle * TAU, about_point = ORIGIN)
|
|
||||||
self.add(dashed_line)
|
|
||||||
|
|
||||||
num_display = DecimalNumber(0)
|
|
||||||
num_display.move_to(2 * DOWN)
|
|
||||||
|
|
||||||
display_val_bias = 0
|
|
||||||
if self.biased_display_start != None:
|
|
||||||
display_val_bias = self.biased_display_start - self.rotate_func(0)
|
|
||||||
display_func = lambda alpha : self.rotate_func(alpha) + display_val_bias
|
|
||||||
|
|
||||||
base_arrow = Arrow(ORIGIN, RIGHT, buff = 0)
|
|
||||||
|
|
||||||
self.play(
|
|
||||||
FuncRotater(base_arrow, rotate_func = self.rotate_func),
|
|
||||||
ChangingDecimal(num_display, display_func),
|
|
||||||
run_time = self.run_time,
|
|
||||||
rate_func = None)
|
|
||||||
|
|
||||||
def point_to_rev((x, y)):
|
def point_to_rev((x, y)):
|
||||||
# Warning: np.arctan2 would happily discontinuously returns the value 0 for (0, 0), due to
|
# Warning: np.arctan2 would happily discontinuously returns the value 0 for (0, 0), due to
|
||||||
# design choices in the underlying atan2 library call, but for our purposes, this is
|
# design choices in the underlying atan2 library call, but for our purposes, this is
|
||||||
|
@ -428,7 +317,7 @@ def plane_func_from_complex_func(f):
|
||||||
def point_func_from_complex_func(f):
|
def point_func_from_complex_func(f):
|
||||||
return lambda (x, y, z): complex_to_R3(f(complex(x, y)))
|
return lambda (x, y, z): complex_to_R3(f(complex(x, y)))
|
||||||
|
|
||||||
empty_animation = Animation(Mobject())
|
empty_animation = Animation(Mobject(), run_time = 0)
|
||||||
def EmptyAnimation():
|
def EmptyAnimation():
|
||||||
return empty_animation
|
return empty_animation
|
||||||
|
|
||||||
|
@ -440,13 +329,13 @@ class WalkerAnimation(Animation):
|
||||||
"coords_to_point" : None
|
"coords_to_point" : None
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, walk_func, rev_func, coords_to_point, **kwargs):
|
def __init__(self, walk_func, rev_func, coords_to_point, scale_factor, **kwargs):
|
||||||
self.walk_func = walk_func
|
self.walk_func = walk_func
|
||||||
self.rev_func = rev_func
|
self.rev_func = rev_func
|
||||||
self.coords_to_point = coords_to_point
|
self.coords_to_point = coords_to_point
|
||||||
self.compound_walker = VGroup()
|
self.compound_walker = VGroup()
|
||||||
self.compound_walker.walker = PiCreature(color = RED)
|
self.compound_walker.walker = PiCreature(color = RED)
|
||||||
self.compound_walker.walker.scale(0.35)
|
self.compound_walker.walker.scale(scale_factor)
|
||||||
self.compound_walker.arrow = Arrow(ORIGIN, RIGHT) #, buff = 0)
|
self.compound_walker.arrow = Arrow(ORIGIN, RIGHT) #, buff = 0)
|
||||||
self.compound_walker.digest_mobject_attrs()
|
self.compound_walker.digest_mobject_attrs()
|
||||||
Animation.__init__(self, self.compound_walker, **kwargs)
|
Animation.__init__(self, self.compound_walker, **kwargs)
|
||||||
|
@ -458,21 +347,60 @@ class WalkerAnimation(Animation):
|
||||||
def update_mobject(self, alpha):
|
def update_mobject(self, alpha):
|
||||||
Animation.update_mobject(self, alpha)
|
Animation.update_mobject(self, alpha)
|
||||||
cur_x, cur_y = cur_coords = self.walk_func(alpha)
|
cur_x, cur_y = cur_coords = self.walk_func(alpha)
|
||||||
self.mobject.walker.move_to(self.coords_to_point(cur_x, cur_y))
|
cur_point = self.coords_to_point(cur_x, cur_y)
|
||||||
|
self.mobject.walker.move_to(cur_point)
|
||||||
rev = self.rev_func(cur_coords)
|
rev = self.rev_func(cur_coords)
|
||||||
self.mobject.walker.set_color(color_func(rev))
|
self.mobject.walker.set_color(rev_to_color(rev))
|
||||||
self.mobject.arrow.set_color(color_func(rev))
|
self.mobject.arrow.set_color(rev_to_color(rev))
|
||||||
self.mobject.arrow.rotate(
|
self.mobject.arrow.rotate(
|
||||||
rev * TAU,
|
rev * TAU,
|
||||||
about_point = ORIGIN #self.mobject.arrow.get_start()
|
about_point = ORIGIN #self.mobject.arrow.get_start()
|
||||||
)
|
)
|
||||||
|
|
||||||
def LinearWalker(start_coords, end_coords, coords_to_point, rev_func, **kwargs):
|
def walker_animation_with_display(
|
||||||
|
walk_func,
|
||||||
|
rev_func,
|
||||||
|
coords_to_point,
|
||||||
|
number_update_func = None,
|
||||||
|
scale_factor = 0.35,
|
||||||
|
**kwargs
|
||||||
|
):
|
||||||
|
|
||||||
|
walker_anim = WalkerAnimation(
|
||||||
|
walk_func = walk_func,
|
||||||
|
rev_func = rev_func,
|
||||||
|
coords_to_point = coords_to_point,
|
||||||
|
scale_factor = scale_factor,
|
||||||
|
**kwargs)
|
||||||
|
walker = walker_anim.compound_walker.walker
|
||||||
|
|
||||||
|
if number_update_func != None:
|
||||||
|
display = DecimalNumber(0, include_background_rectangle = True)
|
||||||
|
displaycement = scale_factor * DOWN # How about that pun, eh?
|
||||||
|
display.move_to(walker.get_center() + displaycement)
|
||||||
|
display_anim = ChangingDecimal(display,
|
||||||
|
number_update_func,
|
||||||
|
tracked_mobject = walker_anim.compound_walker.walker,
|
||||||
|
**kwargs)
|
||||||
|
anim_group = AnimationGroup(walker_anim, display_anim)
|
||||||
|
return anim_group
|
||||||
|
else:
|
||||||
|
return walker_anim
|
||||||
|
|
||||||
|
def LinearWalker(
|
||||||
|
start_coords,
|
||||||
|
end_coords,
|
||||||
|
coords_to_point,
|
||||||
|
rev_func,
|
||||||
|
number_update_func = None,
|
||||||
|
**kwargs
|
||||||
|
):
|
||||||
walk_func = lambda alpha : interpolate(start_coords, end_coords, alpha)
|
walk_func = lambda alpha : interpolate(start_coords, end_coords, alpha)
|
||||||
return WalkerAnimation(
|
return walker_animation_with_display(
|
||||||
walk_func = walk_func,
|
walk_func = walk_func,
|
||||||
coords_to_point = coords_to_point,
|
coords_to_point = coords_to_point,
|
||||||
rev_func = rev_func,
|
rev_func = rev_func,
|
||||||
|
number_update_func = number_update_func,
|
||||||
**kwargs)
|
**kwargs)
|
||||||
|
|
||||||
class PiWalker(Scene):
|
class PiWalker(Scene):
|
||||||
|
@ -507,7 +435,7 @@ class PiWalker(Scene):
|
||||||
ShowCreation(Line(start_point, end_point), rate_func = None),
|
ShowCreation(Line(start_point, end_point), rate_func = None),
|
||||||
run_time = self.step_run_time)
|
run_time = self.step_run_time)
|
||||||
|
|
||||||
# TODO: Allow smooth paths instead of brekaing them up into lines, and
|
# TODO: Allow smooth paths instead of breaking them up into lines, and
|
||||||
# use point_from_proportion to get points along the way
|
# use point_from_proportion to get points along the way
|
||||||
|
|
||||||
|
|
||||||
|
@ -564,30 +492,31 @@ class EquationSolver2d(Scene):
|
||||||
self.add(num_plane)
|
self.add(num_plane)
|
||||||
|
|
||||||
rev_func = lambda p : point_to_rev(self.func(p))
|
rev_func = lambda p : point_to_rev(self.func(p))
|
||||||
|
clockwise_rev_func = lambda p : -rev_func(p)
|
||||||
|
|
||||||
def Animate2dSolver(cur_depth, rect, dim_to_split):
|
def Animate2dSolver(cur_depth, rect, dim_to_split):
|
||||||
|
print "Solver at depth: " + str(cur_depth)
|
||||||
|
|
||||||
if cur_depth >= self.num_iterations:
|
if cur_depth >= self.num_iterations:
|
||||||
return EmptyAnimation()
|
return EmptyAnimation()
|
||||||
|
|
||||||
def draw_line_return_wind(start, end, start_wind):
|
def draw_line_return_wind(start, end, start_wind):
|
||||||
alpha_winder = make_alpha_winder(rev_func, start, end, self.num_checkpoints)
|
alpha_winder = make_alpha_winder(clockwise_rev_func, start, end, self.num_checkpoints)
|
||||||
a0 = alpha_winder(0)
|
a0 = alpha_winder(0)
|
||||||
rebased_winder = lambda alpha: alpha_winder(alpha) - a0 + start_wind
|
rebased_winder = lambda alpha: alpha_winder(alpha) - a0 + start_wind
|
||||||
flashing_line = Line(num_plane.coords_to_point(*start), num_plane.coords_to_point(*end),
|
thin_line = Line(num_plane.coords_to_point(*start), num_plane.coords_to_point(*end),
|
||||||
stroke_width = 5,
|
stroke_width = 2,
|
||||||
color = RED)
|
color = RED)
|
||||||
thin_line = flashing_line.copy()
|
|
||||||
thin_line.set_stroke(width = 1)
|
|
||||||
walker_anim = LinearWalker(
|
walker_anim = LinearWalker(
|
||||||
start_coords = start,
|
start_coords = start,
|
||||||
end_coords = end,
|
end_coords = end,
|
||||||
coords_to_point = num_plane.coords_to_point,
|
coords_to_point = num_plane.coords_to_point,
|
||||||
rev_func = rev_func,
|
rev_func = rev_func,
|
||||||
|
number_update_func = rebased_winder,
|
||||||
remover = True
|
remover = True
|
||||||
)
|
)
|
||||||
line_draw_anim = AnimationGroup(
|
line_draw_anim = AnimationGroup(
|
||||||
ShowCreation(thin_line),
|
ShowCreation(thin_line),
|
||||||
#ShowPassingFlash(flashing_line),
|
|
||||||
walker_anim,
|
walker_anim,
|
||||||
rate_func = None)
|
rate_func = None)
|
||||||
anim = line_draw_anim
|
anim = line_draw_anim
|
||||||
|
@ -636,6 +565,7 @@ class EquationSolver2d(Scene):
|
||||||
return Succession(anim,
|
return Succession(anim,
|
||||||
ShowCreation(mid_line),
|
ShowCreation(mid_line),
|
||||||
# FadeOut(mid_line), # TODO: Can change timing so this fades out at just the time it would be overdrawn
|
# FadeOut(mid_line), # TODO: Can change timing so this fades out at just the time it would be overdrawn
|
||||||
|
# TODO: Investigate weirdness with changing z buffer order on mid_line vs. rectangle lines
|
||||||
AnimationGroup(*sub_anims)
|
AnimationGroup(*sub_anims)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -649,16 +579,133 @@ class EquationSolver2d(Scene):
|
||||||
|
|
||||||
rect = RectangleData(x_interval, y_interval)
|
rect = RectangleData(x_interval, y_interval)
|
||||||
|
|
||||||
|
print "Starting to compute anim"
|
||||||
|
|
||||||
anim = Animate2dSolver(
|
anim = Animate2dSolver(
|
||||||
cur_depth = 0,
|
cur_depth = 0,
|
||||||
rect = rect,
|
rect = rect,
|
||||||
dim_to_split = 0,
|
dim_to_split = 0,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
print "Done computing anim"
|
||||||
|
|
||||||
self.play(anim)
|
self.play(anim)
|
||||||
|
|
||||||
self.wait()
|
self.wait()
|
||||||
|
|
||||||
|
# TODO: Perhaps have bullets (pulses) fade out and in at ends of line, instead of jarringly
|
||||||
|
# popping out and in?
|
||||||
|
#
|
||||||
|
# TODO: Perhaps have bullets change color corresponding to a function of their coordinates?
|
||||||
|
# This could involve some merging of functoinality with PiWalker
|
||||||
|
class LinePulser(ContinualAnimation):
|
||||||
|
def __init__(self, line, bullet_template, num_bullets, pulse_time, output_func = None, **kwargs):
|
||||||
|
self.line = line
|
||||||
|
self.num_bullets = num_bullets
|
||||||
|
self.pulse_time = pulse_time
|
||||||
|
self.bullets = [bullet_template.copy() for i in range(num_bullets)]
|
||||||
|
self.output_func = output_func
|
||||||
|
ContinualAnimation.__init__(self, VGroup(line, VGroup(*self.bullets)), **kwargs)
|
||||||
|
|
||||||
|
def update_mobject(self, dt):
|
||||||
|
alpha = self.external_time % self.pulse_time
|
||||||
|
start = self.line.get_start()
|
||||||
|
end = self.line.get_end()
|
||||||
|
for i in range(self.num_bullets):
|
||||||
|
position = interpolate(start, end,
|
||||||
|
np.true_divide((i + alpha),(self.num_bullets)))
|
||||||
|
self.bullets[i].move_to(position)
|
||||||
|
if self.output_func:
|
||||||
|
position_2d = (position[0], position[1])
|
||||||
|
rev = point_to_rev(self.output_func(position_2d))
|
||||||
|
color = rev_to_color(rev)
|
||||||
|
self.bullets[i].set_color(color)
|
||||||
|
|
||||||
|
class ArrowCircleTest(Scene):
|
||||||
|
def construct(self):
|
||||||
|
circle_radius = 3
|
||||||
|
circle = Circle(radius = circle_radius, color = WHITE)
|
||||||
|
self.add(circle)
|
||||||
|
|
||||||
|
base_arrow = Arrow(circle_radius * 0.7 * RIGHT, circle_radius * 1.3 * RIGHT)
|
||||||
|
|
||||||
|
def rev_rotate(x, revs):
|
||||||
|
x.rotate(revs * TAU, about_point = ORIGIN)
|
||||||
|
x.set_color(rev_to_color(revs))
|
||||||
|
return x
|
||||||
|
|
||||||
|
num_arrows = 8 * 3
|
||||||
|
arrows = [rev_rotate(base_arrow.copy(), (np.true_divide(i, num_arrows))) for i in range(num_arrows)]
|
||||||
|
arrows_vgroup = VGroup(*arrows)
|
||||||
|
|
||||||
|
self.play(ShowCreation(arrows_vgroup), run_time = 2.5, rate_func = None)
|
||||||
|
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
class FuncRotater(Animation):
|
||||||
|
CONFIG = {
|
||||||
|
"rotate_func" : lambda x : x # Func from alpha to revolutions
|
||||||
|
}
|
||||||
|
|
||||||
|
# Perhaps abstract this out into an "Animation updating from original object" class
|
||||||
|
def update_submobject(self, submobject, starting_submobject, alpha):
|
||||||
|
submobject.points = np.array(starting_submobject.points)
|
||||||
|
|
||||||
|
def update_mobject(self, alpha):
|
||||||
|
Animation.update_mobject(self, alpha)
|
||||||
|
angle_revs = self.rotate_func(alpha)
|
||||||
|
# We do a clockwise rotation
|
||||||
|
self.mobject.rotate(
|
||||||
|
-angle_revs * TAU,
|
||||||
|
about_point = ORIGIN
|
||||||
|
)
|
||||||
|
self.mobject.set_color(rev_to_color(angle_revs))
|
||||||
|
|
||||||
|
class TestRotater(Scene):
|
||||||
|
def construct(self):
|
||||||
|
test_line = Line(ORIGIN, RIGHT)
|
||||||
|
self.play(FuncRotater(
|
||||||
|
test_line,
|
||||||
|
rotate_func = lambda x : x % 0.25,
|
||||||
|
run_time = 10))
|
||||||
|
|
||||||
|
# TODO: Be careful about clockwise vs. counterclockwise convention throughout!
|
||||||
|
# Make sure this is correct everywhere in resulting video.
|
||||||
|
class OdometerScene(Scene):
|
||||||
|
CONFIG = {
|
||||||
|
"rotate_func" : lambda x : np.sin(x * TAU),
|
||||||
|
"run_time" : 5,
|
||||||
|
"dashed_line_angle" : None,
|
||||||
|
"biased_display_start" : None
|
||||||
|
}
|
||||||
|
|
||||||
|
def construct(self):
|
||||||
|
radius = 1.3
|
||||||
|
circle = Circle(center = ORIGIN, radius = radius)
|
||||||
|
self.add(circle)
|
||||||
|
|
||||||
|
if self.dashed_line_angle:
|
||||||
|
dashed_line = DashedLine(ORIGIN, radius * RIGHT)
|
||||||
|
# Clockwise rotation
|
||||||
|
dashed_line.rotate(-self.dashed_line_angle * TAU, about_point = ORIGIN)
|
||||||
|
self.add(dashed_line)
|
||||||
|
|
||||||
|
num_display = DecimalNumber(0, include_background_rectangle = True)
|
||||||
|
num_display.move_to(2 * DOWN)
|
||||||
|
|
||||||
|
display_val_bias = 0
|
||||||
|
if self.biased_display_start != None:
|
||||||
|
display_val_bias = self.biased_display_start - self.rotate_func(0)
|
||||||
|
display_func = lambda alpha : self.rotate_func(alpha) + display_val_bias
|
||||||
|
|
||||||
|
base_arrow = Arrow(ORIGIN, RIGHT, buff = 0)
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
FuncRotater(base_arrow, rotate_func = self.rotate_func),
|
||||||
|
ChangingDecimal(num_display, display_func),
|
||||||
|
run_time = self.run_time,
|
||||||
|
rate_func = None)
|
||||||
|
|
||||||
#############
|
#############
|
||||||
# Above are mostly general tools; here, we list, in order, finished or near-finished scenes
|
# Above are mostly general tools; here, we list, in order, finished or near-finished scenes
|
||||||
|
|
||||||
|
@ -853,10 +900,24 @@ class Initial2dFuncSceneWithoutMorphing(Scene):
|
||||||
# creature from previous scene, then place it as a simultaneous inset with Premiere)
|
# creature from previous scene, then place it as a simultaneous inset with Premiere)
|
||||||
|
|
||||||
class LoopSplitScene(Scene):
|
class LoopSplitScene(Scene):
|
||||||
|
CONFIG = {
|
||||||
|
"output_func" : plane_poly_with_roots((1, 1))
|
||||||
|
}
|
||||||
|
|
||||||
def PulsedLine(self, start, end, bullet_template, num_bullets = 4, pulse_time = 1, **kwargs):
|
def PulsedLine(self,
|
||||||
|
start, end,
|
||||||
|
bullet_template,
|
||||||
|
num_bullets = 4,
|
||||||
|
pulse_time = 1,
|
||||||
|
**kwargs):
|
||||||
line = Line(start, end, **kwargs)
|
line = Line(start, end, **kwargs)
|
||||||
anim = LinePulser(line, bullet_template, num_bullets, pulse_time, **kwargs)
|
anim = LinePulser(
|
||||||
|
line = line,
|
||||||
|
bullet_template = bullet_template,
|
||||||
|
num_bullets = num_bullets,
|
||||||
|
pulse_time = pulse_time,
|
||||||
|
output_func = self.output_func,
|
||||||
|
**kwargs)
|
||||||
return [VGroup(line, *anim.bullets), anim]
|
return [VGroup(line, *anim.bullets), anim]
|
||||||
|
|
||||||
def construct(self):
|
def construct(self):
|
||||||
|
@ -978,8 +1039,8 @@ class LoopSplitSceneMapped(LoopSplitScene):
|
||||||
# to illustrate relation between degree and large-scale winding number
|
# to illustrate relation between degree and large-scale winding number
|
||||||
class FundThmAlg(EquationSolver2d):
|
class FundThmAlg(EquationSolver2d):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"func" : plane_poly_with_roots((1, 2), (-1, 2.5), (-1, 2.5)),
|
"func" : plane_poly_with_roots((1, 2), (-1, 1.5), (-1, 1.5)),
|
||||||
"num_iterations" : 1,
|
"num_iterations" : 10,
|
||||||
}
|
}
|
||||||
|
|
||||||
# TODO: Borsuk-Ulam visuals
|
# TODO: Borsuk-Ulam visuals
|
||||||
|
@ -1010,6 +1071,7 @@ class DiffOdometer(OdometerScene):
|
||||||
}
|
}
|
||||||
|
|
||||||
# TODO: Brouwer's fixed point theorem visuals
|
# TODO: Brouwer's fixed point theorem visuals
|
||||||
|
# class BFTScene(Scene):
|
||||||
|
|
||||||
# TODO: Pi creatures wide-eyed in amazement
|
# TODO: Pi creatures wide-eyed in amazement
|
||||||
|
|
||||||
|
@ -1023,11 +1085,6 @@ class DiffOdometer(OdometerScene):
|
||||||
|
|
||||||
# Writing new Pi walker scenes by parametrizing general template
|
# Writing new Pi walker scenes by parametrizing general template
|
||||||
|
|
||||||
# Generalizing Pi walker stuff to make bullets on pulsing lines change colors dynamically according to
|
|
||||||
# function traced out
|
|
||||||
|
|
||||||
# Debugging Pi walker stuff added to EquationSolver2d
|
|
||||||
|
|
||||||
# ----
|
# ----
|
||||||
|
|
||||||
# Pi creature emotion stuff
|
# Pi creature emotion stuff
|
||||||
|
@ -1038,6 +1095,7 @@ class DiffOdometer(OdometerScene):
|
||||||
|
|
||||||
# Domain coloring
|
# Domain coloring
|
||||||
|
|
||||||
# TODO: Ask about tracked mobject, which is probably very useful for our animations
|
# TODO: Add to camera an option for low-quality background than other rendering, helpful
|
||||||
|
# for previews
|
||||||
|
|
||||||
# FIN
|
# FIN
|
||||||
|
|
|
@ -403,12 +403,17 @@ class Succession(Animation):
|
||||||
for anim in animations:
|
for anim in animations:
|
||||||
anim.update(0)
|
anim.update(0)
|
||||||
|
|
||||||
|
animations = filter (lambda x : x.run_time != 0, animations)
|
||||||
|
|
||||||
self.run_times = [anim.run_time for anim in animations]
|
self.run_times = [anim.run_time for anim in animations]
|
||||||
if "run_time" in kwargs:
|
if "run_time" in kwargs:
|
||||||
run_time = kwargs.pop("run_time")
|
run_time = kwargs.pop("run_time")
|
||||||
else:
|
else:
|
||||||
run_time = sum(self.run_times)
|
run_time = sum(self.run_times)
|
||||||
self.num_anims = len(animations) #TODO: If this is zero, some special handling below
|
self.num_anims = len(animations)
|
||||||
|
if self.num_anims == 0:
|
||||||
|
# TODO: Handle this; it should be easy enough, but requires some special cases below
|
||||||
|
print "Warning! Successions with zero animations are not currently handled!"
|
||||||
self.animations = animations
|
self.animations = animations
|
||||||
#Have to keep track of this run_time, because Scene.play
|
#Have to keep track of this run_time, because Scene.play
|
||||||
#might very well mess with it.
|
#might very well mess with it.
|
||||||
|
@ -429,22 +434,25 @@ class Succession(Animation):
|
||||||
|
|
||||||
self.current_alpha = 0
|
self.current_alpha = 0
|
||||||
self.current_anim_index = 0 #TODO: What if self.num_anims == 0?
|
self.current_anim_index = 0 #TODO: What if self.num_anims == 0?
|
||||||
|
self.mobject = self.scene_mobjects_at_time[0]
|
||||||
|
self.mobject.add(self.animations[0].mobject)
|
||||||
|
|
||||||
self.mobject = Group()
|
|
||||||
self.jump_to_start_of_anim(0)
|
|
||||||
Animation.__init__(self, self.mobject, run_time = run_time, **kwargs)
|
Animation.__init__(self, self.mobject, run_time = run_time, **kwargs)
|
||||||
|
|
||||||
|
# Beware: This does NOT take care of updating the subanimation to 0
|
||||||
|
# This was important to avoid a pernicious possibility in which subanimations were called
|
||||||
|
# with update(0) twice, which could in turn call a sub-Succession with update(0) four times,
|
||||||
|
# continuing exponentially
|
||||||
def jump_to_start_of_anim(self, index):
|
def jump_to_start_of_anim(self, index):
|
||||||
|
if index != self.current_anim_index:
|
||||||
|
self.mobject.remove(*self.mobject.submobjects) # Should probably have a cleaner "remove_all" method...
|
||||||
|
self.mobject.add(self.animations[index].mobject)
|
||||||
|
for m in self.scene_mobjects_at_time[index].submobjects:
|
||||||
|
self.mobject.add(m)
|
||||||
|
|
||||||
self.current_anim_index = index
|
self.current_anim_index = index
|
||||||
self.current_alpha = self.critical_alphas[index]
|
self.current_alpha = self.critical_alphas[index]
|
||||||
|
|
||||||
self.mobject.remove(*self.mobject.submobjects) # Should probably have a cleaner "remove_all" method...
|
|
||||||
self.mobject.add(self.animations[index].mobject)
|
|
||||||
for m in self.scene_mobjects_at_time[index].submobjects:
|
|
||||||
self.mobject.add(m)
|
|
||||||
|
|
||||||
self.animations[index].update(0)
|
|
||||||
|
|
||||||
def update_mobject(self, alpha):
|
def update_mobject(self, alpha):
|
||||||
i = 0
|
i = 0
|
||||||
while self.critical_alphas[i + 1] < alpha:
|
while self.critical_alphas[i + 1] < alpha:
|
||||||
|
|
|
@ -385,12 +385,12 @@ class Camera(object):
|
||||||
def get_points_of_all_pixels(self):
|
def get_points_of_all_pixels(self):
|
||||||
"""
|
"""
|
||||||
Returns an array a such that a[i, j] gives the spatial
|
Returns an array a such that a[i, j] gives the spatial
|
||||||
coordsinates associated with the pixel self.pixel_array[i, j]
|
coordinates associated with the pixel self.pixel_array[i, j]
|
||||||
"""
|
"""
|
||||||
shape = self.pixel_array.shape
|
shape = self.pixel_array.shape
|
||||||
indices = np.indices(shape[:2], dtype = 'float64')
|
indices = np.indices(shape[:2], dtype = 'float64')
|
||||||
all_point_coords = np.zeros((shape[0], shape[1], 3))
|
all_point_coords = np.zeros((shape[0], shape[1], 3))
|
||||||
for i, space_dim in enumerate([SPACE_WIDTH, SPACE_HEIGHT]):
|
for i, space_dim in enumerate([SPACE_HEIGHT, SPACE_WIDTH]):
|
||||||
all_point_coords[:,:,i] = \
|
all_point_coords[:,:,i] = \
|
||||||
indices[i,:,:]*2*space_dim/shape[i] - space_dim
|
indices[i,:,:]*2*space_dim/shape[i] - space_dim
|
||||||
return all_point_coords
|
return all_point_coords
|
||||||
|
@ -411,7 +411,7 @@ class Camera(object):
|
||||||
lambda p : float_rgba_to_int_rgba(point_to_rgba_func(p)),
|
lambda p : float_rgba_to_int_rgba(point_to_rgba_func(p)),
|
||||||
2, points_of_all_pixels
|
2, points_of_all_pixels
|
||||||
))
|
))
|
||||||
self.reset()
|
self.reset() # Perhaps this really belongs in set_background?
|
||||||
|
|
||||||
|
|
||||||
class MovingCamera(Camera):
|
class MovingCamera(Camera):
|
||||||
|
|
Loading…
Add table
Reference in a new issue