mirror of
https://github.com/3b1b/manim.git
synced 2025-04-13 09:47:07 +00:00
redimentary ability to preview scenes
This commit is contained in:
parent
b5fbf7edea
commit
b527568f5c
6 changed files with 98 additions and 36 deletions
|
@ -12,7 +12,7 @@ PRODUCTION_QUALITY_DISPLAY_CONFIG = {
|
|||
LOW_QUALITY_DISPLAY_CONFIG = {
|
||||
"height" : 480,
|
||||
"width" : 840,
|
||||
"frame_duration" : 0.15,
|
||||
"frame_duration" : 0.04,
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ LOGO_RADIUS = 1.5
|
|||
|
||||
if __name__ == '__main__':
|
||||
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)
|
||||
alpha = 0.3
|
||||
|
|
|
@ -1582,9 +1582,6 @@ class IntersectionChoppingExamples(Scene):
|
|||
self.remove(*self.mobjects)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
##################################################
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
17
scene.py
17
scene.py
|
@ -15,6 +15,7 @@ from mobject import *
|
|||
from image_mobject import *
|
||||
from animation import *
|
||||
import displayer as disp
|
||||
from tk_scene import TkSceneRoot
|
||||
|
||||
DEFAULT_COUNT_NUM_OFFSET = (SPACE_WIDTH - 1, SPACE_HEIGHT - 1, 0)
|
||||
DEFAULT_COUNT_RUN_TIME = 5.0
|
||||
|
@ -45,6 +46,7 @@ class Scene(object):
|
|||
|
||||
def set_name(self, name):
|
||||
self.name = name
|
||||
return self
|
||||
|
||||
def add(self, *mobjects):
|
||||
"""
|
||||
|
@ -56,6 +58,7 @@ class Scene(object):
|
|||
#now be closer to the foreground.
|
||||
self.remove(mobject)
|
||||
self.mobjects.append(mobject)
|
||||
return self
|
||||
|
||||
def remove(self, *mobjects):
|
||||
for mobject in mobjects:
|
||||
|
@ -63,6 +66,8 @@ class Scene(object):
|
|||
raise Exception("Removing something which is not a mobject")
|
||||
while mobject in self.mobjects:
|
||||
self.mobjects.remove(mobject)
|
||||
return self
|
||||
|
||||
|
||||
def highlight_region(self, region, color = None):
|
||||
self.background = disp.paint_region(
|
||||
|
@ -70,6 +75,7 @@ class Scene(object):
|
|||
image_array = self.background,
|
||||
color = color,
|
||||
)
|
||||
return self
|
||||
|
||||
def reset_background(self):
|
||||
self.background = self.original_background
|
||||
|
@ -100,6 +106,7 @@ class Scene(object):
|
|||
animation.clean_up()
|
||||
self.add(*moving_mobjects)
|
||||
progress_bar.finish()
|
||||
return self
|
||||
|
||||
def count(self, items, item_type = "mobject", *args, **kwargs):
|
||||
if item_type == "mobject":
|
||||
|
@ -108,6 +115,7 @@ class Scene(object):
|
|||
self.count_regions(items, *args, **kwargs)
|
||||
else:
|
||||
raise Exception("Unknown item_type, should be mobject or region")
|
||||
return self
|
||||
|
||||
def count_mobjects(
|
||||
self, mobjects, mode = "highlight",
|
||||
|
@ -147,6 +155,7 @@ class Scene(object):
|
|||
self.remove(num_mob)
|
||||
self.add(num_mob)
|
||||
self.number = num_mob
|
||||
return self
|
||||
|
||||
def count_regions(self, regions,
|
||||
mode = "one_at_a_time",
|
||||
|
@ -167,6 +176,7 @@ class Scene(object):
|
|||
self.remove(num_mob)
|
||||
self.add(num_mob)
|
||||
self.number = num_mob
|
||||
return self
|
||||
|
||||
|
||||
def get_frame(self):
|
||||
|
@ -177,6 +187,7 @@ class Scene(object):
|
|||
|
||||
def dither(self, duration = DEFAULT_DITHER_TIME):
|
||||
self.frames += [self.get_frame()]*int(duration / self.frame_duration)
|
||||
return self
|
||||
|
||||
def write_to_gif(self, name = None,
|
||||
end_dither_time = DEFAULT_DITHER_TIME):
|
||||
|
@ -188,9 +199,13 @@ class Scene(object):
|
|||
self.dither(end_dither_time)
|
||||
disp.write_to_movie(self, name or str(self))
|
||||
|
||||
def show(self):
|
||||
def show_frame(self):
|
||||
Image.fromarray(self.get_frame()).show()
|
||||
|
||||
def preview(self):
|
||||
self.dither()
|
||||
TkSceneRoot(self)
|
||||
|
||||
def save_image(self, path):
|
||||
path = os.path.join(MOVIE_DIR, path) + ".png"
|
||||
Image.fromarray(self.get_frame()).save(path)
|
||||
|
|
64
tex_utils.py
64
tex_utils.py
|
@ -3,51 +3,55 @@ import itertools as it
|
|||
from PIL import Image
|
||||
from constants import *
|
||||
|
||||
#TODO, Cleanup and refactor this file.
|
||||
|
||||
def tex_to_image(expression,
|
||||
size = "\HUGE",
|
||||
template_tex_file = TEMPLATE_TEX_FILE):
|
||||
"""
|
||||
Returns list of images for correpsonding with a list of expressions
|
||||
"""
|
||||
return_list = False
|
||||
arg = expression
|
||||
if not isinstance(expression, str):
|
||||
#TODO, verify that expression is iterable of strings
|
||||
expression = "\n".join([
|
||||
"\onslide<%d>{"%count + exp + "}"
|
||||
for count, exp in zip(it.count(1), expression)
|
||||
])
|
||||
return_list = True
|
||||
filestem = os.path.join(
|
||||
TEX_DIR, str(hash(expression + size))
|
||||
)
|
||||
if not os.path.exists(filestem + ".dvi"):
|
||||
return_list = isinstance(expression, list)
|
||||
simple_tex = "".join(expression)
|
||||
if return_list:
|
||||
expression = tex_expression_list_as_string(expression)
|
||||
exp_hash = str(hash(expression + size))
|
||||
image_dir = os.path.join(TEX_IMAGE_DIR, exp_hash)
|
||||
if os.path.exists(image_dir):
|
||||
result = [
|
||||
Image.open(os.path.join(image_dir, png_file)).convert('RGB')
|
||||
for png_file in os.listdir(image_dir)
|
||||
]
|
||||
else:
|
||||
filestem = os.path.join(TEX_DIR, exp_hash)
|
||||
if not os.path.exists(filestem + ".tex"):
|
||||
print " ".join([
|
||||
"Writing ",
|
||||
"".join(arg),
|
||||
"at size %s to "%(size),
|
||||
filestem,
|
||||
])
|
||||
print "Writing %s at size %s to %s.tex"%(
|
||||
simple_tex, size, filestem
|
||||
)
|
||||
with open(template_tex_file, "r") as infile:
|
||||
body = infile.read()
|
||||
body = body.replace(SIZE_TO_REPLACE, size)
|
||||
body = body.replace(TEX_TEXT_TO_REPLACE, expression)
|
||||
with open(filestem + ".tex", "w") as outfile:
|
||||
outfile.write(body)
|
||||
commands = [
|
||||
"latex",
|
||||
"-interaction=batchmode",
|
||||
"-output-directory=" + TEX_DIR,
|
||||
filestem + ".tex"
|
||||
]
|
||||
#TODO, Error check
|
||||
os.system(" ".join(commands))
|
||||
assert os.path.exists(filestem + ".dvi")
|
||||
result = dvi_to_png(filestem + ".dvi")
|
||||
if not os.path.exists(filestem + ".dvi"):
|
||||
commands = [
|
||||
"latex",
|
||||
"-interaction=batchmode",
|
||||
"-output-directory=" + TEX_DIR,
|
||||
filestem + ".tex",
|
||||
"> /dev/null"
|
||||
]
|
||||
#TODO, Error check
|
||||
os.system(" ".join(commands))
|
||||
result = dvi_to_png(filestem + ".dvi")
|
||||
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):
|
||||
"""
|
||||
|
|
46
tk_scene.py
Normal file
46
tk_scene.py
Normal 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()
|
Loading…
Add table
Reference in a new issue