From 8c5929532abe52fef7e8b29d7b5ded3e344b71a2 Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Sun, 20 Dec 2015 16:43:22 -0800 Subject: [PATCH] Turned VibratingString animation into more general Vibrate --- animation/playground.py | 62 +++++++++++++++++-------------- old_projects/music_and_measure.py | 16 ++++---- 2 files changed, 43 insertions(+), 35 deletions(-) diff --git a/animation/playground.py b/animation/playground.py index e3d24e4c..34fa492e 100644 --- a/animation/playground.py +++ b/animation/playground.py @@ -1,42 +1,50 @@ import numpy as np +import operator as op from animation import Animation from transform import Transform -from mobject import Mobject1D +from mobject import Mobject1D, Mobject +from topics.geometry import Line from helpers import * -class VibratingString(Animation): +class Vibrate(Animation): DEFAULT_CONFIG = { - "num_periods" : 1, - "overtones" : 4, - "amplitude" : 0.5, - "radius" : SPACE_WIDTH/2, - "center" : ORIGIN, - "color" : "white", - "run_time" : 3.0, - "alpha_func" : None + "spatial_period" : 6, + "temporal_period" : 1, + "overtones" : 4, + "amplitude" : 0.5, + "radius" : SPACE_WIDTH/2, + "run_time" : 3.0, + "alpha_func" : None } - def __init__(self, **kwargs): - digest_config(self, kwargs) - def func(x, t): - return sum([ - (self.amplitude/((k+1)**2.5))*np.sin(2*mult*t)*np.sin(k*mult*x) - for k in range(self.overtones) - for mult in [(self.num_periods+k)*np.pi] + def __init__(self, mobject = None, **kwargs): + if mobject is None: + mobject = Line(3*LEFT, 3*RIGHT) + Animation.__init__(self, mobject, **kwargs) + + def wave_function(self, x, t): + return sum([ + reduce(op.mul, [ + self.amplitude/(k**2), #Amplitude + np.sin(2*np.pi*(k**1.5)*t/self.temporal_period), #Frequency + np.sin(2*np.pi*k*x/self.spatial_period) #Number of waves ]) - self.func = func - Animation.__init__(self, Mobject1D(color = self.color), **kwargs) + for k in range(1, self.overtones+1) + ]) + def update_mobject(self, alpha): - self.mobject.init_points() - epsilon = self.mobject.epsilon - self.mobject.add_points([ - [x*self.radius, self.func(x, alpha*self.run_time)+y, 0] - for x in np.arange(-1, 1, epsilon/self.radius) - for y in epsilon*np.arange(3) - ]) - self.mobject.shift(self.center) + time = alpha*self.run_time + families = map( + Mobject.get_full_submobject_family, + [self.mobject, self.starting_mobject] + ) + for mob, start in zip(*families): + mob.points = np.apply_along_axis( + lambda (x, y, z) : (x, y + self.wave_function(x, time), z), + 1, start.points + ) class TurnInsideOut(Transform): diff --git a/old_projects/music_and_measure.py b/old_projects/music_and_measure.py index 4dd60846..3999b9a6 100644 --- a/old_projects/music_and_measure.py +++ b/old_projects/music_and_measure.py @@ -126,7 +126,7 @@ class Piano(ImageMobject): return keys -class VibratingString(Animation): +class Vibrate(Animation): DEFAULT_CONFIG = { "num_periods" : 1, "overtones" : 4, @@ -302,7 +302,7 @@ class MeasureTheoryToHarmony(IntervalScene): line = Line(radius*LEFT, radius*RIGHT).highlight("white") self.play(DelayByOrder(Transform(all_mobs, line))) self.clear() - self.play(VibratingString(alpha_func = smooth)) + self.play(Vibrate(alpha_func = smooth)) self.clear() self.add(line) self.dither() @@ -313,12 +313,12 @@ class ChallengeOne(Scene): title = TextMobject("Challenge #1").to_edge(UP) start_color = Color("blue") colors = start_color.range_to("white", 6) - self.bottom_vibration = VibratingString( + self.bottom_vibration = Vibrate( num_periods = 1, run_time = 3.0, center = DOWN, color = start_color ) top_vibrations = [ - VibratingString( + Vibrate( num_periods = freq, run_time = 3.0, center = 2*UP, color = colors.next() ) @@ -415,8 +415,8 @@ class QuestionAndAnswer(Scene): def construct(self): Q = TextMobject("Q:").shift(UP).to_edge(LEFT) A = TextMobject("A:").shift(DOWN).to_edge(LEFT) - string1 = VibratingString(center = 3*UP, color = "blue") - string2 = VibratingString(num_periods = 2, center = 3.5*UP, color = "green") + string1 = Vibrate(center = 3*UP, color = "blue") + string2 = Vibrate(num_periods = 2, center = 3.5*UP, color = "green") twotwenty = TexMobject("220").scale(0.25).next_to(string1.mobject, LEFT) r220 = TexMobject("r\\times220").scale(0.25).next_to(string2.mobject, LEFT) question = TextMobject( @@ -466,11 +466,11 @@ class PlaySimpleRatio(Scene): return str(fraction).replace("/", "_to_") def construct(self, fraction, color): - string1 = VibratingString( + string1 = Vibrate( num_periods = 1, run_time = 5.0, center = DOWN, color = "blue" ) - string2 = VibratingString( + string2 = Vibrate( num_periods = fraction, run_time = 5.0, center = 2*UP, color = color )