Merge branch 'master' into basel

This commit is contained in:
Ben Hambrecht 2018-01-19 13:31:34 -08:00
commit b7bbc75b98
4 changed files with 95 additions and 21 deletions

View file

@ -387,7 +387,7 @@ class AddingPureFrequencies(PiCreatureScene):
buff = 0,
)
return result
def stack_v_lines(self, x, lines):
point = self.axes.coords_to_point(x, self.equilibrium_height)
A_line, D_line = lines
@ -911,8 +911,8 @@ class FourierMachineScene(Scene):
self.remove(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):
period = np.divide(1., freq)
def get_v_lines_indicating_periods(self, freq, n_lines = 20):
period = np.divide(1., max(freq, 0.01))
v_lines = VGroup(*[
DashedLine(ORIGIN, 1.5*UP).move_to(
self.time_axes.coords_to_point(n*period, 0),
@ -923,6 +923,17 @@ class FourierMachineScene(Scene):
v_lines.set_stroke(LIGHT_GREY)
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):
CONFIG = {
"initial_winding_frequency" : 0.5,
@ -1099,8 +1110,6 @@ class DrawFrequencyPlot(WrapCosineGraphAroundCircle, PiCreatureScene):
"center_of_mass_color" : RED,
}
def construct(self):
self.force_skipping()
self.remove(self.pi_creature)
self.setup_graph()
# self.indicate_weight_of_wire()
@ -1108,6 +1117,8 @@ class DrawFrequencyPlot(WrapCosineGraphAroundCircle, PiCreatureScene):
# self.change_to_various_frequencies()
self.introduce_frequency_plot()
self.draw_full_frequency_plot()
self.recap_objects_on_screen()
self.lower_graph()
self.label_as_almost_fourier()
def setup_graph(self):
@ -1219,7 +1230,6 @@ class DrawFrequencyPlot(WrapCosineGraphAroundCircle, PiCreatureScene):
t_min = 0, t_max = TAU,
)
self.revert_to_original_skipping_status()
self.play(
wps_label.move_to, self.circle_plane.get_top(),
com_label.move_to, self.circle_plane, DOWN,
@ -1235,14 +1245,58 @@ class DrawFrequencyPlot(WrapCosineGraphAroundCircle, PiCreatureScene):
))
self.wait()
def draw_full_frequency_plot(self):
graph = self.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)
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):
pass
@ -1262,20 +1316,19 @@ class DrawFrequencyPlot(WrapCosineGraphAroundCircle, PiCreatureScene):
def change_frequency(self, new_freq, **kwargs):
kwargs["run_time"] = kwargs.get("run_time", 3)
added_anims = kwargs.get("added_anims", [])
freq_label = filter(
lambda sm : isinstance(sm, DecimalNumber),
self.winding_freq_label
)[0]
anims = [
Transform(
self.v_lines_indicating_periods,
self.get_v_lines_indicating_periods(new_freq)
),
ChangeDecimalToValue(freq_label, new_freq),
self.get_frequency_change_animation(
self.graph, new_freq
),
self.get_period_v_lines_update_anim(),
]
anims += added_anims
#TODO, conditionals for center of mass
if hasattr(self, "center_of_mass_dot"):
anims.append(self.center_of_mass_dot_anim)

View file

@ -94,16 +94,23 @@ class AmbientMovement(ContinualAnimation):
self.mobject.shift(dt*self.rate*self.direction)
class ContinualUpdateFromFunc(ContinualAnimation):
CONFIG = {
"function_depends_on_dt" : False
}
def __init__(self, mobject, func, **kwargs):
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)
def update_mobject(self, dt):
args = (self.mobject, dt)
self.func(*args[:self.func_arg_count])
if self.function_depends_on_dt:
self.func(self.mobject, dt)
else:
self.func(self.mobject)
class ContinualUpdateFromTimeFunc(ContinualUpdateFromFunc):
CONFIG = {
"function_depends_on_dt" : True
}
class ContinualMaintainPositionRelativeTo(ContinualAnimation):
# TODO: Possibly reimplement using CycleAnimation?

View file

@ -66,6 +66,7 @@ def get_configuration():
for short_arg, long_arg in optional_args:
parser.add_argument(short_arg, long_arg, action = "store_true")
parser.add_argument("-o", "--output_name")
parser.add_argument("-n", "--skip_to_animation_number")
args = parser.parse_args()
except argparse.ArgumentError as err:
print(str(err))
@ -85,6 +86,7 @@ def get_configuration():
"quiet" : args.quiet or args.write_all,
"write_all" : args.write_all,
"output_name" : args.output_name,
"skip_to_animation_number" : args.skip_to_animation_number,
}
if args.low_quality or args.preview:
config["camera_config"] = LOW_QUALITY_CAMERA_CONFIG
@ -96,12 +98,18 @@ def get_configuration():
config["camera_config"] = PRODUCTION_QUALITY_CAMERA_CONFIG
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
actions = ["write_to_movie", "preview", "show_last_frame"]
if not any([config[key] for key in actions]):
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
def handle_scene(scene, **config):
@ -203,7 +211,8 @@ def main():
"write_to_movie",
"save_frames",
"output_directory",
"save_pngs"
"save_pngs",
"skip_to_animation_number",
]
])

View file

@ -36,6 +36,7 @@ class Scene(object):
"name" : None,
"always_continually_update" : False,
"random_seed" : 0,
"skip_to_animation_number" : None,
}
def __init__(self, **kwargs):
digest_config(self, kwargs)
@ -59,6 +60,7 @@ class Scene(object):
self.construct(*self.construct_args)
if self.write_to_movie:
self.close_movie_pipe()
print("Played a total of %d animations"%self.num_plays)
def setup(self):
"""
@ -389,6 +391,9 @@ class Scene(object):
if len(args) == 0:
warnings.warn("Called Scene.play with no animations")
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:
kwargs["run_time"] = 0