From aa64d7cd5cb0aaa7f46918592f396db8a9e01c72 Mon Sep 17 00:00:00 2001 From: Sridhar Ramesh Date: Tue, 20 Feb 2018 09:11:43 -0800 Subject: [PATCH 1/8] Minor comment changes and clean up --- animation/simple_animations.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/animation/simple_animations.py b/animation/simple_animations.py index 9eb2bda7..aa1b5bd0 100644 --- a/animation/simple_animations.py +++ b/animation/simple_animations.py @@ -443,13 +443,12 @@ class Succession(Animation): # Beware: This does NOT take care of calling update(0) on the subanimation. # 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, + # with update twice, which could in turn call a sub-Succession with update four times, # continuing exponentially. 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... - for m in self.scene_mobjects_at_time[index].submobjects: - self.mobject.add(m) + self.mobject.add(*self.scene_mobjects_at_time[index].submobjects) self.mobject.add(self.animations[index].mobject) for i in range(index): @@ -459,10 +458,9 @@ class Succession(Animation): self.current_alpha = self.critical_alphas[index] def update_mobject(self, alpha): - if alpha == self.current_alpha: - return - if self.num_anims == 0: + # This probably doesn't matter for anything, but just in case, + # we want it in the future, we set current_alpha even in this case self.current_alpha = alpha return From 4982a44fb6e1dbd24a7afd6336dd43e13fa3b794 Mon Sep 17 00:00:00 2001 From: Sridhar Ramesh Date: Tue, 20 Feb 2018 09:42:43 -0800 Subject: [PATCH 2/8] Fixed bug where nested AnimationGroups did not propagate configs correctly --- animation/simple_animations.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/animation/simple_animations.py b/animation/simple_animations.py index 77af467e..47e16a0f 100644 --- a/animation/simple_animations.py +++ b/animation/simple_animations.py @@ -491,16 +491,14 @@ class AnimationGroup(Animation): "rate_func" : None } def __init__(self, *sub_anims, **kwargs): - digest_config(self, kwargs, locals()) sub_anims = filter (lambda x : not(x.empty), sub_anims) + digest_config(self, locals()) + self.update_config(**kwargs) # Handles propagation to self.sub_anims + if len(sub_anims) == 0: self.empty = True self.run_time = 0 else: - for anim in sub_anims: - # If AnimationGroup is called with any configuration, - # it is propagated to the sub_animations - anim.update_config(**kwargs) self.run_time = max([a.run_time for a in sub_anims]) everything = Mobject(*[a.mobject for a in sub_anims]) Animation.__init__(self, everything, **kwargs) @@ -513,6 +511,14 @@ class AnimationGroup(Animation): for anim in self.sub_anims: anim.clean_up(*args, **kwargs) + def update_config(self, **kwargs): + Animation.update_config(self, **kwargs) + + # If AnimationGroup is called with any configuration, + # it is propagated to the sub_animations + for anim in self.sub_anims: + anim.update_config(**kwargs) + class EmptyAnimation(Animation): CONFIG = { "run_time" : 0, From 5639f2e6c3fee6944b5d211b5c5c81d75a00bd19 Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Tue, 20 Feb 2018 11:28:11 -0800 Subject: [PATCH 3/8] Use generate_target in method compiling of scene.play --- scene/scene.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scene/scene.py b/scene/scene.py index fda15aaf..5a471485 100644 --- a/scene/scene.py +++ b/scene/scene.py @@ -380,7 +380,7 @@ class Scene(Container): animations.pop() #method should already have target then. else: - mobject.target = mobject.deepcopy() + mobject.generate_target() # if len(state["method_args"]) > 0 and isinstance(state["method_args"][-1], dict): method_kwargs = state["method_args"].pop() From 1a22b949e1a3dda567d379b7eecc7ef041e9724e Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Tue, 20 Feb 2018 11:28:59 -0800 Subject: [PATCH 4/8] Removed super-over-DRY implementation of style propagation in vmobjects --- mobject/vectorized_mobject.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/mobject/vectorized_mobject.py b/mobject/vectorized_mobject.py index a3ac3372..0e4cb237 100644 --- a/mobject/vectorized_mobject.py +++ b/mobject/vectorized_mobject.py @@ -54,10 +54,14 @@ class VMobject(Mobject): if fill_opacity is not None: self.fill_opacity = fill_opacity if family: - kwargs = locals() - kwargs.pop("self") for mob in self.submobjects: - mob.set_style_data(**kwargs) + mob.set_style_data( + stroke_color = stroke_color, + stroke_width = stroke_width, + fill_color = fill_color, + fill_opacity = fill_opacity, + family = family + ) return self def set_fill(self, color = None, opacity = None, family = True): From a71b9692bf51210ad30fdc758d78834a4dac0d29 Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Tue, 20 Feb 2018 11:29:17 -0800 Subject: [PATCH 5/8] Small uncertainty progress --- active_projects/uncertainty.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/active_projects/uncertainty.py b/active_projects/uncertainty.py index 2c385c8c..1af18595 100644 --- a/active_projects/uncertainty.py +++ b/active_projects/uncertainty.py @@ -1727,7 +1727,7 @@ class IntroduceDopplerRadar(Scene): words = ["Original signal", "Echo"] for graph, word in zip([pulse_graph, echo_graph], words): arrow = Vector(DOWN) - arrow.next_to(graph.peak_point, UP, SMALL_BUFF) + arrow.next_to(graph.peak_point, UP, MED_SMALL_BUFF) arrow.match_color(graph) graph.arrow = arrow label = TextMobject(word) @@ -2035,7 +2035,9 @@ class IntroduceDopplerRadar(Scene): sum_graph.background_image_file = "blue_yellow_gradient" return pulse_graph, echo_graph, sum_graph - +class MentionPRFNuance(TeacherStudentsScene): + def construct(self): + pass From 7fe0f0650a2ed7adfcd56ea8b87bea0f2291679a Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Tue, 20 Feb 2018 11:30:59 -0800 Subject: [PATCH 6/8] ... --- topics/light.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/topics/light.py b/topics/light.py index 67f1458c..9ba8d75c 100644 --- a/topics/light.py +++ b/topics/light.py @@ -537,7 +537,7 @@ class Spotlight(VMobject): new_submob = self.new_sector(submob.inner_radius,dr,lower_angle,upper_angle) submob.points = new_submob.points submob.set_fill(opacity = 10 * self.opacity_function(submob.outer_radius)) - print "new opacity:", self.opacity_function(submob.outer_radius) + # print "new opacity:", self.opacity_function(submob.outer_radius) From c2b9417c6a84a699e10150967751a334c7b95ca0 Mon Sep 17 00:00:00 2001 From: Sridhar Ramesh Date: Tue, 20 Feb 2018 12:33:58 -0800 Subject: [PATCH 7/8] Fixed division by zero bug in alpha compositing --- camera/camera.py | 7 ++++++- helpers.py | 15 +++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/camera/camera.py b/camera/camera.py index 1217f86f..2943162c 100644 --- a/camera/camera.py +++ b/camera/camera.py @@ -430,10 +430,15 @@ class Camera(object): ] out_a = src_a + dst_a*(1.0-src_a) + + # When the output alpha is 0 for full transparency, + # we have a choice over what RGB value to use in our + # output representation. We choose 0.0 here. out_rgb = fdiv( src_rgb*src_a[..., None] + \ dst_rgb*dst_a[..., None]*(1.0-src_a[..., None]), - out_a[..., None] + out_a[..., None], + zero_over_zero_value = 0.0 ) self.pixel_array[..., :3] = out_rgb*self.rgb_max_val diff --git a/helpers.py b/helpers.py index b9c7f387..878eb4e9 100644 --- a/helpers.py +++ b/helpers.py @@ -694,8 +694,19 @@ class DictAsObject(object): self.__dict__ = dict # Just to have a less heavyweight name for this extremely common operation -def fdiv(a, b): - return np.true_divide(a,b) +# +# We may wish to have more fine-grained control over division by zero behavior +# in future (separate specifiable default values for 0/0 and x/0 with x != 0), +# but for now, we just allow the option to handle 0/0. +def fdiv(a, b, zero_over_zero_value = None): + if zero_over_zero_value != None: + out = np.full_like(a, zero_over_zero_value) + where = np.logical_or (a != 0, b != 0) + else: + out = None + where = True + + return np.true_divide(a, b, out = out, where = where) def add_extension_if_not_present(file_name, extension): # This could conceivably be smarter about handling existing differing extensions From d3a39f2e65ba1a448846776f26926f4de06de708 Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Tue, 20 Feb 2018 14:03:59 -0800 Subject: [PATCH 8/8] Enabling transparent background of exported videos --- extract_scene.py | 2 ++ scene/scene.py | 15 ++++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/extract_scene.py b/extract_scene.py index 0d21e8a7..cec13bdf 100644 --- a/extract_scene.py +++ b/extract_scene.py @@ -95,6 +95,7 @@ def get_configuration(): "save_pngs" : args.save_pngs, #If -t is passed in (for transparent), this will be RGBA "saved_image_mode": "RGBA" if args.transparent else "RGB", + "movie_file_extension" : ".mov" if args.transparent else ".mp4", "quiet" : args.quiet or args.write_all, "ignore_waits" : args.preview, "write_all" : args.write_all, @@ -237,6 +238,7 @@ def main(): "write_to_movie", "output_directory", "save_pngs", + "movie_file_extension", "start_at_animation_number", "end_at_animation_number", ] diff --git a/scene/scene.py b/scene/scene.py index 5a471485..09c6ffa1 100644 --- a/scene/scene.py +++ b/scene/scene.py @@ -570,18 +570,23 @@ class Scene(Container): FFMPEG_BIN, '-y', # overwrite output file if it exists '-f', 'rawvideo', - '-vcodec','rawvideo', '-s', '%dx%d'%(width, height), # size of one frame '-pix_fmt', 'rgba', '-r', str(fps), # frames per second '-i', '-', # The imput comes from a pipe '-an', # Tells FFMPEG not to expect any audio - '-vcodec', 'mpeg', - '-c:v', 'libx264', - '-pix_fmt', 'yuv420p', '-loglevel', 'error', - temp_file_path, ] + if self.movie_file_extension == ".mov": + # This is if the background of the exported video + # should be transparent. + command += ['-vcodec', 'png'] + else: + command += [ + '-c:v', 'libx264', + '-pix_fmt', 'yuv420p', + ] + command += [temp_file_path] # self.writing_process = sp.Popen(command, stdin=sp.PIPE, shell=True) self.writing_process = sp.Popen(command, stdin=sp.PIPE)