redimentary ability to preview scenes

This commit is contained in:
Grant Sanderson 2015-06-09 11:26:12 -07:00
parent b5fbf7edea
commit b527568f5c
6 changed files with 98 additions and 36 deletions

View file

@ -12,7 +12,7 @@ PRODUCTION_QUALITY_DISPLAY_CONFIG = {
LOW_QUALITY_DISPLAY_CONFIG = { LOW_QUALITY_DISPLAY_CONFIG = {
"height" : 480, "height" : 480,
"width" : 840, "width" : 840,
"frame_duration" : 0.15, "frame_duration" : 0.04,
} }

View file

@ -21,7 +21,7 @@ LOGO_RADIUS = 1.5
if __name__ == '__main__': if __name__ == '__main__':
circle = Circle(density = 100, color = 'skyblue').repeat(5).scale(LOGO_RADIUS) circle = Circle(density = 100, color = 'skyblue').repeat(5).scale(LOGO_RADIUS)
sphere = Sphere(density = 100, color = DARK_BLUE).scale(LOGO_RADIUS) sphere = Sphere(density = 50, color = DARK_BLUE).scale(LOGO_RADIUS)
sphere.rotate(-np.pi / 7, [1, 0, 0]) sphere.rotate(-np.pi / 7, [1, 0, 0])
sphere.rotate(-np.pi / 7) sphere.rotate(-np.pi / 7)
alpha = 0.3 alpha = 0.3

View file

@ -1582,9 +1582,6 @@ class IntersectionChoppingExamples(Scene):
self.remove(*self.mobjects) self.remove(*self.mobjects)
################################################## ##################################################
if __name__ == "__main__": if __name__ == "__main__":

View file

@ -15,6 +15,7 @@ from mobject import *
from image_mobject import * from image_mobject import *
from animation import * from animation import *
import displayer as disp import displayer as disp
from tk_scene import TkSceneRoot
DEFAULT_COUNT_NUM_OFFSET = (SPACE_WIDTH - 1, SPACE_HEIGHT - 1, 0) DEFAULT_COUNT_NUM_OFFSET = (SPACE_WIDTH - 1, SPACE_HEIGHT - 1, 0)
DEFAULT_COUNT_RUN_TIME = 5.0 DEFAULT_COUNT_RUN_TIME = 5.0
@ -45,6 +46,7 @@ class Scene(object):
def set_name(self, name): def set_name(self, name):
self.name = name self.name = name
return self
def add(self, *mobjects): def add(self, *mobjects):
""" """
@ -56,6 +58,7 @@ class Scene(object):
#now be closer to the foreground. #now be closer to the foreground.
self.remove(mobject) self.remove(mobject)
self.mobjects.append(mobject) self.mobjects.append(mobject)
return self
def remove(self, *mobjects): def remove(self, *mobjects):
for mobject in mobjects: for mobject in mobjects:
@ -63,6 +66,8 @@ class Scene(object):
raise Exception("Removing something which is not a mobject") raise Exception("Removing something which is not a mobject")
while mobject in self.mobjects: while mobject in self.mobjects:
self.mobjects.remove(mobject) self.mobjects.remove(mobject)
return self
def highlight_region(self, region, color = None): def highlight_region(self, region, color = None):
self.background = disp.paint_region( self.background = disp.paint_region(
@ -70,6 +75,7 @@ class Scene(object):
image_array = self.background, image_array = self.background,
color = color, color = color,
) )
return self
def reset_background(self): def reset_background(self):
self.background = self.original_background self.background = self.original_background
@ -100,6 +106,7 @@ class Scene(object):
animation.clean_up() animation.clean_up()
self.add(*moving_mobjects) self.add(*moving_mobjects)
progress_bar.finish() progress_bar.finish()
return self
def count(self, items, item_type = "mobject", *args, **kwargs): def count(self, items, item_type = "mobject", *args, **kwargs):
if item_type == "mobject": if item_type == "mobject":
@ -108,6 +115,7 @@ class Scene(object):
self.count_regions(items, *args, **kwargs) self.count_regions(items, *args, **kwargs)
else: else:
raise Exception("Unknown item_type, should be mobject or region") raise Exception("Unknown item_type, should be mobject or region")
return self
def count_mobjects( def count_mobjects(
self, mobjects, mode = "highlight", self, mobjects, mode = "highlight",
@ -147,6 +155,7 @@ class Scene(object):
self.remove(num_mob) self.remove(num_mob)
self.add(num_mob) self.add(num_mob)
self.number = num_mob self.number = num_mob
return self
def count_regions(self, regions, def count_regions(self, regions,
mode = "one_at_a_time", mode = "one_at_a_time",
@ -167,6 +176,7 @@ class Scene(object):
self.remove(num_mob) self.remove(num_mob)
self.add(num_mob) self.add(num_mob)
self.number = num_mob self.number = num_mob
return self
def get_frame(self): def get_frame(self):
@ -177,6 +187,7 @@ class Scene(object):
def dither(self, duration = DEFAULT_DITHER_TIME): def dither(self, duration = DEFAULT_DITHER_TIME):
self.frames += [self.get_frame()]*int(duration / self.frame_duration) self.frames += [self.get_frame()]*int(duration / self.frame_duration)
return self
def write_to_gif(self, name = None, def write_to_gif(self, name = None,
end_dither_time = DEFAULT_DITHER_TIME): end_dither_time = DEFAULT_DITHER_TIME):
@ -188,9 +199,13 @@ class Scene(object):
self.dither(end_dither_time) self.dither(end_dither_time)
disp.write_to_movie(self, name or str(self)) disp.write_to_movie(self, name or str(self))
def show(self): def show_frame(self):
Image.fromarray(self.get_frame()).show() Image.fromarray(self.get_frame()).show()
def preview(self):
self.dither()
TkSceneRoot(self)
def save_image(self, path): def save_image(self, path):
path = os.path.join(MOVIE_DIR, path) + ".png" path = os.path.join(MOVIE_DIR, path) + ".png"
Image.fromarray(self.get_frame()).save(path) Image.fromarray(self.get_frame()).save(path)

View file

@ -3,51 +3,55 @@ import itertools as it
from PIL import Image from PIL import Image
from constants import * from constants import *
#TODO, Cleanup and refactor this file.
def tex_to_image(expression, def tex_to_image(expression,
size = "\HUGE", size = "\HUGE",
template_tex_file = TEMPLATE_TEX_FILE): template_tex_file = TEMPLATE_TEX_FILE):
""" """
Returns list of images for correpsonding with a list of expressions Returns list of images for correpsonding with a list of expressions
""" """
return_list = False return_list = isinstance(expression, list)
arg = expression simple_tex = "".join(expression)
if not isinstance(expression, str): if return_list:
#TODO, verify that expression is iterable of strings expression = tex_expression_list_as_string(expression)
expression = "\n".join([ exp_hash = str(hash(expression + size))
"\onslide<%d>{"%count + exp + "}" image_dir = os.path.join(TEX_IMAGE_DIR, exp_hash)
for count, exp in zip(it.count(1), expression) if os.path.exists(image_dir):
]) result = [
return_list = True Image.open(os.path.join(image_dir, png_file)).convert('RGB')
filestem = os.path.join( for png_file in os.listdir(image_dir)
TEX_DIR, str(hash(expression + size)) ]
) else:
if not os.path.exists(filestem + ".dvi"): filestem = os.path.join(TEX_DIR, exp_hash)
if not os.path.exists(filestem + ".tex"): if not os.path.exists(filestem + ".tex"):
print " ".join([ print "Writing %s at size %s to %s.tex"%(
"Writing ", simple_tex, size, filestem
"".join(arg), )
"at size %s to "%(size),
filestem,
])
with open(template_tex_file, "r") as infile: with open(template_tex_file, "r") as infile:
body = infile.read() body = infile.read()
body = body.replace(SIZE_TO_REPLACE, size) body = body.replace(SIZE_TO_REPLACE, size)
body = body.replace(TEX_TEXT_TO_REPLACE, expression) body = body.replace(TEX_TEXT_TO_REPLACE, expression)
with open(filestem + ".tex", "w") as outfile: with open(filestem + ".tex", "w") as outfile:
outfile.write(body) outfile.write(body)
commands = [ if not os.path.exists(filestem + ".dvi"):
"latex", commands = [
"-interaction=batchmode", "latex",
"-output-directory=" + TEX_DIR, "-interaction=batchmode",
filestem + ".tex" "-output-directory=" + TEX_DIR,
] filestem + ".tex",
#TODO, Error check "> /dev/null"
os.system(" ".join(commands)) ]
assert os.path.exists(filestem + ".dvi") #TODO, Error check
result = dvi_to_png(filestem + ".dvi") os.system(" ".join(commands))
result = dvi_to_png(filestem + ".dvi")
return result if return_list else result[0] return result if return_list else result[0]
def tex_expression_list_as_string(expression):
return "\n".join([
"\onslide<%d>{"%count + exp + "}"
for count, exp in zip(it.count(1), expression)
])
def dvi_to_png(filename, regen_if_exists = False): def dvi_to_png(filename, regen_if_exists = False):
""" """

46
tk_scene.py Normal file
View file

@ -0,0 +1,46 @@
from scene import *
import Tkinter
from PIL import ImageTk, Image
class TkSceneRoot(Tkinter.Tk):
def __init__(self, scene):
if scene.frames == []:
raise str(scene) + " has no frames!"
self.scene = scene
Tkinter.Tk.__init__(self)
self.height, self.width = scene.shape
kwargs = {"height" : self.height, "width" : self.width}
self.frame = Tkinter.Frame(self, **kwargs)
self.frame.pack()
self.canvas = Tkinter.Canvas(self.frame, **kwargs)
self.canvas.configure(background='black')
self.canvas.place(x=-2,y=-2)
self.frame_index = 0
self.num_frames = len(self.scene.frames)
self.frame_duration_in_ms = int(1000*scene.frame_duration)
# self.after(0,self.show_new_image)
while(1):
self.frame_index = 0
self.show_new_image()
self.mainloop()
def show_new_image(self):
self.frame_index += 1
if self.frame_index >= self.num_frames:
return
frame = self.scene.frames[self.frame_index]
image = Image.fromarray(frame).convert('RGB')
image.resize(self.frame.size())
photo = ImageTk.PhotoImage(image)
self.canvas.delete(Tkinter.ALL)
self.canvas.create_image(
0, 0,
image = photo, anchor = Tkinter.NW
)
self.after(self.frame_duration_in_ms, self.show_new_image)
self.update()