mirror of
https://github.com/3b1b/manim.git
synced 2025-04-13 09:47:07 +00:00
Refactored scene
This commit is contained in:
parent
75954ff01c
commit
e4b61dc5df
12 changed files with 239 additions and 220 deletions
137
constants.py
137
constants.py
|
@ -1,10 +1,15 @@
|
|||
import os
|
||||
import numpy as np
|
||||
|
||||
|
||||
DEFAULT_HEIGHT = 1440
|
||||
DEFAULT_WIDTH = 2560
|
||||
DEFAULT_FRAME_DURATION = 0.04
|
||||
|
||||
PRODUCTION_QUALITY_DISPLAY_CONFIG = {
|
||||
"height" : 1440,
|
||||
"width" : 2560,
|
||||
"frame_duration" : 0.04,
|
||||
"height" : DEFAULT_HEIGHT,
|
||||
"width" : DEFAULT_WIDTH ,
|
||||
"frame_duration" : DEFAULT_FRAME_DURATION,
|
||||
}
|
||||
|
||||
MEDIUM_QUALITY_DISPLAY_CONFIG = {
|
||||
|
@ -26,8 +31,6 @@ DEFAULT_POINT_DENSITY_1D = 200
|
|||
DEFAULT_POINT_THICKNESS = 3
|
||||
|
||||
#TODO, Make sure these are not needd
|
||||
DEFAULT_HEIGHT = PRODUCTION_QUALITY_DISPLAY_CONFIG["height"]
|
||||
DEFAULT_WIDTH = PRODUCTION_QUALITY_DISPLAY_CONFIG["width"]
|
||||
SPACE_HEIGHT = 4.0
|
||||
SPACE_WIDTH = SPACE_HEIGHT * DEFAULT_WIDTH / DEFAULT_HEIGHT
|
||||
|
||||
|
@ -37,7 +40,6 @@ DEFAULT_MOBJECT_TO_MOBJECT_BUFFER = 0.2
|
|||
|
||||
|
||||
#All in seconds
|
||||
DEFAULT_FRAME_DURATION = 0.04
|
||||
DEFAULT_ANIMATION_RUN_TIME = 1.0
|
||||
DEFAULT_POINTWISE_FUNCTION_RUN_TIME = 3.0
|
||||
DEFAULT_DITHER_TIME = 1.0
|
||||
|
@ -56,14 +58,14 @@ BOTTOM = SPACE_HEIGHT*DOWN
|
|||
LEFT_SIDE = SPACE_WIDTH*LEFT
|
||||
RIGHT_SIDE = SPACE_WIDTH*RIGHT
|
||||
|
||||
THIS_DIR = os.path.dirname(os.path.realpath(__file__))
|
||||
FILE_DIR = os.path.join(THIS_DIR, os.pardir, "animation_files")
|
||||
IMAGE_DIR = os.path.join(FILE_DIR, "images")
|
||||
GIF_DIR = os.path.join(FILE_DIR, "gifs")
|
||||
MOVIE_DIR = os.path.join(FILE_DIR, "movies")
|
||||
TEX_DIR = os.path.join(FILE_DIR, "Tex")
|
||||
TEX_IMAGE_DIR = os.path.join(IMAGE_DIR, "Tex")
|
||||
MOBJECT_DIR = os.path.join(FILE_DIR, "mobjects")
|
||||
THIS_DIR = os.path.dirname(os.path.realpath(__file__))
|
||||
FILE_DIR = os.path.join(THIS_DIR, os.pardir, "animation_files")
|
||||
IMAGE_DIR = os.path.join(FILE_DIR, "images")
|
||||
GIF_DIR = os.path.join(FILE_DIR, "gifs")
|
||||
MOVIE_DIR = os.path.join(FILE_DIR, "movies")
|
||||
TEX_DIR = os.path.join(FILE_DIR, "Tex")
|
||||
TEX_IMAGE_DIR = os.path.join(IMAGE_DIR, "Tex")
|
||||
MOBJECT_DIR = os.path.join(FILE_DIR, "mobjects")
|
||||
IMAGE_MOBJECT_DIR = os.path.join(MOBJECT_DIR, "image")
|
||||
|
||||
for folder in [IMAGE_DIR, GIF_DIR, MOVIE_DIR, TEX_DIR,
|
||||
|
@ -74,76 +76,67 @@ for folder in [IMAGE_DIR, GIF_DIR, MOVIE_DIR, TEX_DIR,
|
|||
PDF_DENSITY = 800
|
||||
SIZE_TO_REPLACE = "SizeHere"
|
||||
TEX_TEXT_TO_REPLACE = "YourTextHere"
|
||||
TEMPLATE_TEX_FILE = os.path.join(TEX_DIR, "template.tex")
|
||||
TEMPLATE_TEXT_FILE = os.path.join(TEX_DIR, "text_template.tex")
|
||||
TEMPLATE_TEX_FILE = os.path.join(THIS_DIR, "template.tex")
|
||||
TEMPLATE_TEXT_FILE = os.path.join(THIS_DIR, "text_template.tex")
|
||||
MAX_LEN_FOR_HUGE_TEX_FONT = 25
|
||||
|
||||
LOGO_PATH = os.path.join(IMAGE_DIR, "logo.png")
|
||||
|
||||
|
||||
PI_CREATURE_DIR = os.path.join(IMAGE_DIR, "PiCreature")
|
||||
PI_CREATURE_PART_NAME_TO_DIR = lambda name : os.path.join(PI_CREATURE_DIR, "pi_creature_"+name) + ".png"
|
||||
PI_CREATURE_SCALE_VAL = 0.5
|
||||
PI_CREATURE_MOUTH_TO_EYES_DISTANCE = 0.25
|
||||
|
||||
|
||||
### Colors ###
|
||||
|
||||
|
||||
COLOR_MAP = {
|
||||
"DARK_BLUE" : "#236B8E",
|
||||
"DARK_BROWN" : "#8B4513",
|
||||
"DARK_BLUE" : "#236B8E",
|
||||
"DARK_BROWN" : "#8B4513",
|
||||
"LIGHT_BROWN" : "#CD853F",
|
||||
"BLUE_A" : "#1C758A",
|
||||
"BLUE_B" : "#29ABCA",
|
||||
"BLUE_C" : "#58C4DD",
|
||||
"BLUE_D" : "#9CDCEB",
|
||||
"BLUE_E" : "#C7E9F1",
|
||||
"TEAL_A" : "#49A88F",
|
||||
"TEAL_B" : "#55C1A7",
|
||||
"TEAL_C" : "#5CD0B3",
|
||||
"TEAL_D" : "#76DDC0",
|
||||
"TEAL_E" : "#ACEAD7",
|
||||
"GREEN_A" : "#699C52",
|
||||
"GREEN_B" : "#77B05D",
|
||||
"GREEN_C" : "#83C167",
|
||||
"GREEN_D" : "#A6CF8C",
|
||||
"GREEN_E" : "#C9E2AE",
|
||||
"YELLOW_A" : "#E8C11C",
|
||||
"YELLOW_B" : "#F4D345",
|
||||
"YELLOW_C" : "#FCE15B",
|
||||
"YELLOW_D" : "#FFEA94",
|
||||
"YELLOW_E" : "#FFF1B6",
|
||||
"GOLD_A" : "#C78D46",
|
||||
"GOLD_B" : "#E1A158",
|
||||
"GOLD_C" : "#F0AC5F",
|
||||
"GOLD_D" : "#F9B775",
|
||||
"GOLD_E" : "#F7C797",
|
||||
"RED_A" : "#CF5044",
|
||||
"RED_B" : "#E65A4C",
|
||||
"RED_C" : "#FC6255",
|
||||
"RED_D" : "#FF8080",
|
||||
"RED_E" : "#F7A1A3",
|
||||
"MAROON_A" : "#94424F",
|
||||
"MAROON_B" : "#A24D61",
|
||||
"MAROON_C" : "#C55F73",
|
||||
"MAROON_D" : "#EC92AB",
|
||||
"MAROON_E" : "#ECABC1",
|
||||
"PURPLE_A" : "#644172",
|
||||
"PURPLE_B" : "#715582",
|
||||
"PURPLE_C" : "#9A72AC",
|
||||
"PURPLE_D" : "#B189C6",
|
||||
"PURPLE_E" : "#CAA3E8",
|
||||
"WHITE" : "#FFFFFF",
|
||||
"BLACK" : "#000000",
|
||||
"BLUE_A" : "#1C758A",
|
||||
"BLUE_B" : "#29ABCA",
|
||||
"BLUE_C" : "#58C4DD",
|
||||
"BLUE_D" : "#9CDCEB",
|
||||
"BLUE_E" : "#C7E9F1",
|
||||
"TEAL_A" : "#49A88F",
|
||||
"TEAL_B" : "#55C1A7",
|
||||
"TEAL_C" : "#5CD0B3",
|
||||
"TEAL_D" : "#76DDC0",
|
||||
"TEAL_E" : "#ACEAD7",
|
||||
"GREEN_A" : "#699C52",
|
||||
"GREEN_B" : "#77B05D",
|
||||
"GREEN_C" : "#83C167",
|
||||
"GREEN_D" : "#A6CF8C",
|
||||
"GREEN_E" : "#C9E2AE",
|
||||
"YELLOW_A" : "#E8C11C",
|
||||
"YELLOW_B" : "#F4D345",
|
||||
"YELLOW_C" : "#FCE15B",
|
||||
"YELLOW_D" : "#FFEA94",
|
||||
"YELLOW_E" : "#FFF1B6",
|
||||
"GOLD_A" : "#C78D46",
|
||||
"GOLD_B" : "#E1A158",
|
||||
"GOLD_C" : "#F0AC5F",
|
||||
"GOLD_D" : "#F9B775",
|
||||
"GOLD_E" : "#F7C797",
|
||||
"RED_A" : "#CF5044",
|
||||
"RED_B" : "#E65A4C",
|
||||
"RED_C" : "#FC6255",
|
||||
"RED_D" : "#FF8080",
|
||||
"RED_E" : "#F7A1A3",
|
||||
"MAROON_A" : "#94424F",
|
||||
"MAROON_B" : "#A24D61",
|
||||
"MAROON_C" : "#C55F73",
|
||||
"MAROON_D" : "#EC92AB",
|
||||
"MAROON_E" : "#ECABC1",
|
||||
"PURPLE_A" : "#644172",
|
||||
"PURPLE_B" : "#715582",
|
||||
"PURPLE_C" : "#9A72AC",
|
||||
"PURPLE_D" : "#B189C6",
|
||||
"PURPLE_E" : "#CAA3E8",
|
||||
"WHITE" : "#FFFFFF",
|
||||
"BLACK" : "#000000",
|
||||
}
|
||||
PALETTE = COLOR_MAP.values()
|
||||
global_dict = globals()
|
||||
global_dict.update(COLOR_MAP)
|
||||
for name in ["BLUE", "TEAL", "GREEN",
|
||||
"YELLOW", "GOLD", "RED",
|
||||
"MAROON", "PURPLE"]:
|
||||
global_dict[name] = global_dict[name + "_C"]
|
||||
globals().update(COLOR_MAP)
|
||||
for name in filter(lambda s : s.endswith("_C"), COLOR_MAP.keys()):
|
||||
globals()[name.replace("_C", "")] = globals()[name]
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -139,10 +139,10 @@ def write_to_movie(scene, name):
|
|||
file_path = get_file_path(name, ".mp4")
|
||||
print "Writing to %s"%file_path
|
||||
|
||||
fps = int(1/scene.display_config["frame_duration"])
|
||||
dim = (scene.display_config["width"], scene.display_config["height"])
|
||||
fps = int(1/scene.frame_duration)
|
||||
dim = (scene.width, scene.height)
|
||||
|
||||
command = [
|
||||
command = [
|
||||
FFMPEG_BIN,
|
||||
'-y', # overwrite output file if it exists
|
||||
'-f', 'rawvideo',
|
||||
|
|
|
@ -187,10 +187,8 @@ def main():
|
|||
inspect.getmembers(module, is_scene)
|
||||
)
|
||||
config["movie_prefix"] = config["module"]
|
||||
scene_kwargs = {
|
||||
"display_config" : config["display_config"],
|
||||
"announce_construction" : True
|
||||
}
|
||||
scene_kwargs = config["display_config"]
|
||||
scene_kwargs["announce_construction"] = True
|
||||
for SceneClass in get_scene_classes(scene_names_to_classes, config):
|
||||
for args in get_scene_args(SceneClass, config):
|
||||
scene_kwargs["construct_args"] = args
|
||||
|
|
71
generate_logo.py
Normal file
71
generate_logo.py
Normal file
|
@ -0,0 +1,71 @@
|
|||
|
||||
|
||||
|
||||
from animation.transform import Transform
|
||||
from mobject import Mobject
|
||||
from mobject.tex_mobject import TextMobject
|
||||
from topics.geometry import Circle
|
||||
from topics.three_dimensions import Sphere
|
||||
from scene import Scene
|
||||
|
||||
from helpers import *
|
||||
|
||||
|
||||
class LogoGeneration(Scene):
|
||||
DEFAULT_CONFIG = {
|
||||
"radius" : 1.5,
|
||||
"inner_radius_ratio" : 0.55,
|
||||
"circle_density" : 100,
|
||||
"circle_blue" : "skyblue",
|
||||
"circle_brown" : DARK_BROWN,
|
||||
"circle_repeats" : 5,
|
||||
"sphere_density" : 50,
|
||||
"sphere_blue" : DARK_BLUE,
|
||||
"sphere_brown" : LIGHT_BROWN,
|
||||
"interpolation_factor" : 0.3,
|
||||
"frame_duration" : 0.01,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
digest_config(self, {})
|
||||
circle = Circle(
|
||||
density = self.circle_density,
|
||||
color = self.circle_blue
|
||||
)
|
||||
circle.repeat(self.circle_repeats)
|
||||
circle.scale(self.radius)
|
||||
sphere = Sphere(
|
||||
density = self.sphere_density,
|
||||
color = self.sphere_blue
|
||||
)
|
||||
sphere.scale(self.radius)
|
||||
sphere.rotate(-np.pi / 7, [1, 0, 0])
|
||||
sphere.rotate(-np.pi / 7)
|
||||
iris = Mobject()
|
||||
Mobject.interpolate(
|
||||
circle, sphere, iris,
|
||||
self.interpolation_factor
|
||||
)
|
||||
for mob, color in [(iris, self.sphere_brown), (circle, self.circle_brown)]:
|
||||
mob.highlight(color, lambda (x, y, z) : x < 0 and y > 0)
|
||||
mob.highlight(
|
||||
"black",
|
||||
lambda point: np.linalg.norm(point) < \
|
||||
self.inner_radius_ratio*self.radius
|
||||
)
|
||||
name = TextMobject("3Blue1Brown").center()
|
||||
name.highlight("grey")
|
||||
name.shift(2*DOWN)
|
||||
|
||||
self.play(Transform(
|
||||
circle, iris,
|
||||
run_time = DEFAULT_ANIMATION_RUN_TIME
|
||||
))
|
||||
self.frames = drag_pixels(self.frames)
|
||||
self.set_frame_as_background()
|
||||
self.save_image()
|
||||
self.add(name)
|
||||
self.dither()
|
||||
print "Dragging pixels..."
|
||||
|
||||
|
|
@ -11,6 +11,12 @@ import re
|
|||
|
||||
from constants import *
|
||||
|
||||
def list_update(l1, l2):
|
||||
return filter(lambda e : e not in l2, l1) + l2
|
||||
|
||||
def all_elements_are_instances(iterable, Class):
|
||||
return all(map(lambda e : isinstance(e, Class), iterable))
|
||||
|
||||
def adjascent_pairs(objects):
|
||||
return zip(objects, list(objects[1:])+[objects[0]])
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@ def generate_tex_file(expression, size, template_tex_file):
|
|||
|
||||
def tex_to_dvi(tex_file):
|
||||
result = tex_file.replace(".tex", ".dvi")
|
||||
if not os.path.exists(filestem + ".dvi"):
|
||||
if not os.path.exists(result):
|
||||
commands = [
|
||||
"latex",
|
||||
"-interaction=batchmode",
|
||||
|
@ -122,7 +122,7 @@ def dvi_to_png(dvi_file, regen_if_exists = False):
|
|||
"convert",
|
||||
"-density",
|
||||
str(PDF_DENSITY),
|
||||
path,
|
||||
dvi_file,
|
||||
"-size",
|
||||
str(DEFAULT_WIDTH) + "x" + str(DEFAULT_HEIGHT),
|
||||
os.path.join(images_dir, name + ".png")
|
||||
|
|
|
@ -1,62 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import numpy as np
|
||||
import itertools as it
|
||||
from copy import deepcopy
|
||||
import sys
|
||||
|
||||
|
||||
from animation import *
|
||||
from mobject import *
|
||||
from constants import *
|
||||
from region import *
|
||||
from scene import Scene
|
||||
|
||||
class LogoGeneration(Scene):
|
||||
LOGO_RADIUS = 1.5
|
||||
INNER_RADIUS_RATIO = 0.55
|
||||
CIRCLE_DENSITY = 100
|
||||
CIRCLE_BLUE = "skyblue"
|
||||
SPHERE_DENSITY = 50
|
||||
SPHERE_BLUE = DARK_BLUE
|
||||
CIRCLE_SPHERE_INTERPOLATION = 0.3
|
||||
FRAME_DURATION = 0.01
|
||||
|
||||
def construct(self):
|
||||
self.frame_duration = FRAME_DURATION
|
||||
circle = Circle(
|
||||
density = self.CIRCLE_DENSITY,
|
||||
color = self.CIRCLE_BLUE
|
||||
).repeat(5).scale(self.LOGO_RADIUS)
|
||||
sphere = Sphere(
|
||||
density = self.SPHERE_DENSITY,
|
||||
color = self.SPHERE_BLUE
|
||||
).scale(self.LOGO_RADIUS)
|
||||
sphere.rotate(-np.pi / 7, [1, 0, 0])
|
||||
sphere.rotate(-np.pi / 7)
|
||||
alpha = 0.3
|
||||
iris = Mobject()
|
||||
Mobject.interpolate(
|
||||
circle, sphere, iris,
|
||||
self.CIRCLE_SPHERE_INTERPOLATION
|
||||
)
|
||||
for mob, color in [(iris, LIGHT_BROWN), (circle, DARK_BROWN)]:
|
||||
mob.highlight(color, lambda (x, y, z) : x < 0 and y > 0)
|
||||
mob.highlight(
|
||||
"black",
|
||||
lambda point: np.linalg.norm(point) < \
|
||||
self.INNER_RADIUS_RATIO*self.LOGO_RADIUS
|
||||
)
|
||||
name = TextMobject("3Blue1Brown").center()
|
||||
name.highlight("grey")
|
||||
name.shift(2*DOWN)
|
||||
|
||||
self.play(Transform(
|
||||
circle, iris,
|
||||
run_time = DEFAULT_ANIMATION_RUN_TIME
|
||||
))
|
||||
self.add(name)
|
||||
self.dither()
|
||||
print "Dragging pixels..."
|
||||
self.frames = drag_pixels(self.frames)
|
||||
|
|
@ -14,33 +14,34 @@ from helpers import *
|
|||
import displayer as disp
|
||||
from tk_scene import TkSceneRoot
|
||||
from mobject import Mobject
|
||||
from animation.transform import ApplyMethod
|
||||
|
||||
class Scene(object):
|
||||
DEFAULT_CONFIG = {
|
||||
"display_config" : PRODUCTION_QUALITY_DISPLAY_CONFIG,
|
||||
"construct_args" : [],
|
||||
"background" : None,
|
||||
"start_dither_time" : DEFAULT_DITHER_TIME,
|
||||
"height" : DEFAULT_HEIGHT,
|
||||
"width" : DEFAULT_WIDTH ,
|
||||
"frame_duration" : DEFAULT_FRAME_DURATION,
|
||||
"construct_args" : [],
|
||||
"background" : None,
|
||||
"start_dither_time" : DEFAULT_DITHER_TIME,
|
||||
"announce_construction" : False,
|
||||
}
|
||||
def __init__(self, **kwargs):
|
||||
digest_config(self, kwargs)
|
||||
if self.announce_construction:
|
||||
print "Constructing %s..."%str(self)
|
||||
self.frame_duration = self.display_config["frame_duration"]
|
||||
self.frames = []
|
||||
self.mobjects = []
|
||||
if self.background:
|
||||
self.original_background = np.array(background)
|
||||
#TODO, Error checking?
|
||||
else:
|
||||
self.original_background = np.zeros(
|
||||
(self.display_config["height"], self.display_config["width"], 3),
|
||||
(self.height, self.width, 3),
|
||||
dtype = 'uint8'
|
||||
)
|
||||
self.background = self.original_background
|
||||
self.shape = self.background.shape[:2]
|
||||
#TODO, space shape
|
||||
self.background = self.original_background
|
||||
self.frames = [self.background]
|
||||
self.mobjects = []
|
||||
|
||||
self.construct(*self.construct_args)
|
||||
|
||||
def construct(self):
|
||||
|
@ -56,18 +57,23 @@ class Scene(object):
|
|||
self.name = name
|
||||
return self
|
||||
|
||||
def get_frame(self):
|
||||
return self.frames[-1]
|
||||
|
||||
def set_frame(self, frame):
|
||||
self.frames[-1] = frame
|
||||
return self
|
||||
|
||||
def add(self, *mobjects):
|
||||
"""
|
||||
Mobjects will be displayed, from background to foreground,
|
||||
in the order with which they are entered.
|
||||
"""
|
||||
for mobject in mobjects:
|
||||
if not isinstance(mobject, Mobject):
|
||||
raise Exception("Adding something which is not a mobject")
|
||||
#In case it's already in there, it should
|
||||
#now be closer to the foreground.
|
||||
self.remove(mobject)
|
||||
self.mobjects.append(mobject)
|
||||
if not all_elements_are_instances(mobjects, Mobject):
|
||||
raise Exception("Adding something which is not a mobject")
|
||||
self.set_frame(disp.paint_mobjects(mobjects, self.get_frame()))
|
||||
old_mobjects = filter(lambda m : m not in mobjects, self.mobjects)
|
||||
self.mobjects = old_mobjects + list(mobjects)
|
||||
return self
|
||||
|
||||
def add_local_mobjects(self):
|
||||
|
@ -81,11 +87,13 @@ class Scene(object):
|
|||
))
|
||||
|
||||
def remove(self, *mobjects):
|
||||
for mobject in mobjects:
|
||||
if not isinstance(mobject, Mobject):
|
||||
raise Exception("Removing something which is not a mobject")
|
||||
while mobject in self.mobjects:
|
||||
self.mobjects.remove(mobject)
|
||||
if not all_elements_are_instances(mobjects, Mobject):
|
||||
raise Exception("Removing something which is not a mobject")
|
||||
mobjects = filter(lambda m : m in self.mobjects, mobjects)
|
||||
if len(mobjects):
|
||||
return
|
||||
self.mobjects = filter(lambda m : m not in mobjects, self.mobjects)
|
||||
self.repaint_mojects()
|
||||
return self
|
||||
|
||||
def bring_to_front(self, mobject):
|
||||
|
@ -95,11 +103,13 @@ class Scene(object):
|
|||
def bring_to_back(self, mobject):
|
||||
self.remove(mobject)
|
||||
self.mobjects = [mobject] + self.mobjects
|
||||
self.repaint_mojects()
|
||||
return self
|
||||
|
||||
def clear(self):
|
||||
self.reset_background()
|
||||
self.remove(*self.mobjects)
|
||||
self.mobjects = []
|
||||
self.set_frame(self.background)
|
||||
return self
|
||||
|
||||
def highlight_region(self, region, color = None):
|
||||
|
@ -108,6 +118,7 @@ class Scene(object):
|
|||
image_array = self.background,
|
||||
color = color,
|
||||
)
|
||||
self.repaint_mojects()
|
||||
return self
|
||||
|
||||
def highlight_region_over_time_range(self, region, time_range = None, color = "black"):
|
||||
|
@ -128,6 +139,10 @@ class Scene(object):
|
|||
self.background = self.original_background
|
||||
return self
|
||||
|
||||
def repaint_mojects(self):
|
||||
self.set_frame(disp.paint_mobjects(self.mobjects, self.background))
|
||||
return self
|
||||
|
||||
def paint_into_background(self, *mobjects):
|
||||
#This way current mobjects don't have to be redrawn with
|
||||
#every change, and one can later call "apply" without worrying
|
||||
|
@ -135,6 +150,9 @@ class Scene(object):
|
|||
self.background = disp.paint_mobjects(mobjects, self.background)
|
||||
return self
|
||||
|
||||
def set_frame_as_background(self):
|
||||
self.background = self.get_frame()
|
||||
|
||||
def play(self, *animations, **kwargs):
|
||||
if "run_time" in kwargs:
|
||||
run_time = kwargs["run_time"]
|
||||
|
@ -188,9 +206,6 @@ class Scene(object):
|
|||
def apply(self, mobject_method, *args, **kwargs):
|
||||
self.play(ApplyMethod(mobject_method, *args, **kwargs))
|
||||
|
||||
def get_frame(self):
|
||||
return disp.paint_mobjects(self.mobjects, self.background)
|
||||
|
||||
def dither(self, duration = DEFAULT_DITHER_TIME):
|
||||
self.frames += [self.get_frame()]*int(duration / self.frame_duration)
|
||||
return self
|
||||
|
|
|
@ -3,6 +3,11 @@ from helpers import *
|
|||
from mobject import Mobject, CompoundMobject
|
||||
from image_mobject import ImageMobject
|
||||
|
||||
PI_CREATURE_DIR = os.path.join(IMAGE_DIR, "PiCreature")
|
||||
PI_CREATURE_PART_NAME_TO_DIR = lambda name : os.path.join(PI_CREATURE_DIR, "pi_creature_"+name) + ".png"
|
||||
PI_CREATURE_SCALE_VAL = 0.5
|
||||
PI_CREATURE_MOUTH_TO_EYES_DISTANCE = 0.25
|
||||
|
||||
class PiCreature(CompoundMobject):
|
||||
DEFAULT_COLOR = BLUE
|
||||
PART_NAMES = [
|
||||
|
|
|
@ -11,22 +11,23 @@ def complex_string(complex_num):
|
|||
|
||||
class ComplexPlane(NumberPlane):
|
||||
DEFAULT_CONFIG = {
|
||||
"color" : GREEN,
|
||||
"color" : GREEN,
|
||||
"unit_to_spatial_width" : 1,
|
||||
"line_frequency" : 1,
|
||||
"faded_line_frequency" : 0.5,
|
||||
"number_at_center" : complex(0),
|
||||
"line_frequency" : 1,
|
||||
"faded_line_frequency" : 0.5,
|
||||
"number_at_center" : complex(0),
|
||||
}
|
||||
def __init__(self, **kwargs):
|
||||
digest_config(self, kwargs)
|
||||
kwargs.update({
|
||||
"x_unit_to_spatial_width" : self.unit_to_spatial_width,
|
||||
"x_unit_to_spatial_width" : self.unit_to_spatial_width,
|
||||
"y_uint_to_spatial_height" : self.unit_to_spatial_width,
|
||||
"x_line_frequency" : self.line_frequency,
|
||||
"x_faded_line_frequency" : self.faded_line_frequency,
|
||||
"y_line_frequency" : self.line_frequency,
|
||||
"y_faded_line_frequency" : self.faded_line_frequency,
|
||||
"num_pair_at_center" : (self.number_at_center.real, self.number_at_center.imag),
|
||||
"x_line_frequency" : self.line_frequency,
|
||||
"x_faded_line_frequency" : self.faded_line_frequency,
|
||||
"y_line_frequency" : self.line_frequency,
|
||||
"y_faded_line_frequency" : self.faded_line_frequency,
|
||||
"num_pair_at_center" : (self.number_at_center.real,
|
||||
self.number_at_center.imag),
|
||||
})
|
||||
NumberPlane.__init__(self, **kwargs)
|
||||
|
||||
|
@ -88,23 +89,15 @@ class ComplexFunction(ApplyPointwiseFunction):
|
|||
)
|
||||
|
||||
class ComplexHomotopy(Homotopy):
|
||||
def __init__(self, complex_homotopy, **kwargs):
|
||||
def __init__(self, complex_homotopy, mobject = ComplexPlane, **kwargs):
|
||||
"""
|
||||
Complex Hootopy a function (z, t) to z'
|
||||
Complex Hootopy a function Cx[0, 1] to C
|
||||
"""
|
||||
def homotopy((x, y, z, t)):
|
||||
c = complex_homotopy((complex(x, y), t))
|
||||
return (c.real, c.imag, z)
|
||||
if len(args) > 0:
|
||||
args = list(args)
|
||||
mobject = args.pop(0)
|
||||
elif "mobject" in kwargs:
|
||||
mobject = kwargs["mobject"]
|
||||
else:
|
||||
mobject = Grid()
|
||||
Homotopy.__init__(self, homotopy, mobject, *args, **kwargs)
|
||||
self.name = "ComplexHomotopy" + \
|
||||
to_cammel_case(complex_homotopy.__name__)
|
||||
|
||||
|
||||
class ComplexMultiplication(Scene):
|
||||
@staticmethod
|
||||
|
|
|
@ -21,7 +21,7 @@ class Dot(Mobject1D): #Use 1D density, even though 2D
|
|||
|
||||
class Cross(Mobject1D):
|
||||
DEFAULT_CONFIG = {
|
||||
"color" : YELLOW,
|
||||
"color" : YELLOW,
|
||||
"radius" : 0.3
|
||||
}
|
||||
def __init__(self, center_point = ORIGIN, **kwargs):
|
||||
|
@ -76,7 +76,7 @@ class Line(Mobject1D):
|
|||
|
||||
class Arrow(Line):
|
||||
DEFAULT_CONFIG = {
|
||||
"color" : WHITE,
|
||||
"color" : WHITE,
|
||||
"tip_length" : 0.25
|
||||
}
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -132,8 +132,8 @@ class CurvedLine(Line):
|
|||
|
||||
class PartialCircle(Mobject1D):
|
||||
DEFAULT_CONFIG = {
|
||||
"radius" : 1.0,
|
||||
"start_angle" : 0
|
||||
"radius" : 1.0,
|
||||
"start_angle" : 0,
|
||||
}
|
||||
def __init__(self, angle, **kwargs):
|
||||
digest_locals(self)
|
||||
|
@ -159,7 +159,7 @@ class Circle(PartialCircle):
|
|||
|
||||
class Polygon(Mobject1D):
|
||||
DEFAULT_CONFIG = {
|
||||
"color" : GREEN_D,
|
||||
"color" : GREEN_D,
|
||||
"edge_colors" : None
|
||||
}
|
||||
def __init__(self, *points, **kwargs):
|
||||
|
@ -184,9 +184,9 @@ class Polygon(Mobject1D):
|
|||
|
||||
class Rectangle(Mobject1D):
|
||||
DEFAULT_CONFIG = {
|
||||
"color" : YELLOW,
|
||||
"color" : YELLOW,
|
||||
"height" : 2.0,
|
||||
"width" : 4.0
|
||||
"width" : 4.0
|
||||
}
|
||||
def generate_points(self):
|
||||
wh = [self.width/2.0, self.height/2.0]
|
||||
|
|
|
@ -5,15 +5,15 @@ from scene import Scene
|
|||
|
||||
class NumberLine(Mobject1D):
|
||||
DEFAULT_CONFIG = {
|
||||
"color" : BLUE,
|
||||
"numerical_radius" : SPACE_WIDTH,
|
||||
"color" : BLUE,
|
||||
"numerical_radius" : SPACE_WIDTH,
|
||||
"unit_length_to_spatial_width" : 1,
|
||||
"tick_size" : 0.1,
|
||||
"tick_frequency" : 0.5,
|
||||
"leftmost_tick" : None,
|
||||
"number_at_center" : 0,
|
||||
"tick_size" : 0.1,
|
||||
"tick_frequency" : 0.5,
|
||||
"leftmost_tick" : None,
|
||||
"number_at_center" : 0,
|
||||
"numbers_with_elongated_ticks" : [0],
|
||||
"longer_tick_multiple" : 2,
|
||||
"longer_tick_multiple" : 2,
|
||||
}
|
||||
def __init__(self, **kwargs):
|
||||
digest_config(self, kwargs)
|
||||
|
@ -100,29 +100,29 @@ class NumberLine(Mobject1D):
|
|||
|
||||
class UnitInterval(NumberLine):
|
||||
DEFAULT_CONFIG = {
|
||||
"numerical_radius" : 0.5,
|
||||
"numerical_radius" : 0.5,
|
||||
"unit_length_to_spatial_width" : 2*(SPACE_WIDTH-1),
|
||||
"tick_frequency" : 0.1,
|
||||
"leftmost_tick" : 0,
|
||||
"number_at_center" : 0.5,
|
||||
"tick_frequency" : 0.1,
|
||||
"leftmost_tick" : 0,
|
||||
"number_at_center" : 0.5,
|
||||
"numbers_with_elongated_ticks" : [0, 1],
|
||||
}
|
||||
|
||||
|
||||
class NumberPlane(Mobject1D):
|
||||
DEFAULT_CONFIG = {
|
||||
"color" : BLUE,
|
||||
"x_radius" : SPACE_WIDTH,
|
||||
"y_radius" : SPACE_HEIGHT,
|
||||
"x_unit_to_spatial_width" : 1,
|
||||
"color" : BLUE,
|
||||
"x_radius" : SPACE_WIDTH,
|
||||
"y_radius" : SPACE_HEIGHT,
|
||||
"x_unit_to_spatial_width" : 1,
|
||||
"y_uint_to_spatial_height" : 1,
|
||||
"x_line_frequency" : 1,
|
||||
"x_faded_line_frequency" : 0.5,
|
||||
"y_line_frequency" : 1,
|
||||
"y_faded_line_frequency" : 0.5,
|
||||
"fade_factor" : 0.3,
|
||||
"number_scale_factor" : 0.25,
|
||||
"num_pair_at_center" : np.array((0, 0)),
|
||||
"x_line_frequency" : 1,
|
||||
"x_faded_line_frequency" : 0.5,
|
||||
"y_line_frequency" : 1,
|
||||
"y_faded_line_frequency" : 0.5,
|
||||
"fade_factor" : 0.3,
|
||||
"number_scale_factor" : 0.25,
|
||||
"num_pair_at_center" : np.array((0, 0)),
|
||||
}
|
||||
|
||||
def generate_points(self):
|
||||
|
|
Loading…
Add table
Reference in a new issue