mirror of
https://github.com/3b1b/manim.git
synced 2025-08-21 05:44:04 +00:00
Preliminaries of scene-oriented model implemented
This commit is contained in:
parent
948e1e3038
commit
5750a40bc6
4 changed files with 135 additions and 171 deletions
211
animate.py
211
animate.py
|
@ -17,10 +17,8 @@ import displayer as disp
|
||||||
class Animation(object):
|
class Animation(object):
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
mobject,
|
mobject,
|
||||||
|
run_time = DEFAULT_ANIMATION_RUN_TIME,
|
||||||
alpha_func = high_inflection_0_to_1,
|
alpha_func = high_inflection_0_to_1,
|
||||||
run_time = DEFAULT_ANIMATION_RUN_TIME,
|
|
||||||
pause_time = DEFAULT_ANIMATION_PAUSE_TIME,
|
|
||||||
dither_time = DEFAULT_DITHER_TIME,
|
|
||||||
name = None):
|
name = None):
|
||||||
if isinstance(mobject, type) and issubclass(mobject, Mobject):
|
if isinstance(mobject, type) and issubclass(mobject, Mobject):
|
||||||
self.mobject = mobject()
|
self.mobject = mobject()
|
||||||
|
@ -34,24 +32,14 @@ class Animation(object):
|
||||||
self.reference_mobjects = [self.starting_mobject]
|
self.reference_mobjects = [self.starting_mobject]
|
||||||
self.alpha_func = alpha_func or (lambda x : x)
|
self.alpha_func = alpha_func or (lambda x : x)
|
||||||
self.run_time = run_time
|
self.run_time = run_time
|
||||||
self.pause_time = pause_time
|
|
||||||
self.dither_time = dither_time
|
|
||||||
self.nframes, self.ndither_frames = self.get_frame_count()
|
|
||||||
self.nframes_past = 0
|
|
||||||
self.frames = []
|
|
||||||
self.concurrent_animations = []
|
|
||||||
self.following_animations = []
|
|
||||||
self.reference_animations = []
|
|
||||||
self.background_mobjects = []
|
|
||||||
self.filter_functions = []
|
self.filter_functions = []
|
||||||
self.restricted_height = SPACE_HEIGHT
|
self.restricted_height = SPACE_HEIGHT
|
||||||
self.restricted_width = SPACE_WIDTH
|
self.restricted_width = SPACE_WIDTH
|
||||||
self.spacial_center = np.zeros(3)
|
self.spacial_center = np.zeros(3)
|
||||||
self.name = self.__class__.__name__ + str(self.mobject)
|
self.name = name or self.__class__.__name__ + str(self.mobject)
|
||||||
self.inputted_name = name
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.inputted_name or self.name
|
return self.name
|
||||||
|
|
||||||
def get_points_and_rgbs(self):
|
def get_points_and_rgbs(self):
|
||||||
"""
|
"""
|
||||||
|
@ -59,24 +47,10 @@ class Animation(object):
|
||||||
the space. Returns np array of points and corresponding np array
|
the space. Returns np array of points and corresponding np array
|
||||||
of rgbs
|
of rgbs
|
||||||
"""
|
"""
|
||||||
points = np.zeros(0)
|
#TODO, I don't think this should be necessary. This should happen
|
||||||
rgbs = np.zeros(0)
|
#under the individual mobjects.
|
||||||
for mobject in self.background_mobjects + [self.mobject]:
|
points = self.mobject.points
|
||||||
points = np.append(points, mobject.points)
|
rgbs = self.mobject.rgbs
|
||||||
rgbs = np.append(rgbs, mobject.rgbs)
|
|
||||||
#Kind of hacky
|
|
||||||
if mobject.SHOULD_BUFF_POINTS: #TODO, think about this.
|
|
||||||
up_nudge = np.array(
|
|
||||||
(2.0 * SPACE_HEIGHT / HEIGHT, 0, 0)
|
|
||||||
)
|
|
||||||
side_nudge = np.array(
|
|
||||||
(0, 2.0 * SPACE_WIDTH / WIDTH, 0)
|
|
||||||
)
|
|
||||||
for nudge in up_nudge, side_nudge, up_nudge + side_nudge:
|
|
||||||
points = np.append(points, mobject.points + nudge)
|
|
||||||
rgbs = np.append(rgbs, mobject.rgbs)
|
|
||||||
points = points.reshape((points.size/3, 3))
|
|
||||||
rgbs = rgbs.reshape((rgbs.size/3, 3))
|
|
||||||
#Filters out what is out of bounds.
|
#Filters out what is out of bounds.
|
||||||
admissibles = (abs(points[:,0]) < self.restricted_width) * \
|
admissibles = (abs(points[:,0]) < self.restricted_width) * \
|
||||||
(abs(points[:,1]) < self.restricted_height)
|
(abs(points[:,1]) < self.restricted_height)
|
||||||
|
@ -93,91 +67,27 @@ class Animation(object):
|
||||||
admissibles = admissibles[:rgbs.shape[0]]
|
admissibles = admissibles[:rgbs.shape[0]]
|
||||||
return points[admissibles, :], rgbs[admissibles, :]
|
return points[admissibles, :], rgbs[admissibles, :]
|
||||||
|
|
||||||
def update(self):
|
def update(self, alpha):
|
||||||
if self.nframes_past > self.nframes:
|
if alpha < 0:
|
||||||
return False
|
alpha = 0
|
||||||
self.nframes_past += 1
|
if alpha > 1:
|
||||||
for anim in self.concurrent_animations + self.reference_animations:
|
alpha = 1
|
||||||
anim.update()
|
self.update_mobject(self.alpha_func(alpha))
|
||||||
self.update_mobject(self.alpha_func(self.get_fraction_complete()))
|
|
||||||
return True
|
|
||||||
|
|
||||||
def while_also(self, action, display = True, *args, **kwargs):
|
# def generate_frames(self):
|
||||||
if isinstance(action, type) and issubclass(action, Animation):
|
# print "Generating " + str(self) + "..."
|
||||||
self.reference_animations += [
|
# progress_bar = progressbar.ProgressBar(maxval=self.nframes)
|
||||||
action(mobject, *args, **kwargs)
|
# progress_bar.start()
|
||||||
for mobject in self.reference_mobjects + [self.mobject]
|
|
||||||
]
|
|
||||||
self.name += action.__name__
|
|
||||||
return self
|
|
||||||
if action.mobject == self.mobject:
|
|
||||||
#This is just for a weird edge case
|
|
||||||
action.mobject = self.starting_mobject
|
|
||||||
new_home = self.concurrent_animations if display else \
|
|
||||||
self.reference_animations
|
|
||||||
new_home.append(action)
|
|
||||||
self.name += str(action)
|
|
||||||
return self
|
|
||||||
|
|
||||||
def with_background(self, *mobjects):
|
# self.frames = []
|
||||||
for anim in [self] + self.following_animations:
|
# while self.update():
|
||||||
anim.background_mobjects.append(CompoundMobject(*mobjects))
|
# self.frames.append(self.get_image())
|
||||||
return self
|
# progress_bar.update(self.nframes_past - 1)
|
||||||
|
# self.clean_up()
|
||||||
def then(self, action, carry_over_background = False, *args, **kwargs):
|
# for anim in self.following_animations:
|
||||||
if isinstance(action, type) and issubclass(action, Animation):
|
# self.frames += anim.get_frames()
|
||||||
action = action(mobject = self.mobject, *args, **kwargs)
|
# progress_bar.finish()
|
||||||
if carry_over_background:
|
# return self
|
||||||
action.background_mobjects += self.background_mobjects
|
|
||||||
self.following_animations.append(action)
|
|
||||||
if self.frames:
|
|
||||||
self.frames += action.get_frames()
|
|
||||||
self.name += "Then" + str(action)
|
|
||||||
return self
|
|
||||||
|
|
||||||
def get_image(self):
|
|
||||||
all_points, all_rgbs = self.get_points_and_rgbs()
|
|
||||||
for anim in self.concurrent_animations:
|
|
||||||
new_points, new_rgbs = anim.get_points_and_rgbs()
|
|
||||||
all_points = np.append(all_points, new_points)
|
|
||||||
all_rgbs = np.append(all_rgbs, new_rgbs)
|
|
||||||
all_points = all_points.reshape((all_points.size/3, 3))
|
|
||||||
all_rgbs = all_rgbs.reshape((all_rgbs.size/3, 3))
|
|
||||||
return disp.get_image(all_points, all_rgbs)
|
|
||||||
|
|
||||||
def generate_frames(self):
|
|
||||||
print "Generating " + str(self) + "..."
|
|
||||||
progress_bar = progressbar.ProgressBar(maxval=self.nframes)
|
|
||||||
progress_bar.start()
|
|
||||||
|
|
||||||
self.frames = []
|
|
||||||
while self.update():
|
|
||||||
self.frames.append(self.get_image())
|
|
||||||
progress_bar.update(self.nframes_past - 1)
|
|
||||||
self.clean_up()
|
|
||||||
for anim in self.following_animations:
|
|
||||||
self.frames += anim.get_frames()
|
|
||||||
progress_bar.finish()
|
|
||||||
return self
|
|
||||||
|
|
||||||
def get_fraction_complete(self):
|
|
||||||
result = float(self.nframes_past - self.ndither_frames) / (
|
|
||||||
self.nframes - 2 * self.ndither_frames)
|
|
||||||
if result <= 0:
|
|
||||||
return 0
|
|
||||||
elif result >= 1:
|
|
||||||
return 1
|
|
||||||
return result
|
|
||||||
|
|
||||||
def get_frames(self):
|
|
||||||
if not self.frames:
|
|
||||||
self.generate_frames()
|
|
||||||
return self.frames
|
|
||||||
|
|
||||||
def get_frame_count(self):
|
|
||||||
nframes = int((self.run_time + 2*self.dither_time)/ self.pause_time)
|
|
||||||
ndither_frames = int(self.dither_time / self.pause_time)
|
|
||||||
return nframes, ndither_frames
|
|
||||||
|
|
||||||
def filter_out(self, *filter_functions):
|
def filter_out(self, *filter_functions):
|
||||||
self.filter_functions += filter_functions
|
self.filter_functions += filter_functions
|
||||||
|
@ -193,22 +103,10 @@ class Animation(object):
|
||||||
|
|
||||||
def shift(self, vector):
|
def shift(self, vector):
|
||||||
self.spacial_center += vector
|
self.spacial_center += vector
|
||||||
for anim in self.following_animations:
|
|
||||||
anim.shift(vector)
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def set_dither(self, time, apply_to_concurrent = False):
|
def set_run_time(self, time):
|
||||||
self.dither_time = time
|
|
||||||
if apply_to_concurrent:
|
|
||||||
for anim in self.concurrent_animations + self.reference_animations:
|
|
||||||
anim.set_dither(time)
|
|
||||||
return self.reload()
|
|
||||||
|
|
||||||
def set_run_time(self, time, apply_to_concurrent = False):
|
|
||||||
self.run_time = time
|
self.run_time = time
|
||||||
if apply_to_concurrent:
|
|
||||||
for anim in self.concurrent_animations + self.reference_animations:
|
|
||||||
anim.set_run_time(time)
|
|
||||||
return self.reload()
|
return self.reload()
|
||||||
|
|
||||||
def set_alpha_func(self, alpha_func):
|
def set_alpha_func(self, alpha_func):
|
||||||
|
@ -218,30 +116,17 @@ class Animation(object):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def set_name(self, name):
|
def set_name(self, name):
|
||||||
self.inputted_name = name
|
self.name = name
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def reload(self):
|
# def drag_pixels(self):
|
||||||
self.nframes, self.ndither_frames = self.get_frame_count()
|
# self.frames = drag_pixels(self.get_frames())
|
||||||
if self.frames:
|
# return self
|
||||||
self.nframes_past = 0
|
|
||||||
self.generate_frames()
|
|
||||||
return self
|
|
||||||
|
|
||||||
def drag_pixels(self):
|
# def reverse(self):
|
||||||
self.frames = drag_pixels(self.get_frames())
|
# self.get_frames().reverse()
|
||||||
return self
|
# self.name = 'Reversed' + str(self)
|
||||||
|
# return self
|
||||||
def reverse(self):
|
|
||||||
self.get_frames().reverse()
|
|
||||||
self.name = 'Reversed' + str(self)
|
|
||||||
return self
|
|
||||||
|
|
||||||
def write_to_gif(self, name = None):
|
|
||||||
disp.write_to_gif(self, name or str(self))
|
|
||||||
|
|
||||||
def write_to_movie(self, name = None):
|
|
||||||
disp.write_to_movie(self, name or str(self))
|
|
||||||
|
|
||||||
def update_mobject(self, alpha):
|
def update_mobject(self, alpha):
|
||||||
#Typically ipmlemented by subclass
|
#Typically ipmlemented by subclass
|
||||||
|
@ -249,9 +134,6 @@ class Animation(object):
|
||||||
|
|
||||||
def clean_up(self):
|
def clean_up(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def dither(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
###### Concrete Animations ########
|
###### Concrete Animations ########
|
||||||
|
@ -263,12 +145,11 @@ class Rotating(Animation):
|
||||||
axes = [[0, 0, 1], [0, 1, 0]],
|
axes = [[0, 0, 1], [0, 1, 0]],
|
||||||
radians = 2 * np.pi,
|
radians = 2 * np.pi,
|
||||||
run_time = 20.0,
|
run_time = 20.0,
|
||||||
dither_time = 0.0,
|
|
||||||
alpha_func = None,
|
alpha_func = None,
|
||||||
*args, **kwargs):
|
*args, **kwargs):
|
||||||
Animation.__init__(
|
Animation.__init__(
|
||||||
self, mobject,
|
self, mobject,
|
||||||
run_time = run_time, dither_time = dither_time,
|
run_time = run_time,
|
||||||
alpha_func = alpha_func,
|
alpha_func = alpha_func,
|
||||||
*args, **kwargs
|
*args, **kwargs
|
||||||
)
|
)
|
||||||
|
@ -282,19 +163,20 @@ class Rotating(Animation):
|
||||||
self.radians * alpha,
|
self.radians * alpha,
|
||||||
axis
|
axis
|
||||||
)
|
)
|
||||||
|
|
||||||
class RotationAsTransform(Rotating):
|
class RotationAsTransform(Rotating):
|
||||||
def __init__(self, mobject, radians,
|
def __init__(self, mobject, radians, axis = (0, 0, 1), axes = None,
|
||||||
run_time = DEFAULT_ANIMATION_RUN_TIME,
|
run_time = DEFAULT_ANIMATION_RUN_TIME,
|
||||||
dither_time = DEFAULT_DITHER_TIME,
|
alpha_func = high_inflection_0_to_1,
|
||||||
*args, **kwargs):
|
*args, **kwargs):
|
||||||
Rotating.__init__(
|
Rotating.__init__(
|
||||||
self,
|
self,
|
||||||
mobject,
|
mobject,
|
||||||
axis = (0, 0, 1),
|
axis = axis,
|
||||||
|
axes = axes,
|
||||||
run_time = run_time,
|
run_time = run_time,
|
||||||
dither_time = dither_time,
|
|
||||||
radians = radians,
|
radians = radians,
|
||||||
alpha_func = high_inflection_0_to_1,
|
alpha_func = alpha_func,
|
||||||
)
|
)
|
||||||
|
|
||||||
class FadeOut(Animation):
|
class FadeOut(Animation):
|
||||||
|
@ -309,7 +191,8 @@ class Reveal(Animation):
|
||||||
#TODO, Why do you need to do this? Shouldn't points always align?
|
#TODO, Why do you need to do this? Shouldn't points always align?
|
||||||
|
|
||||||
class Transform(Animation):
|
class Transform(Animation):
|
||||||
def __init__(self, mobject1, mobject2, run_time = DEFAULT_TRANSFORM_RUN_TIME,
|
def __init__(self, mobject1, mobject2,
|
||||||
|
run_time = DEFAULT_TRANSFORM_RUN_TIME,
|
||||||
*args, **kwargs):
|
*args, **kwargs):
|
||||||
count1, count2 = mobject1.get_num_points(), mobject2.get_num_points()
|
count1, count2 = mobject1.get_num_points(), mobject2.get_num_points()
|
||||||
Mobject.align_data(mobject1, mobject2)
|
Mobject.align_data(mobject1, mobject2)
|
||||||
|
@ -353,7 +236,7 @@ class Transform(Animation):
|
||||||
class ApplyMethod(Transform):
|
class ApplyMethod(Transform):
|
||||||
def __init__(self, method, mobject, *args, **kwargs):
|
def __init__(self, method, mobject, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
method is a method of Mobject
|
Method is a method of Mobject
|
||||||
"""
|
"""
|
||||||
method_args = ()
|
method_args = ()
|
||||||
if isinstance(method, tuple):
|
if isinstance(method, tuple):
|
||||||
|
@ -434,6 +317,7 @@ class ComplexHomotopy(Homotopy):
|
||||||
|
|
||||||
class ShowCreation(Animation):
|
class ShowCreation(Animation):
|
||||||
def update_mobject(self, alpha):
|
def update_mobject(self, alpha):
|
||||||
|
#TODO, shoudl I make this more efficient?
|
||||||
new_num_points = int(alpha * self.starting_mobject.points.shape[0])
|
new_num_points = int(alpha * self.starting_mobject.points.shape[0])
|
||||||
for attr in ["points", "rgbs"]:
|
for attr in ["points", "rgbs"]:
|
||||||
setattr(
|
setattr(
|
||||||
|
@ -444,10 +328,9 @@ class ShowCreation(Animation):
|
||||||
|
|
||||||
class Flash(Animation):
|
class Flash(Animation):
|
||||||
def __init__(self, mobject, color = "white", slow_factor = 0.01,
|
def __init__(self, mobject, color = "white", slow_factor = 0.01,
|
||||||
run_time = 0.1, dither_time = 0, alpha_func = None,
|
run_time = 0.1, alpha_func = None,
|
||||||
*args, **kwargs):
|
*args, **kwargs):
|
||||||
Animation.__init__(self, mobject, run_time = run_time,
|
Animation.__init__(self, mobject, run_time = run_time,
|
||||||
dither_time = dither_time,
|
|
||||||
alpha_func = alpha_func,
|
alpha_func = alpha_func,
|
||||||
*args, **kwargs)
|
*args, **kwargs)
|
||||||
self.intermediate = Mobject(color = color)
|
self.intermediate = Mobject(color = color)
|
||||||
|
|
|
@ -8,7 +8,7 @@ DEFAULT_POINT_DENSITY_1D = 200 if PRODUCTION_QUALITY else 50
|
||||||
HEIGHT = 1024#1440 if PRODUCTION_QUALITY else 480
|
HEIGHT = 1024#1440 if PRODUCTION_QUALITY else 480
|
||||||
WIDTH = 1024#2560 if PRODUCTION_QUALITY else 640
|
WIDTH = 1024#2560 if PRODUCTION_QUALITY else 640
|
||||||
#All in seconds
|
#All in seconds
|
||||||
DEFAULT_ANIMATION_PAUSE_TIME = 0.04 if PRODUCTION_QUALITY else 0.1
|
DEFAULT_FRAME_DURATION = 0.04 if PRODUCTION_QUALITY else 0.1
|
||||||
DEFAULT_ANIMATION_RUN_TIME = 3.0
|
DEFAULT_ANIMATION_RUN_TIME = 3.0
|
||||||
DEFAULT_TRANSFORM_RUN_TIME = 1.0
|
DEFAULT_TRANSFORM_RUN_TIME = 1.0
|
||||||
DEFAULT_DITHER_TIME = 1.0
|
DEFAULT_DITHER_TIME = 1.0
|
||||||
|
|
13
displayer.py
13
displayer.py
|
@ -36,20 +36,21 @@ def get_pixels(points, rgbs):
|
||||||
pixels[indices] = rgbs
|
pixels[indices] = rgbs
|
||||||
return pixels.reshape((HEIGHT, WIDTH, 3)).astype('uint8')
|
return pixels.reshape((HEIGHT, WIDTH, 3)).astype('uint8')
|
||||||
|
|
||||||
def write_to_gif(animation, name):
|
def write_to_gif(scene, name):
|
||||||
#TODO, find better means of compression
|
#TODO, find better means of compression
|
||||||
if not name.endswith(".gif"):
|
if not name.endswith(".gif"):
|
||||||
name += ".gif"
|
name += ".gif"
|
||||||
filepath = os.path.join(GIF_DIR, name)
|
filepath = os.path.join(GIF_DIR, name)
|
||||||
temppath = os.path.join(GIF_DIR, "Temp.gif")
|
temppath = os.path.join(GIF_DIR, "Temp.gif")
|
||||||
print "Writing " + name + "..."
|
print "Writing " + name + "..."
|
||||||
writeGif(temppath, animation.get_frames(), animation.pause_time)
|
writeGif(temppath, scene.frames, scene.frame_duration)
|
||||||
print "Compressing..."
|
print "Compressing..."
|
||||||
os.system("gifsicle -O " + temppath + " > " + filepath)
|
os.system("gifsicle -O " + temppath + " > " + filepath)
|
||||||
os.system("rm " + temppath)
|
os.system("rm " + temppath)
|
||||||
|
|
||||||
def write_to_movie(animation, name):
|
def write_to_movie(scene, name):
|
||||||
frames = animation.get_frames()
|
#TODO, incorporate pause time
|
||||||
|
frames = scene.frames
|
||||||
progress_bar = progressbar.ProgressBar(maxval=len(frames))
|
progress_bar = progressbar.ProgressBar(maxval=len(frames))
|
||||||
progress_bar.start()
|
progress_bar.start()
|
||||||
print "writing " + name + "..."
|
print "writing " + name + "..."
|
||||||
|
@ -75,7 +76,7 @@ def write_to_movie(animation, name):
|
||||||
"-c:v",
|
"-c:v",
|
||||||
"libx264",
|
"libx264",
|
||||||
"-vf",
|
"-vf",
|
||||||
"fps=%d,format=yuv420p"%int(1/animation.pause_time),
|
"fps=%d,format=yuv420p"%int(1/scene.frame_duration),
|
||||||
filepath
|
filepath
|
||||||
]
|
]
|
||||||
os.system(" ".join(commands))
|
os.system(" ".join(commands))
|
||||||
|
@ -87,7 +88,7 @@ def write_to_movie(animation, name):
|
||||||
# filepath = os.path.join(MOVIE_DIR, name + ".mov")
|
# filepath = os.path.join(MOVIE_DIR, name + ".mov")
|
||||||
# fourcc = cv2.cv.FOURCC(*"8bps")
|
# fourcc = cv2.cv.FOURCC(*"8bps")
|
||||||
# out = cv2.VideoWriter(
|
# out = cv2.VideoWriter(
|
||||||
# filepath, fourcc, 1.0/animation.pause_time, (WIDTH, HEIGHT), True
|
# filepath, fourcc, 1.0/animation.frame_duration, (WIDTH, HEIGHT), True
|
||||||
# )
|
# )
|
||||||
# progress = 0
|
# progress = 0
|
||||||
# for frame in frames:
|
# for frame in frames:
|
||||||
|
|
80
scene.py
Normal file
80
scene.py
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
from PIL import Image
|
||||||
|
from colour import Color
|
||||||
|
import numpy as np
|
||||||
|
import warnings
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
import copy
|
||||||
|
import progressbar
|
||||||
|
import inspect
|
||||||
|
|
||||||
|
|
||||||
|
from helpers import *
|
||||||
|
from mobject import *
|
||||||
|
from animate import *
|
||||||
|
import displayer as disp
|
||||||
|
|
||||||
|
class Scene(object):
|
||||||
|
def __init__(self,
|
||||||
|
frame_duration = DEFAULT_FRAME_DURATION,
|
||||||
|
name = None):
|
||||||
|
self.frame_duration = frame_duration
|
||||||
|
self.frames = []
|
||||||
|
self.mobjects = set([])
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name or "Babadinook" #TODO
|
||||||
|
|
||||||
|
def add(self, *mobjects):
|
||||||
|
#TODO, perhaps mobjects should be ordered, for foreground/background
|
||||||
|
self.mobjects.update(mobjects)
|
||||||
|
|
||||||
|
def remove(self, *mobjects):
|
||||||
|
self.mobjects.difference_update(mobjects)
|
||||||
|
|
||||||
|
def animate(self, animations,
|
||||||
|
dither_time = DEFAULT_DITHER_TIME):
|
||||||
|
if isinstance(animations, Animation):
|
||||||
|
animations = [animations]
|
||||||
|
self.pause(dither_time)
|
||||||
|
run_time = max([anim.run_time for anim in animations])
|
||||||
|
|
||||||
|
print "Generating animations..."
|
||||||
|
progress_bar = progressbar.ProgressBar(maxval=run_time)
|
||||||
|
progress_bar.start()
|
||||||
|
|
||||||
|
for t in np.arange(0, run_time, self.frame_duration):
|
||||||
|
progress_bar.update(t)
|
||||||
|
for anim in animations:
|
||||||
|
anim.update(t)
|
||||||
|
self.frames.append(self.get_frame(*animations))
|
||||||
|
for anim in animations:
|
||||||
|
anim.clean_up()
|
||||||
|
progress_bar.finish()
|
||||||
|
|
||||||
|
def pause(self, duration):
|
||||||
|
self.frames += [self.get_frame()]*int(duration / self.frame_duration)
|
||||||
|
|
||||||
|
def get_frame(self, *animations):
|
||||||
|
#Include animations so as to display mobjects not in the list
|
||||||
|
#TODO, This is temporary
|
||||||
|
mob = list(self.mobjects)[0]
|
||||||
|
return disp.get_image(mob.points, mob.rgbs)
|
||||||
|
|
||||||
|
def write_to_gif(self, name = None, end_dither_time = DEFAULT_DITHER_TIME):
|
||||||
|
self.pause(end_dither_time)
|
||||||
|
disp.write_to_gif(self, name or str(self))
|
||||||
|
|
||||||
|
def write_to_movie(self, name = None, end_dither_time = DEFAULT_DITHER_TIME):
|
||||||
|
self.pause(end_dither_time)
|
||||||
|
disp.write_to_movie(self, name or str(self))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue