mirror of
https://github.com/3b1b/manim.git
synced 2025-04-13 09:47:07 +00:00
259 lines
6.1 KiB
Python
259 lines
6.1 KiB
Python
![]() |
#!/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, SceneFromVideo
|
||
|
from script_wrapper import command_line_create_scene
|
||
|
|
||
|
MOVIE_PREFIX = "counting_in_binary/"
|
||
|
BASE_HAND_FILE = os.path.join(MOVIE_DIR, MOVIE_PREFIX, "Base.mp4")
|
||
|
FORCED_FRAME_DURATION = 0.02
|
||
|
TIME_RANGE = (0, 42)
|
||
|
INITIAL_PADDING = 27
|
||
|
NUM_GOOD_FRAMES = 1223
|
||
|
|
||
|
ALGORITHM_TEXT = [
|
||
|
"""
|
||
|
\\begin{flushleft}
|
||
|
Turn up the rightmost finger that is down.
|
||
|
""", """
|
||
|
Turn down all fingers to its right.
|
||
|
\\end{flushleft}
|
||
|
"""
|
||
|
]
|
||
|
FINGER_WORDS = [
|
||
|
"Thumb",
|
||
|
"Index Finger",
|
||
|
"Middle Finger",
|
||
|
"Ring Finger",
|
||
|
"Pinky",
|
||
|
]
|
||
|
|
||
|
COUNT_TO_FRAME_NUM = {
|
||
|
0 : 0,
|
||
|
1 : 27,
|
||
|
2 : 76,
|
||
|
3 : 110,
|
||
|
4 : 163,
|
||
|
5 : 189,
|
||
|
6 : 226,
|
||
|
7 : 264,
|
||
|
8 : 318,
|
||
|
9 : 356,
|
||
|
10 : 384,
|
||
|
11 : 423,
|
||
|
12 : 457,
|
||
|
13 : 513,
|
||
|
14 : 528,
|
||
|
15 : 590,
|
||
|
16 : 620,
|
||
|
17 : 671,
|
||
|
18 : 691,
|
||
|
19 : 740,
|
||
|
20 : 781,
|
||
|
21 : 810,
|
||
|
22 : 855,
|
||
|
23 : 881,
|
||
|
24 : 940,
|
||
|
25 : 970,
|
||
|
26 : 1014,
|
||
|
27 : 1055,
|
||
|
28 : 1092,
|
||
|
29 : 1143,
|
||
|
30 : 1184,
|
||
|
31 : 1219,
|
||
|
}
|
||
|
|
||
|
class Hand(ImageMobject):
|
||
|
def __init__(self, num, **kwargs):
|
||
|
Mobject2D.__init__(self, **kwargs)
|
||
|
path = os.path.join(
|
||
|
MOVIE_DIR, MOVIE_PREFIX, "images", "Hand%d.png"%num
|
||
|
)
|
||
|
invert = False
|
||
|
if self.read_in_cached_attrs(path, invert):
|
||
|
return
|
||
|
ImageMobject.__init__(self, path, invert = invert)
|
||
|
center = self.get_center()
|
||
|
self.center()
|
||
|
self.rotate(np.pi, axis = RIGHT+UP)
|
||
|
self.sort_points(lambda p : np.log(complex(*p[:2])).imag)
|
||
|
self.rotate(np.pi, axis = RIGHT+UP)
|
||
|
self.shift(center)
|
||
|
self.cache_attrs(path, invert = False)
|
||
|
|
||
|
# def highlight_thumb(self, color = "yellow"):
|
||
|
# self.highlight(
|
||
|
# color = color,
|
||
|
# condition = lambda p : p[0] > 4.5 and p[1] > -1.5
|
||
|
# )
|
||
|
|
||
|
def get_algorithm():
|
||
|
return text_mobject(ALGORITHM_TEXT)
|
||
|
|
||
|
def get_finger_colors():
|
||
|
return list(Color("yellow").range_to("red", 5))
|
||
|
|
||
|
def five_char_binary(num):
|
||
|
result = bin(num)[2:]
|
||
|
return (5-len(result))*"0" + result
|
||
|
|
||
|
def read_reversed_binary(string):
|
||
|
return sum([
|
||
|
2**count if char == '1' else 0
|
||
|
for count, char in zip(it.count(), string)
|
||
|
])
|
||
|
|
||
|
class LeftHand(Hand):
|
||
|
def __init__(self, num, **kwargs):
|
||
|
Hand.__init__(
|
||
|
self,
|
||
|
read_reversed_binary(five_char_binary(num)),
|
||
|
**kwargs
|
||
|
)
|
||
|
self.rotate(np.pi, UP)
|
||
|
self.to_edge(LEFT)
|
||
|
|
||
|
def get_hand_map(which_hand = "right"):
|
||
|
if which_hand == "right":
|
||
|
Class = Hand
|
||
|
elif which_hand == "left":
|
||
|
Class = LeftHand
|
||
|
else:
|
||
|
print "Bad arg, bro"
|
||
|
return
|
||
|
return dict([
|
||
|
(num, Class(num))
|
||
|
for num in range(32)
|
||
|
])
|
||
|
|
||
|
class OverHand(SceneFromVideo):
|
||
|
def construct(self):
|
||
|
SceneFromVideo.construct(self, BASE_HAND_FILE)
|
||
|
self.frame_duration = FORCED_FRAME_DURATION
|
||
|
self.frames = self.frames[:NUM_GOOD_FRAMES]
|
||
|
|
||
|
|
||
|
class SaveEachNumber(OverHand):
|
||
|
def construct(self):
|
||
|
OverHand.construct(self)
|
||
|
for count in COUNT_TO_FRAME_NUM:
|
||
|
path = os.path.join(
|
||
|
MOVIE_DIR, MOVIE_PREFIX, "images",
|
||
|
"Hand%d.png"%count
|
||
|
)
|
||
|
Image.fromarray(self.frames[COUNT_TO_FRAME_NUM[count]]).save(path)
|
||
|
|
||
|
def write_to_movie(self, name = None):
|
||
|
print "Why bother writing to movie..."
|
||
|
|
||
|
class ShowCounting(OverHand):
|
||
|
def construct(self):
|
||
|
OverHand.construct(self)
|
||
|
self.frames = INITIAL_PADDING*[self.frames[0]] + self.frames
|
||
|
num_frames = len(self.frames)
|
||
|
self.frames = [
|
||
|
disp.paint_mobject(
|
||
|
self.get_counting_mob(32*count // num_frames),
|
||
|
frame
|
||
|
)
|
||
|
for frame, count in zip(self.frames, it.count())
|
||
|
]
|
||
|
|
||
|
def get_counting_mob(self, count):
|
||
|
mob = tex_mobject(str(count))
|
||
|
mob.scale(2)
|
||
|
mob.shift(LEFT)
|
||
|
mob.to_edge(UP, buff = 0.1)
|
||
|
return mob
|
||
|
|
||
|
|
||
|
class ShowFrameNum(OverHand):
|
||
|
def construct(self):
|
||
|
OverHand.construct(self)
|
||
|
for frame, count in zip(self.frames, it.count()):
|
||
|
print count, "of", len(self.frames)
|
||
|
mob = CompoundMobject(*[
|
||
|
tex_mobject(char).shift(0.3*x*RIGHT)
|
||
|
for char, x, in zip(str(count), it.count())
|
||
|
])
|
||
|
self.frames[count] = disp.paint_mobject(
|
||
|
mob.to_corner(UP+LEFT),
|
||
|
frame
|
||
|
)
|
||
|
|
||
|
class CountTo1023(Scene):
|
||
|
def construct(self):
|
||
|
rh_map = get_hand_map("right")
|
||
|
lh_map = get_hand_map("left")
|
||
|
for mob in rh_map.values()+lh_map.values():
|
||
|
mob.scale(0.9)
|
||
|
mob.to_edge(DOWN, buff = 0)
|
||
|
for mob in rh_map.values():
|
||
|
mob.to_edge(RIGHT)
|
||
|
for mob in lh_map.values():
|
||
|
mob.to_edge(LEFT)
|
||
|
def get_num(count):
|
||
|
return CompoundMobject(*[
|
||
|
tex_mobject(char).shift(0.35*x*RIGHT)
|
||
|
for char, x, in zip(str(count), it.count())
|
||
|
]).center().to_edge(UP)
|
||
|
self.frames = [
|
||
|
disp.paint_mobject(CompoundMobject(
|
||
|
rh_map[count%32], lh_map[count//32], get_num(count)
|
||
|
))
|
||
|
for count in range(2**10)
|
||
|
]
|
||
|
|
||
|
class Introduction(Scene):
|
||
|
def construct(self):
|
||
|
words = text_mobject("""
|
||
|
First, let's see how to count
|
||
|
to 31 on just one hand...
|
||
|
""")
|
||
|
hand = Hand(0)
|
||
|
for mob in words, hand:
|
||
|
mob.sort_points(lambda p : p[0])
|
||
|
|
||
|
self.add(words)
|
||
|
self.dither()
|
||
|
self.animate(DelayByOrder(Transform(words, hand)))
|
||
|
self.dither()
|
||
|
|
||
|
class ShowReadingRule(Scene):
|
||
|
def construct(self):
|
||
|
pass
|
||
|
|
||
|
class CountWithReadingRule(ShowCounting):
|
||
|
def get_counting_mob(self, count):
|
||
|
pass
|
||
|
|
||
|
class ShowIncrementRule(Scene):
|
||
|
def construct(self):
|
||
|
pass
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
command_line_create_scene(MOVIE_PREFIX)
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|