mirror of
https://github.com/3b1b/manim.git
synced 2025-08-01 08:54:38 +08:00
More moser, count method of scene implemented
This commit is contained in:
16
animation.py
16
animation.py
@ -14,7 +14,7 @@ from constants import *
|
||||
from mobject import Mobject
|
||||
|
||||
class Animation(object):
|
||||
def __init__(self,
|
||||
def __init__(self,
|
||||
mobject,
|
||||
run_time = DEFAULT_ANIMATION_RUN_TIME,
|
||||
alpha_func = high_inflection_0_to_1,
|
||||
@ -217,6 +217,18 @@ class Transform(Animation):
|
||||
)[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):
|
||||
def __init__(self, method, mobject, *args, **kwargs):
|
||||
"""
|
||||
@ -232,7 +244,7 @@ class ApplyMethod(Transform):
|
||||
mobject,
|
||||
method(copy.deepcopy(mobject), *method_args),
|
||||
*args, **kwargs
|
||||
)
|
||||
)
|
||||
|
||||
class ApplyFunction(Transform):
|
||||
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).
|
||||
"""
|
||||
#TODO, Should self.color change?
|
||||
to_change = np.apply_along_axis(condition, 1, self.points)
|
||||
self.rgbs[to_change, :] *= 0
|
||||
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):
|
||||
#TODO, Count things explicitly?
|
||||
sc = CircleScene(radians)
|
||||
text = tex_mobject(r"\text{How Many Lines?}", size = r"\large")
|
||||
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]
|
||||
new_lines = [
|
||||
Line((x-1, y, 0), (x+1, y, 0))
|
||||
@ -55,6 +62,16 @@ def count_lines(*radians):
|
||||
Transform(line1, line2, run_time = 2)
|
||||
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
|
||||
|
||||
|
||||
@ -63,35 +80,44 @@ def count_intersection_points(*radians):
|
||||
radians.sort()
|
||||
sc = CircleScene(radians)
|
||||
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)
|
||||
]
|
||||
intersection_dots = CompoundMobject(*[
|
||||
Dot(point) for point in intersection_points
|
||||
])
|
||||
how_many = tex_mobject(r"""
|
||||
\text{How many}\\
|
||||
\text{intersection points?}
|
||||
""", size = r"\large")
|
||||
text_center = (sc.radius + 1, sc.radius -1, 0)
|
||||
how_many.scale(0.4).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
|
||||
intersection_dots = [Dot(point) for point in intersection_points]
|
||||
text_center = (sc.radius + 1, sc.radius -0.5, 0)
|
||||
size = r"\large"
|
||||
scale_factor = 0.4
|
||||
text = tex_mobject(r"\text{How Many Intersection Points?}", size = size)
|
||||
n = len(radians)
|
||||
formula, answer = tex_mobjects([
|
||||
r"{%d \choose 4} = \frac{%d(%d - 1)(%d - 2)(%d-3)}{1\cdot 2\cdot 3 \cdot 4}="%(n, n, n, n, n),
|
||||
str(choose(n, 4))
|
||||
])
|
||||
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.animate(ShowCreation(intersection_dots))
|
||||
sc.add(intersection_dots)
|
||||
sc.animate(Transform(intersection_dots, new_dots))
|
||||
sc.add(tex_mobject(str(len(new_points))).center())
|
||||
sc.add(text)
|
||||
sc.count(intersection_dots, "show_creation", num_offset = (0, 0, 0))
|
||||
sc.dither()
|
||||
# sc.animate(Transform(intersection_dots, new_dots))
|
||||
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
|
||||
|
||||
def non_general_position():
|
||||
@ -127,11 +153,52 @@ def non_general_position():
|
||||
])
|
||||
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__':
|
||||
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")
|
||||
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 itertools as it
|
||||
|
||||
from constants import *
|
||||
from image_mobject import *
|
||||
|
||||
def choose(n, r):
|
||||
if n < r: return 0
|
||||
if r == 0: return 1
|
||||
@ -32,3 +35,6 @@ def intersection(line1, line2):
|
||||
result = np.dot(transform, [[x_intercept], [0]])
|
||||
result = result.reshape((2,)) + p0
|
||||
return result
|
||||
|
||||
|
||||
|
||||
|
32
scene.py
32
scene.py
@ -12,6 +12,7 @@ import inspect
|
||||
|
||||
from helpers import *
|
||||
from mobject import *
|
||||
from image_mobject import *
|
||||
from animation import *
|
||||
import displayer as disp
|
||||
|
||||
@ -98,6 +99,37 @@ class Scene(object):
|
||||
self.add(*moving_mobjects)
|
||||
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):
|
||||
frame = self.background
|
||||
for mob in self.mobjects:
|
||||
|
Reference in New Issue
Block a user