mirror of
https://github.com/3b1b/manim.git
synced 2025-09-19 04:41:56 +00:00
Merge branch 'master' into basel
This commit is contained in:
commit
b7bbc75b98
4 changed files with 95 additions and 21 deletions
|
@ -387,7 +387,7 @@ class AddingPureFrequencies(PiCreatureScene):
|
||||||
buff = 0,
|
buff = 0,
|
||||||
)
|
)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def stack_v_lines(self, x, lines):
|
def stack_v_lines(self, x, lines):
|
||||||
point = self.axes.coords_to_point(x, self.equilibrium_height)
|
point = self.axes.coords_to_point(x, self.equilibrium_height)
|
||||||
A_line, D_line = lines
|
A_line, D_line = lines
|
||||||
|
@ -911,8 +911,8 @@ class FourierMachineScene(Scene):
|
||||||
self.remove(v_line.polarized_mobject)
|
self.remove(v_line.polarized_mobject)
|
||||||
self.play(FadeOut(VGroup(v_line, v_line.polarized_mobject)))
|
self.play(FadeOut(VGroup(v_line, v_line.polarized_mobject)))
|
||||||
|
|
||||||
def get_v_lines_indicating_periods(self, freq, n_lines = 10):
|
def get_v_lines_indicating_periods(self, freq, n_lines = 20):
|
||||||
period = np.divide(1., freq)
|
period = np.divide(1., max(freq, 0.01))
|
||||||
v_lines = VGroup(*[
|
v_lines = VGroup(*[
|
||||||
DashedLine(ORIGIN, 1.5*UP).move_to(
|
DashedLine(ORIGIN, 1.5*UP).move_to(
|
||||||
self.time_axes.coords_to_point(n*period, 0),
|
self.time_axes.coords_to_point(n*period, 0),
|
||||||
|
@ -923,6 +923,17 @@ class FourierMachineScene(Scene):
|
||||||
v_lines.set_stroke(LIGHT_GREY)
|
v_lines.set_stroke(LIGHT_GREY)
|
||||||
return v_lines
|
return v_lines
|
||||||
|
|
||||||
|
def get_period_v_lines_update_anim(self):
|
||||||
|
def update_v_lines(v_lines):
|
||||||
|
freq = self.graph.polarized_mobject.frequency
|
||||||
|
Transform(
|
||||||
|
v_lines,
|
||||||
|
self.get_v_lines_indicating_periods(freq)
|
||||||
|
).update(1)
|
||||||
|
return UpdateFromFunc(
|
||||||
|
self.v_lines_indicating_periods, update_v_lines
|
||||||
|
)
|
||||||
|
|
||||||
class WrapCosineGraphAroundCircle(FourierMachineScene):
|
class WrapCosineGraphAroundCircle(FourierMachineScene):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"initial_winding_frequency" : 0.5,
|
"initial_winding_frequency" : 0.5,
|
||||||
|
@ -1099,8 +1110,6 @@ class DrawFrequencyPlot(WrapCosineGraphAroundCircle, PiCreatureScene):
|
||||||
"center_of_mass_color" : RED,
|
"center_of_mass_color" : RED,
|
||||||
}
|
}
|
||||||
def construct(self):
|
def construct(self):
|
||||||
self.force_skipping()
|
|
||||||
|
|
||||||
self.remove(self.pi_creature)
|
self.remove(self.pi_creature)
|
||||||
self.setup_graph()
|
self.setup_graph()
|
||||||
# self.indicate_weight_of_wire()
|
# self.indicate_weight_of_wire()
|
||||||
|
@ -1108,6 +1117,8 @@ class DrawFrequencyPlot(WrapCosineGraphAroundCircle, PiCreatureScene):
|
||||||
# self.change_to_various_frequencies()
|
# self.change_to_various_frequencies()
|
||||||
self.introduce_frequency_plot()
|
self.introduce_frequency_plot()
|
||||||
self.draw_full_frequency_plot()
|
self.draw_full_frequency_plot()
|
||||||
|
self.recap_objects_on_screen()
|
||||||
|
self.lower_graph()
|
||||||
self.label_as_almost_fourier()
|
self.label_as_almost_fourier()
|
||||||
|
|
||||||
def setup_graph(self):
|
def setup_graph(self):
|
||||||
|
@ -1219,7 +1230,6 @@ class DrawFrequencyPlot(WrapCosineGraphAroundCircle, PiCreatureScene):
|
||||||
t_min = 0, t_max = TAU,
|
t_min = 0, t_max = TAU,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.revert_to_original_skipping_status()
|
|
||||||
self.play(
|
self.play(
|
||||||
wps_label.move_to, self.circle_plane.get_top(),
|
wps_label.move_to, self.circle_plane.get_top(),
|
||||||
com_label.move_to, self.circle_plane, DOWN,
|
com_label.move_to, self.circle_plane, DOWN,
|
||||||
|
@ -1235,14 +1245,58 @@ class DrawFrequencyPlot(WrapCosineGraphAroundCircle, PiCreatureScene):
|
||||||
))
|
))
|
||||||
self.wait()
|
self.wait()
|
||||||
|
|
||||||
|
|
||||||
def draw_full_frequency_plot(self):
|
def draw_full_frequency_plot(self):
|
||||||
graph = self.graph
|
graph = self.graph
|
||||||
fourier_graph = self.get_fourier_transform_graph(graph)
|
fourier_graph = self.get_fourier_transform_graph(graph)
|
||||||
|
fourier_graph.save_state()
|
||||||
|
v_line = DashedLine(
|
||||||
|
self.frequency_axes.coords_to_point(0, 0),
|
||||||
|
self.frequency_axes.coords_to_point(0, 1),
|
||||||
|
stroke_width = 6,
|
||||||
|
color = fourier_graph.get_color()
|
||||||
|
)
|
||||||
|
dot = Dot(color = fourier_graph.get_color())
|
||||||
|
def update_dot(dot):
|
||||||
|
f = self.graph.polarized_mobject.frequency
|
||||||
|
dot.move_to(self.frequency_axes.input_to_graph_point(
|
||||||
|
f, fourier_graph
|
||||||
|
))
|
||||||
|
dot_update_anim = UpdateFromFunc(dot, update_dot)
|
||||||
|
|
||||||
|
|
||||||
self.revert_to_original_skipping_status()
|
|
||||||
self.change_frequency(0.0)
|
self.change_frequency(0.0)
|
||||||
|
dot_update_anim.update(0)
|
||||||
|
self.wait()
|
||||||
|
self.play(ShowCreation(v_line))
|
||||||
|
self.play(GrowFromCenter(dot), FadeOut(v_line))
|
||||||
|
f_max = int(self.frequency_axes.x_max)
|
||||||
|
for freq in range(1, f_max+1):
|
||||||
|
fourier_graph.restore()
|
||||||
|
self.change_frequency(
|
||||||
|
freq,
|
||||||
|
added_anims = [
|
||||||
|
ShowCreation(
|
||||||
|
fourier_graph,
|
||||||
|
rate_func = lambda t : interpolate(
|
||||||
|
(freq-1.)/f_max,
|
||||||
|
float(freq)/f_max,
|
||||||
|
smooth(t)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
dot_update_anim
|
||||||
|
],
|
||||||
|
run_time = 5,
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
self.play(FadeOut(dot))
|
||||||
|
self.fourier_graph = fourier_graph
|
||||||
|
|
||||||
|
def recap_objects_on_screen(self):
|
||||||
|
rect = FullScreenFadeRectangle()
|
||||||
|
|
||||||
|
self.play(FadeIn(rect))
|
||||||
|
|
||||||
|
def lower_graph(self):
|
||||||
|
pass
|
||||||
|
|
||||||
def label_as_almost_fourier(self):
|
def label_as_almost_fourier(self):
|
||||||
pass
|
pass
|
||||||
|
@ -1262,20 +1316,19 @@ class DrawFrequencyPlot(WrapCosineGraphAroundCircle, PiCreatureScene):
|
||||||
|
|
||||||
def change_frequency(self, new_freq, **kwargs):
|
def change_frequency(self, new_freq, **kwargs):
|
||||||
kwargs["run_time"] = kwargs.get("run_time", 3)
|
kwargs["run_time"] = kwargs.get("run_time", 3)
|
||||||
|
added_anims = kwargs.get("added_anims", [])
|
||||||
freq_label = filter(
|
freq_label = filter(
|
||||||
lambda sm : isinstance(sm, DecimalNumber),
|
lambda sm : isinstance(sm, DecimalNumber),
|
||||||
self.winding_freq_label
|
self.winding_freq_label
|
||||||
)[0]
|
)[0]
|
||||||
anims = [
|
anims = [
|
||||||
Transform(
|
|
||||||
self.v_lines_indicating_periods,
|
|
||||||
self.get_v_lines_indicating_periods(new_freq)
|
|
||||||
),
|
|
||||||
ChangeDecimalToValue(freq_label, new_freq),
|
ChangeDecimalToValue(freq_label, new_freq),
|
||||||
self.get_frequency_change_animation(
|
self.get_frequency_change_animation(
|
||||||
self.graph, new_freq
|
self.graph, new_freq
|
||||||
),
|
),
|
||||||
|
self.get_period_v_lines_update_anim(),
|
||||||
]
|
]
|
||||||
|
anims += added_anims
|
||||||
#TODO, conditionals for center of mass
|
#TODO, conditionals for center of mass
|
||||||
if hasattr(self, "center_of_mass_dot"):
|
if hasattr(self, "center_of_mass_dot"):
|
||||||
anims.append(self.center_of_mass_dot_anim)
|
anims.append(self.center_of_mass_dot_anim)
|
||||||
|
|
|
@ -94,16 +94,23 @@ class AmbientMovement(ContinualAnimation):
|
||||||
self.mobject.shift(dt*self.rate*self.direction)
|
self.mobject.shift(dt*self.rate*self.direction)
|
||||||
|
|
||||||
class ContinualUpdateFromFunc(ContinualAnimation):
|
class ContinualUpdateFromFunc(ContinualAnimation):
|
||||||
|
CONFIG = {
|
||||||
|
"function_depends_on_dt" : False
|
||||||
|
}
|
||||||
def __init__(self, mobject, func, **kwargs):
|
def __init__(self, mobject, func, **kwargs):
|
||||||
self.func = func
|
self.func = func
|
||||||
self.func_arg_count = func.func_code.co_argcount
|
|
||||||
if self.func_arg_count > 2:
|
|
||||||
raise Exception("ContinualUpdateFromFunc function must take 1 or 2 args")
|
|
||||||
ContinualAnimation.__init__(self, mobject, **kwargs)
|
ContinualAnimation.__init__(self, mobject, **kwargs)
|
||||||
|
|
||||||
def update_mobject(self, dt):
|
def update_mobject(self, dt):
|
||||||
args = (self.mobject, dt)
|
if self.function_depends_on_dt:
|
||||||
self.func(*args[:self.func_arg_count])
|
self.func(self.mobject, dt)
|
||||||
|
else:
|
||||||
|
self.func(self.mobject)
|
||||||
|
|
||||||
|
class ContinualUpdateFromTimeFunc(ContinualUpdateFromFunc):
|
||||||
|
CONFIG = {
|
||||||
|
"function_depends_on_dt" : True
|
||||||
|
}
|
||||||
|
|
||||||
class ContinualMaintainPositionRelativeTo(ContinualAnimation):
|
class ContinualMaintainPositionRelativeTo(ContinualAnimation):
|
||||||
# TODO: Possibly reimplement using CycleAnimation?
|
# TODO: Possibly reimplement using CycleAnimation?
|
||||||
|
|
|
@ -66,6 +66,7 @@ def get_configuration():
|
||||||
for short_arg, long_arg in optional_args:
|
for short_arg, long_arg in optional_args:
|
||||||
parser.add_argument(short_arg, long_arg, action = "store_true")
|
parser.add_argument(short_arg, long_arg, action = "store_true")
|
||||||
parser.add_argument("-o", "--output_name")
|
parser.add_argument("-o", "--output_name")
|
||||||
|
parser.add_argument("-n", "--skip_to_animation_number")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
except argparse.ArgumentError as err:
|
except argparse.ArgumentError as err:
|
||||||
print(str(err))
|
print(str(err))
|
||||||
|
@ -85,6 +86,7 @@ def get_configuration():
|
||||||
"quiet" : args.quiet or args.write_all,
|
"quiet" : args.quiet or args.write_all,
|
||||||
"write_all" : args.write_all,
|
"write_all" : args.write_all,
|
||||||
"output_name" : args.output_name,
|
"output_name" : args.output_name,
|
||||||
|
"skip_to_animation_number" : args.skip_to_animation_number,
|
||||||
}
|
}
|
||||||
if args.low_quality or args.preview:
|
if args.low_quality or args.preview:
|
||||||
config["camera_config"] = LOW_QUALITY_CAMERA_CONFIG
|
config["camera_config"] = LOW_QUALITY_CAMERA_CONFIG
|
||||||
|
@ -96,12 +98,18 @@ def get_configuration():
|
||||||
config["camera_config"] = PRODUCTION_QUALITY_CAMERA_CONFIG
|
config["camera_config"] = PRODUCTION_QUALITY_CAMERA_CONFIG
|
||||||
config["frame_duration"] = PRODUCTION_QUALITY_FRAME_DURATION
|
config["frame_duration"] = PRODUCTION_QUALITY_FRAME_DURATION
|
||||||
|
|
||||||
|
stan = config["skip_to_animation_number"]
|
||||||
|
if stan is not None:
|
||||||
|
config["skip_to_animation_number"] = int(stan)
|
||||||
|
|
||||||
#By default, write to file
|
#By default, write to file
|
||||||
actions = ["write_to_movie", "preview", "show_last_frame"]
|
actions = ["write_to_movie", "preview", "show_last_frame"]
|
||||||
if not any([config[key] for key in actions]):
|
if not any([config[key] for key in actions]):
|
||||||
config["write_to_movie"] = True
|
config["write_to_movie"] = True
|
||||||
config["skip_animations"] = config["show_last_frame"] and not config["write_to_movie"]
|
config["skip_animations"] = any([
|
||||||
|
config["show_last_frame"] and not config["write_to_movie"],
|
||||||
|
config["skip_to_animation_number"],
|
||||||
|
])
|
||||||
return config
|
return config
|
||||||
|
|
||||||
def handle_scene(scene, **config):
|
def handle_scene(scene, **config):
|
||||||
|
@ -203,7 +211,8 @@ def main():
|
||||||
"write_to_movie",
|
"write_to_movie",
|
||||||
"save_frames",
|
"save_frames",
|
||||||
"output_directory",
|
"output_directory",
|
||||||
"save_pngs"
|
"save_pngs",
|
||||||
|
"skip_to_animation_number",
|
||||||
]
|
]
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ class Scene(object):
|
||||||
"name" : None,
|
"name" : None,
|
||||||
"always_continually_update" : False,
|
"always_continually_update" : False,
|
||||||
"random_seed" : 0,
|
"random_seed" : 0,
|
||||||
|
"skip_to_animation_number" : None,
|
||||||
}
|
}
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
digest_config(self, kwargs)
|
digest_config(self, kwargs)
|
||||||
|
@ -59,6 +60,7 @@ class Scene(object):
|
||||||
self.construct(*self.construct_args)
|
self.construct(*self.construct_args)
|
||||||
if self.write_to_movie:
|
if self.write_to_movie:
|
||||||
self.close_movie_pipe()
|
self.close_movie_pipe()
|
||||||
|
print("Played a total of %d animations"%self.num_plays)
|
||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
"""
|
"""
|
||||||
|
@ -389,6 +391,9 @@ class Scene(object):
|
||||||
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
|
return
|
||||||
|
if self.skip_to_animation_number:
|
||||||
|
if self.num_plays + 1 == self.skip_to_animation_number:
|
||||||
|
self.skip_animations = False
|
||||||
if self.skip_animations:
|
if self.skip_animations:
|
||||||
kwargs["run_time"] = 0
|
kwargs["run_time"] = 0
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue