mirror of
https://github.com/3b1b/manim.git
synced 2025-08-05 16:49:03 +00:00
More moser, count method of scene implemented
This commit is contained in:
parent
d79db9d142
commit
5aff0b6374
6 changed files with 149 additions and 31 deletions
16
animation.py
16
animation.py
|
@ -14,7 +14,7 @@ from constants import *
|
||||||
from mobject import Mobject
|
from mobject import Mobject
|
||||||
|
|
||||||
class Animation(object):
|
class Animation(object):
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
mobject,
|
mobject,
|
||||||
run_time = DEFAULT_ANIMATION_RUN_TIME,
|
run_time = DEFAULT_ANIMATION_RUN_TIME,
|
||||||
alpha_func = high_inflection_0_to_1,
|
alpha_func = high_inflection_0_to_1,
|
||||||
|
@ -217,6 +217,18 @@ class Transform(Animation):
|
||||||
)[self.non_redundant_m2_indices]
|
)[self.non_redundant_m2_indices]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
class FadeToColor(Transform):
|
||||||
|
def __init__(self, mobject, color, *args, **kwargs):
|
||||||
|
target = copy.deepcopy(mobject).highlight(color)
|
||||||
|
Transform.__init__(self, mobject, target, *args, **kwargs)
|
||||||
|
|
||||||
|
class ScaleInPlace(Transform):
|
||||||
|
def __init__(self, mobject, scale_factor, *args, **kwargs):
|
||||||
|
target = copy.deepcopy(mobject)
|
||||||
|
center = mobject.get_center()
|
||||||
|
target.shift(-center).scale(scale_factor).shift(center)
|
||||||
|
Transform.__init__(self, mobject, target, *args, **kwargs)
|
||||||
|
|
||||||
class ApplyMethod(Transform):
|
class ApplyMethod(Transform):
|
||||||
def __init__(self, method, mobject, *args, **kwargs):
|
def __init__(self, method, mobject, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
@ -232,7 +244,7 @@ class ApplyMethod(Transform):
|
||||||
mobject,
|
mobject,
|
||||||
method(copy.deepcopy(mobject), *method_args),
|
method(copy.deepcopy(mobject), *method_args),
|
||||||
*args, **kwargs
|
*args, **kwargs
|
||||||
)
|
)
|
||||||
|
|
||||||
class ApplyFunction(Transform):
|
class ApplyFunction(Transform):
|
||||||
def __init__(self, function, mobject, run_time = DEFAULT_ANIMATION_RUN_TIME,
|
def __init__(self, function, mobject, run_time = DEFAULT_ANIMATION_RUN_TIME,
|
||||||
|
|
|
@ -130,6 +130,7 @@ class Mobject(object):
|
||||||
"""
|
"""
|
||||||
Condition is function which takes in one arguments, (x, y, z).
|
Condition is function which takes in one arguments, (x, y, z).
|
||||||
"""
|
"""
|
||||||
|
#TODO, Should self.color change?
|
||||||
to_change = np.apply_along_axis(condition, 1, self.points)
|
to_change = np.apply_along_axis(condition, 1, self.points)
|
||||||
self.rgbs[to_change, :] *= 0
|
self.rgbs[to_change, :] *= 0
|
||||||
self.rgbs[to_change, :] += Color(color).get_rgb()
|
self.rgbs[to_change, :] += Color(color).get_rgb()
|
||||||
|
|
0
moser/__init__.py
Normal file
0
moser/__init__.py
Normal file
125
moser/main.py
125
moser/main.py
|
@ -36,10 +36,17 @@ class CircleScene(Scene):
|
||||||
##################################################
|
##################################################
|
||||||
|
|
||||||
def count_lines(*radians):
|
def count_lines(*radians):
|
||||||
|
#TODO, Count things explicitly?
|
||||||
sc = CircleScene(radians)
|
sc = CircleScene(radians)
|
||||||
text = tex_mobject(r"\text{How Many Lines?}", size = r"\large")
|
|
||||||
text_center = (sc.radius + 1, sc.radius -1, 0)
|
text_center = (sc.radius + 1, sc.radius -1, 0)
|
||||||
text.scale(0.4).shift(text_center)
|
scale_factor = 0.4
|
||||||
|
text = tex_mobject(r"\text{How Many Lines?}", size = r"\large")
|
||||||
|
n = len(radians)
|
||||||
|
formula, answer = tex_mobject([
|
||||||
|
r"{%d \choose 2} = \frac{%d(%d - 1)}{2} = "%(n, n, n),
|
||||||
|
str(choose(n, 2))
|
||||||
|
])
|
||||||
|
text.scale(scale_factor).shift(text_center)
|
||||||
x = text_center[0]
|
x = text_center[0]
|
||||||
new_lines = [
|
new_lines = [
|
||||||
Line((x-1, y, 0), (x+1, y, 0))
|
Line((x-1, y, 0), (x+1, y, 0))
|
||||||
|
@ -55,6 +62,16 @@ def count_lines(*radians):
|
||||||
Transform(line1, line2, run_time = 2)
|
Transform(line1, line2, run_time = 2)
|
||||||
for line1, line2 in zip(sc.lines, new_lines)
|
for line1, line2 in zip(sc.lines, new_lines)
|
||||||
])
|
])
|
||||||
|
sc.dither()
|
||||||
|
sc.remove(text)
|
||||||
|
sc.count(new_lines)
|
||||||
|
anims = [FadeIn(formula)]
|
||||||
|
for mob in sc.mobjects:
|
||||||
|
if mob == sc.number: #put in during animate_count
|
||||||
|
anims.append(Transform(mob, answer))
|
||||||
|
else:
|
||||||
|
anims.append(FadeOut(mob))
|
||||||
|
sc.animate(*anims, run_time = 1)
|
||||||
return sc
|
return sc
|
||||||
|
|
||||||
|
|
||||||
|
@ -63,35 +80,44 @@ def count_intersection_points(*radians):
|
||||||
radians.sort()
|
radians.sort()
|
||||||
sc = CircleScene(radians)
|
sc = CircleScene(radians)
|
||||||
intersection_points = [
|
intersection_points = [
|
||||||
intersection([p[0], p[2]], [p[1], p[3]])
|
intersection((p[0], p[2]), (p[1], p[3]))
|
||||||
for p in it.combinations(sc.points, 4)
|
for p in it.combinations(sc.points, 4)
|
||||||
]
|
]
|
||||||
intersection_dots = CompoundMobject(*[
|
intersection_dots = [Dot(point) for point in intersection_points]
|
||||||
Dot(point) for point in intersection_points
|
text_center = (sc.radius + 1, sc.radius -0.5, 0)
|
||||||
])
|
size = r"\large"
|
||||||
how_many = tex_mobject(r"""
|
scale_factor = 0.4
|
||||||
\text{How many}\\
|
text = tex_mobject(r"\text{How Many Intersection Points?}", size = size)
|
||||||
\text{intersection points?}
|
n = len(radians)
|
||||||
""", size = r"\large")
|
formula, answer = tex_mobjects([
|
||||||
text_center = (sc.radius + 1, sc.radius -1, 0)
|
r"{%d \choose 4} = \frac{%d(%d - 1)(%d - 2)(%d-3)}{1\cdot 2\cdot 3 \cdot 4}="%(n, n, n, n, n),
|
||||||
how_many.scale(0.4).shift(text_center)
|
str(choose(n, 4))
|
||||||
new_points = [
|
|
||||||
(text_center[0], y, 0)
|
|
||||||
for y in np.arange(
|
|
||||||
-(sc.radius - 1),
|
|
||||||
sc.radius - 1,
|
|
||||||
(2*sc.radius - 2)/choose(len(sc.points), 4)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
new_dots = CompoundMobject(*[
|
|
||||||
Dot(point) for point in new_points
|
|
||||||
])
|
])
|
||||||
|
text.scale(scale_factor).shift(text_center)
|
||||||
|
# new_points = [
|
||||||
|
# (text_center[0], y, 0)
|
||||||
|
# for y in np.arange(
|
||||||
|
# -(sc.radius - 1),
|
||||||
|
# sc.radius - 1,
|
||||||
|
# (2*sc.radius - 2)/choose(len(sc.points), 4)
|
||||||
|
# )
|
||||||
|
# ]
|
||||||
|
# new_dots = CompoundMobject(*[
|
||||||
|
# Dot(point) for point in new_points
|
||||||
|
# ])
|
||||||
|
|
||||||
sc.add(how_many)
|
sc.add(text)
|
||||||
sc.animate(ShowCreation(intersection_dots))
|
sc.count(intersection_dots, "show_creation", num_offset = (0, 0, 0))
|
||||||
sc.add(intersection_dots)
|
sc.dither()
|
||||||
sc.animate(Transform(intersection_dots, new_dots))
|
# sc.animate(Transform(intersection_dots, new_dots))
|
||||||
sc.add(tex_mobject(str(len(new_points))).center())
|
anims = []
|
||||||
|
for mob in sc.mobjects:
|
||||||
|
if mob == sc.number: #put in during animate_count
|
||||||
|
anims.append(Transform(mob, answer))
|
||||||
|
else:
|
||||||
|
anims.append(FadeOut(mob))
|
||||||
|
anims.append(FadeIn(formula)) #Put here to so they are foreground
|
||||||
|
sc.animate(*anims, run_time = 1)
|
||||||
return sc
|
return sc
|
||||||
|
|
||||||
def non_general_position():
|
def non_general_position():
|
||||||
|
@ -127,11 +153,52 @@ def non_general_position():
|
||||||
])
|
])
|
||||||
return sc1
|
return sc1
|
||||||
|
|
||||||
|
def line_corresponds_with_pair(radians, r1, r2):
|
||||||
|
sc = CircleScene(radians)
|
||||||
|
#Remove from sc.lines list, so they won't be faded out
|
||||||
|
assert r1 in radians and r2 in radians
|
||||||
|
line_index = list(it.combinations(radians, 2)).index((r1, r2))
|
||||||
|
radians = list(radians)
|
||||||
|
dot0_index, dot1_index = radians.index(r1), radians.index(r2)
|
||||||
|
line, dot0, dot1 = sc.lines[line_index], sc.dots[dot0_index], sc.dots[dot1_index]
|
||||||
|
sc.lines.remove(line)
|
||||||
|
sc.dots.remove(dot0)
|
||||||
|
sc.dots.remove(dot1)
|
||||||
|
sc.dither()
|
||||||
|
sc.animate(*[FadeOut(mob) for mob in sc.lines + sc.dots])
|
||||||
|
sc.add(sc.circle)
|
||||||
|
sc.animate(*[
|
||||||
|
ScaleInPlace(mob, 3, alpha_func = there_and_back)
|
||||||
|
for mob in (dot0, dot1)
|
||||||
|
])
|
||||||
|
sc.animate(Transform(line, dot0))
|
||||||
|
return sc
|
||||||
|
|
||||||
|
def illustrate_n_choose_2(n):
|
||||||
|
#TODO, maybe make this snazzy
|
||||||
|
sc = Scene()
|
||||||
|
nrange = range(1, n+1)
|
||||||
|
nrange_im = tex_mobject(str(nrange))
|
||||||
|
pairs_str = str(list(it.combinations(nrange, 2)))
|
||||||
|
exp = tex_mobject(r"{{%d \choose 2} = %d \text{ total pairs}}"%(n, choose(n, 2)))
|
||||||
|
pairs_im = tex_mobject(r"\underbrace{%s}"%pairs_str, size=r"\tiny")
|
||||||
|
nrange_im.shift((0, 2, 0))
|
||||||
|
pairs_im.scale(0.7)
|
||||||
|
exp.shift((0, -2, 0))
|
||||||
|
sc.add(nrange_im)
|
||||||
|
sc.dither()
|
||||||
|
sc.animate(FadeIn(pairs_im), FadeIn(exp))
|
||||||
|
sc.add(pairs_im)
|
||||||
|
return sc
|
||||||
|
|
||||||
|
|
||||||
##################################################
|
##################################################
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
radians = np.arange(0, 6, 6.0/7)
|
radians = np.arange(0, 6, 6.0/7)
|
||||||
count_lines(*radians).write_to_movie("moser/CountLines")
|
# count_lines(*radians).write_to_movie("moser/CountLines")
|
||||||
count_intersection_points(*radians).write_to_movie("moser/CountIntersectionPoints")
|
count_intersection_points(*radians).write_to_movie("moser/CountIntersectionPoints")
|
||||||
non_general_position().write_to_movie("moser/NonGeneralPosition")
|
# non_general_position().write_to_movie("moser/NonGeneralPosition")
|
||||||
|
# line_corresponds_with_pair(radians, radians[3], radians[4]).write_to_movie("moser/LineCorrespondsWithPair34")
|
||||||
|
# line_corresponds_with_pair(radians, radians[2], radians[5]).write_to_movie("moser/LineCorrespondsWithPair25")
|
||||||
|
# illustrate_n_choose_2(6).write_to_movie("moser/IllustrateNChoose2with6")
|
||||||
|
|
|
@ -2,6 +2,9 @@ import numpy as np
|
||||||
import operator as op
|
import operator as op
|
||||||
import itertools as it
|
import itertools as it
|
||||||
|
|
||||||
|
from constants import *
|
||||||
|
from image_mobject import *
|
||||||
|
|
||||||
def choose(n, r):
|
def choose(n, r):
|
||||||
if n < r: return 0
|
if n < r: return 0
|
||||||
if r == 0: return 1
|
if r == 0: return 1
|
||||||
|
@ -32,3 +35,6 @@ def intersection(line1, line2):
|
||||||
result = np.dot(transform, [[x_intercept], [0]])
|
result = np.dot(transform, [[x_intercept], [0]])
|
||||||
result = result.reshape((2,)) + p0
|
result = result.reshape((2,)) + p0
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
32
scene.py
32
scene.py
|
@ -12,6 +12,7 @@ import inspect
|
||||||
|
|
||||||
from helpers import *
|
from helpers import *
|
||||||
from mobject import *
|
from mobject import *
|
||||||
|
from image_mobject import *
|
||||||
from animation import *
|
from animation import *
|
||||||
import displayer as disp
|
import displayer as disp
|
||||||
|
|
||||||
|
@ -98,6 +99,37 @@ class Scene(object):
|
||||||
self.add(*moving_mobjects)
|
self.add(*moving_mobjects)
|
||||||
progress_bar.finish()
|
progress_bar.finish()
|
||||||
|
|
||||||
|
def count(self, mobjects, mode = "highlight",
|
||||||
|
color = "red",
|
||||||
|
num_offset = (SPACE_WIDTH - 1, SPACE_HEIGHT - 1, 0),
|
||||||
|
run_time = 5.0):
|
||||||
|
"""
|
||||||
|
Note: Leaves scene with a "number" attribute
|
||||||
|
for the final number mobject
|
||||||
|
"""
|
||||||
|
if len(mobjects) > 50: #TODO
|
||||||
|
raise Exception("I don't know if you should be counting \
|
||||||
|
too many mobjects...")
|
||||||
|
if mode not in ["highlight", "show_creation"]:
|
||||||
|
raise Exception("Invalid mode")
|
||||||
|
frame_time = run_time / len(mobjects)
|
||||||
|
if mode == "highlight":
|
||||||
|
self.add(*mobjects)
|
||||||
|
for mob, num in zip(mobjects, it.count(1)):
|
||||||
|
num_mob = tex_mobject(str(num))
|
||||||
|
num_mob.center().shift(num_offset)
|
||||||
|
self.add(num_mob)
|
||||||
|
if mode == "highlight":
|
||||||
|
original_color = mob.color
|
||||||
|
mob.highlight(color)
|
||||||
|
self.dither(frame_time)
|
||||||
|
mob.highlight(original_color)
|
||||||
|
if mode == "show_creation":
|
||||||
|
self.animate(ShowCreation(mob, run_time = frame_time))
|
||||||
|
self.remove(num_mob)
|
||||||
|
self.add(num_mob)
|
||||||
|
self.number = num_mob
|
||||||
|
|
||||||
def get_frame(self):
|
def get_frame(self):
|
||||||
frame = self.background
|
frame = self.background
|
||||||
for mob in self.mobjects:
|
for mob in self.mobjects:
|
||||||
|
|
Loading…
Add table
Reference in a new issue