mirror of
https://github.com/3b1b/manim.git
synced 2025-07-30 13:34:19 +08:00
MoserSolutionInPascal
This commit is contained in:
BIN
Images/logo.png
Normal file
BIN
Images/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 71 KiB |
@ -32,7 +32,7 @@ DEFAULT_DITHER_TIME = 1.0
|
||||
DEFAULT_NUM_STARS = 1000
|
||||
|
||||
SPACE_HEIGHT = 4.0
|
||||
SPACE_WIDTH = DEFAULT_WIDTH * DEFAULT_HEIGHT / DEFAULT_WIDTH
|
||||
SPACE_WIDTH = SPACE_HEIGHT * DEFAULT_WIDTH / DEFAULT_HEIGHT
|
||||
|
||||
THIS_DIR = os.path.dirname(os.path.realpath(__file__))
|
||||
IMAGE_DIR = os.path.join(THIS_DIR, "images")
|
||||
|
@ -96,16 +96,17 @@ def tex_mobject(expression, size = r"\HUGE"):
|
||||
return tex_mobjects(expression, size)
|
||||
|
||||
def tex_mobjects(expression, size = r"\HUGE"):
|
||||
scale_value = 2
|
||||
images = tex_to_image(expression, size)
|
||||
if isinstance(images, list):
|
||||
#TODO, is checking listiness really the best here?
|
||||
result = [ImageMobject(im).scale(2) for im in images]
|
||||
result = [ImageMobject(im).scale(scale_value) for im in images]
|
||||
center = CompoundMobject(*result).get_center()
|
||||
for mob in result:
|
||||
mob.shift(-center)
|
||||
return result
|
||||
else:
|
||||
return ImageMobject(images).center().scale(2)
|
||||
return ImageMobject(images).center().scale(scale_value)
|
||||
|
||||
|
||||
|
||||
|
145
moser/main.py
145
moser/main.py
@ -629,6 +629,66 @@ class PascalsTriangleWithNChooseK(PascalsTriangleScene):
|
||||
self.remove(*self.mobjects)
|
||||
self.add(*[mob_dicts[1-i][n][k] for n, k in self.coords])
|
||||
|
||||
class PascalsTriangleNChooseKExample(PascalsTriangleScene):
|
||||
args_list = [
|
||||
(N_PASCAL_ROWS, 5, 3),
|
||||
]
|
||||
@staticmethod
|
||||
def args_to_string(nrows, n, k):
|
||||
return "%d_n=%d_k=%d"%(nrows, n, k)
|
||||
|
||||
def __init__(self, nrows, n, k, *args, **kwargs):
|
||||
PascalsTriangleScene.__init__(self, nrows, *args, **kwargs)
|
||||
dither_time = 0.5
|
||||
triangle_terms = [self.coords_to_mobs[a][b] for a, b in self.coords]
|
||||
formula_terms = left, n_mob, k_mob, right = tex_mobject([
|
||||
r"\left(", str(n), r"\atop %d"%k, r"\right)"
|
||||
])
|
||||
formula_center = (SPACE_WIDTH - 1, SPACE_HEIGHT - 1, 0)
|
||||
self.remove(*triangle_terms)
|
||||
self.add(*formula_terms)
|
||||
self.dither()
|
||||
self.animate(*
|
||||
[
|
||||
ShowCreation(mob) for mob in triangle_terms
|
||||
]+[
|
||||
ApplyMethod((Mobject.shift, formula_center), mob)
|
||||
for mob in formula_terms
|
||||
],
|
||||
run_time = 1.0
|
||||
)
|
||||
self.remove(n_mob, k_mob)
|
||||
for a in range(n+1):
|
||||
row = [self.coords_to_mobs[a][b] for b in range(a+1)]
|
||||
a_mob = tex_mobject(str(a))
|
||||
a_mob.shift(n_mob.get_center())
|
||||
a_mob.highlight("green")
|
||||
self.add(a_mob)
|
||||
for mob in row:
|
||||
mob.highlight("green")
|
||||
self.dither(dither_time)
|
||||
if a < n:
|
||||
for mob in row:
|
||||
mob.highlight("white")
|
||||
self.remove(a_mob)
|
||||
self.dither()
|
||||
for b in range(k+1):
|
||||
b_mob = tex_mobject(str(b))
|
||||
b_mob.shift(k_mob.get_center())
|
||||
b_mob.highlight("yellow")
|
||||
self.add(b_mob)
|
||||
self.coords_to_mobs[n][b].highlight("yellow")
|
||||
self.dither(dither_time)
|
||||
if b < k:
|
||||
self.coords_to_mobs[n][b].highlight("green")
|
||||
self.remove(b_mob)
|
||||
self.animate(*[
|
||||
ApplyMethod((Mobject.fade, 0.2), mob)
|
||||
for mob in triangle_terms
|
||||
if mob != self.coords_to_mobs[n][k]
|
||||
])
|
||||
self.dither()
|
||||
|
||||
class PascalsTriangleSumRows(PascalsTriangleScene):
|
||||
def __init__(self, *args, **kwargs):
|
||||
PascalsTriangleScene.__init__(self, *args, **kwargs)
|
||||
@ -690,6 +750,91 @@ class PascalsTriangleSumRows(PascalsTriangleScene):
|
||||
self.add(powers_of_two_symbols[n])
|
||||
|
||||
|
||||
class MoserSolutionInPascal(PascalsTriangleScene):
|
||||
args_list = [
|
||||
(N_PASCAL_ROWS, n)
|
||||
for n in range(3, 8)
|
||||
] + [
|
||||
(BIG_N_PASCAL_ROWS, 10)
|
||||
]
|
||||
@staticmethod
|
||||
def args_to_string(nrows, n):
|
||||
return "%d_n=%d"%(nrows,n)
|
||||
|
||||
def __init__(self, nrows, n, *args, **kwargs):
|
||||
PascalsTriangleScene.__init__(self, nrows, *args, **kwargs)
|
||||
term_color = "green"
|
||||
self.generate_n_choose_k_mobs()
|
||||
self.remove(*[self.coords_to_mobs[n0][k0] for n0, k0 in self.coords])
|
||||
terms = one, plus0, n_choose_2, plus1, n_choose_4 = tex_mobjects([
|
||||
"1", "+", r"{%d \choose 2}"%n, "+", r"{%d \choose 4}"%n
|
||||
])
|
||||
target_terms = []
|
||||
for k in range(len(terms)):
|
||||
if k%2 == 0 and k <= n:
|
||||
new_term = deepcopy(self.coords_to_n_choose_k[n][k])
|
||||
new_term.highlight(term_color)
|
||||
else:
|
||||
new_term = Point(
|
||||
self.coords_to_center(n, k)
|
||||
)
|
||||
target_terms.append(new_term)
|
||||
self.add(*terms)
|
||||
self.dither()
|
||||
self.animate(*
|
||||
[
|
||||
FadeIn(self.coords_to_n_choose_k[n0][k0])
|
||||
for n0, k0 in self.coords
|
||||
if (n0, k0) not in [(n, 0), (n, 2), (n, 4)]
|
||||
]+[
|
||||
Transform(term, target_term)
|
||||
for term, target_term in zip(terms, target_terms)
|
||||
]
|
||||
)
|
||||
self.dither()
|
||||
term_range = range(0, min(4, n)+1, 2)
|
||||
target_terms = dict([
|
||||
(k, deepcopy(self.coords_to_mobs[n][k]).highlight(term_color))
|
||||
for k in term_range
|
||||
])
|
||||
self.animate(*
|
||||
[
|
||||
SemiCircleTransform(
|
||||
self.coords_to_n_choose_k[n0][k0],
|
||||
self.coords_to_mobs[n0][k0]
|
||||
)
|
||||
for n0, k0 in self.coords
|
||||
if (n0, k0) not in [(n, k) for k in term_range]
|
||||
]+[
|
||||
SemiCircleTransform(terms[k], target_terms[k])
|
||||
for k in term_range
|
||||
]
|
||||
)
|
||||
self.dither()
|
||||
for k in term_range:
|
||||
if k == 0:
|
||||
above_terms = [self.coords_to_n_choose_k[n-1][k]]
|
||||
elif k == n:
|
||||
above_terms = [self.coords_to_n_choose_k[n-1][k-1]]
|
||||
else:
|
||||
above_terms = [
|
||||
self.coords_to_n_choose_k[n-1][k-1],
|
||||
self.coords_to_n_choose_k[n-1][k],
|
||||
]
|
||||
self.add(self.coords_to_mobs[n][k])
|
||||
self.animate(Transform(
|
||||
terms[k],
|
||||
CompoundMobject(*above_terms).highlight(term_color)
|
||||
))
|
||||
self.remove(*above_terms)
|
||||
self.dither()
|
||||
terms_sum = tex_mobject(str(moser_function(n)))
|
||||
terms_sum.shift((SPACE_WIDTH-1, terms[0].get_center()[1], 0))
|
||||
terms_sum.highlight(term_color)
|
||||
self.animate(Transform(CompoundMobject(*terms), terms_sum))
|
||||
|
||||
|
||||
|
||||
##################################################
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
518
moser/main.py~
Normal file
518
moser/main.py~
Normal file
@ -0,0 +1,518 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import numpy as np
|
||||
import itertools as it
|
||||
import operator as op
|
||||
from copy import deepcopy
|
||||
from random import random
|
||||
|
||||
|
||||
from animation import *
|
||||
from mobject import *
|
||||
from image_mobject import *
|
||||
from constants import *
|
||||
from region import *
|
||||
from scene import Scene
|
||||
|
||||
from moser_helpers import *
|
||||
from graphs import *
|
||||
|
||||
RADIUS = SPACE_HEIGHT - 0.1
|
||||
CIRCLE_DENSITY = DEFAULT_POINT_DENSITY_1D*RADIUS
|
||||
|
||||
movie_prefix = "moser/"
|
||||
|
||||
############################################
|
||||
|
||||
class CircleScene(Scene):
|
||||
def __init__(self, radians, *args, **kwargs):
|
||||
Scene.__init__(self, *args, **kwargs)
|
||||
self.radius = RADIUS
|
||||
self.circle = Circle(density = CIRCLE_DENSITY).scale(self.radius)
|
||||
self.points = [
|
||||
(self.radius * np.cos(angle), self.radius * np.sin(angle), 0)
|
||||
for angle in radians
|
||||
]
|
||||
self.dots = [Dot(point) for point in self.points]
|
||||
self.lines = [Line(p1, p2) for p1, p2 in it.combinations(self.points, 2)]
|
||||
self.add(self.circle, *self.dots + self.lines)
|
||||
|
||||
class GraphScene(Scene):
|
||||
#Note, the placement of vertices in this is pretty hard coded, be
|
||||
#warned if you want to change it.
|
||||
def __init__(self, graph, *args, **kwargs):
|
||||
Scene.__init__(self, *args, **kwargs)
|
||||
#See CUBE_GRAPH above for format of graph
|
||||
self.graph = graph
|
||||
self.points = map(np.array, graph["vertices"])
|
||||
self.vertices = self.dots = [Dot(p) for p in self.points]
|
||||
self.edges = [
|
||||
Line(self.points[i], self.points[j])
|
||||
for i, j in graph["edges"]
|
||||
]
|
||||
self.add(*self.dots + self.edges)
|
||||
|
||||
def generate_regions(self):
|
||||
regions = [
|
||||
region_from_line_boundary(*[
|
||||
[
|
||||
self.points[rc[i]],
|
||||
self.points[rc[(i+1)%len(rc)]]
|
||||
]
|
||||
for i in range(len(rc))
|
||||
])
|
||||
for rc in self.graph["region_cycles"]
|
||||
]
|
||||
regions[-1].complement()#Outer region painted outwardly...
|
||||
self.regions = regions
|
||||
|
||||
##################################################
|
||||
|
||||
def count_lines(*radians):
|
||||
#TODO, Count things explicitly?
|
||||
sc = CircleScene(radians)
|
||||
text_center = (sc.radius + 1, sc.radius -1, 0)
|
||||
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))
|
||||
for y in np.arange(
|
||||
-(sc.radius - 1),
|
||||
sc.radius - 1,
|
||||
(2*sc.radius - 2)/len(sc.lines)
|
||||
)
|
||||
]
|
||||
sc.add(text)
|
||||
sc.dither()
|
||||
sc.animate(*[
|
||||
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)
|
||||
sc.write_to_movie(movie_prefix + "CountLines%dPoints"%len(radians))
|
||||
|
||||
|
||||
def count_intersection_points(*radians):
|
||||
radians = [r % (2*np.pi) for r in radians]
|
||||
radians.sort()
|
||||
sc = CircleScene(radians)
|
||||
intersection_points = [
|
||||
intersection((p[0], p[2]), (p[1], p[3]))
|
||||
for p in it.combinations(sc.points, 4)
|
||||
]
|
||||
intersection_dots = [Dot(point) for point in intersection_points]
|
||||
text_center = (sc.radius + 0.5, 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(text)
|
||||
sc.count(intersection_dots, "show", 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(Animation(formula))
|
||||
sc.animate(*anims, run_time = 1)
|
||||
|
||||
name = "CountIntersectionPoints%dPoints"%len(radians)
|
||||
sc.write_to_movie(movie_prefix + name)
|
||||
|
||||
def non_general_position():
|
||||
radians = np.arange(1, 7)
|
||||
new_radians = (np.pi/3)*radians
|
||||
sc1 = CircleScene(radians)
|
||||
sc2 = CircleScene(new_radians)
|
||||
center_region = reduce(
|
||||
Region.intersect,
|
||||
[
|
||||
HalfPlane((sc1.points[x], sc1.points[(x+3)%6]))
|
||||
for x in [0, 4, 2]#Ya know, trust it
|
||||
]
|
||||
)
|
||||
center_region
|
||||
text = tex_mobject(r"\text{This region disappears}", size = r"\large")
|
||||
text.center().scale(0.5).shift((-sc1.radius, sc1.radius-0.3, 0))
|
||||
arrow = Arrow(
|
||||
point = (-0.35, -0.1, 0),
|
||||
direction = (1, -1, 0),
|
||||
length = sc1.radius + 1,
|
||||
color = "white",
|
||||
)
|
||||
|
||||
sc1.highlight_region(center_region, "green")
|
||||
sc1.add(text, arrow)
|
||||
sc1.dither(2)
|
||||
sc1.remove(text, arrow)
|
||||
sc1.reset_background()
|
||||
sc1.animate(*[
|
||||
Transform(mob1, mob2, run_time = DEFAULT_ANIMATION_RUN_TIME)
|
||||
for mob1, mob2 in zip(sc1.mobjects, sc2.mobjects)
|
||||
])
|
||||
sc1.write_to_movie(movie_prefix + "NonGeneralPosition")
|
||||
|
||||
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, alpha_func = not_quite_there)
|
||||
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))
|
||||
name = "LineCorrspondsWithPair%d%d"%(dot0_index, dot1_index)
|
||||
sc.write_to_movie(movie_prefix + name)
|
||||
|
||||
def illustrate_n_choose_k(n, k):
|
||||
sc = Scene()
|
||||
nrange = range(1, n+1)
|
||||
tuples = list(it.combinations(nrange, k))
|
||||
nrange_mobs = tex_mobjects([str(n) + r'\;' for n in nrange])
|
||||
tuple_mobs = tex_mobjects(
|
||||
[
|
||||
(r'\\&' if c%(20//k) == 0 else r'\;\;') + str(p)
|
||||
for p, c in zip(tuples, it.count())
|
||||
],
|
||||
size = r"\small"
|
||||
)
|
||||
tuple_terms = {
|
||||
2 : "pairs",
|
||||
3 : "triplets",
|
||||
4 : "quadruplets",
|
||||
}
|
||||
tuple_term = tuple_terms[k] if k in tuple_terms else "tuples"
|
||||
form1, count, form2 = tex_mobject([
|
||||
r"{%d \choose %d} = "%(n, k),
|
||||
"%d"%choose(n, k),
|
||||
r" \text{ total %s}"%tuple_term
|
||||
])
|
||||
for mob in nrange_mobs:
|
||||
mob.shift((0, 2, 0))
|
||||
for mob in form1, count, form2:
|
||||
mob.shift((0, -SPACE_HEIGHT + 1, 0))
|
||||
count_center = count.get_center()
|
||||
for mob in tuple_mobs:
|
||||
mob.scale(0.6)
|
||||
|
||||
sc.add(*nrange_mobs)
|
||||
sc.dither()
|
||||
run_time = 6.0
|
||||
frame_time = run_time / len(tuples)
|
||||
for tup, count in zip(tuples, it.count()):
|
||||
count_mob = tex_mobject(str(count+1))
|
||||
count_mob.center().shift(count_center)
|
||||
sc.add(count_mob)
|
||||
tuple_copy = CompoundMobject(*[nrange_mobs[index-1] for index in tup])
|
||||
tuple_copy.highlight()
|
||||
sc.add(tuple_copy)
|
||||
sc.add(tuple_mobs[count])
|
||||
sc.dither(frame_time)
|
||||
sc.remove(count_mob)
|
||||
sc.remove(tuple_copy)
|
||||
sc.add(count_mob)
|
||||
sc.animate(FadeIn(CompoundMobject(form1, form2)))
|
||||
sc.write_to_movie(movie_prefix + "Illustrate%dChoose%d"%(n, k))
|
||||
|
||||
def intersection_point_correspondances(radians, indices):
|
||||
assert(len(indices) == 4)
|
||||
indices.sort()
|
||||
sc = CircleScene(radians)
|
||||
intersection_point = intersection(
|
||||
(sc.points[indices[0]], sc.points[indices[2]]),
|
||||
(sc.points[indices[1]], sc.points[indices[3]])
|
||||
)
|
||||
intersection_point = tuple(list(intersection_point) + [0])
|
||||
intersection_dot = Dot(intersection_point)
|
||||
intersection_dot_arrow = Arrow(intersection_point).nudge()
|
||||
sc.add(intersection_dot)
|
||||
pairs = list(it.combinations(range(len(radians)), 2))
|
||||
lines_to_save = [
|
||||
sc.lines[pairs.index((indices[p0], indices[p1]))]
|
||||
for p0, p1 in [(0, 2), (1, 3)]
|
||||
]
|
||||
dots_to_save = [
|
||||
sc.dots[p]
|
||||
for p in indices
|
||||
]
|
||||
line_statement = tex_mobject(r"\text{Pair of Lines}")
|
||||
dots_statement = tex_mobject(r"&\text{Quadruplet of} \\ &\text{outer dots}")
|
||||
for mob in line_statement, dots_statement:
|
||||
mob.center()
|
||||
mob.scale(0.7)
|
||||
mob.shift((SPACE_WIDTH-2, SPACE_HEIGHT - 1, 0))
|
||||
fade_outs = []
|
||||
line_highlights = []
|
||||
dot_highlights = []
|
||||
dot_pointers = []
|
||||
for mob in sc.mobjects:
|
||||
if mob in lines_to_save:
|
||||
line_highlights.append(Highlight(mob))
|
||||
elif mob in dots_to_save:
|
||||
dot_highlights.append(Highlight(mob))
|
||||
dot_pointers.append(Arrow(mob.get_center()).nudge())
|
||||
elif mob != intersection_dot:
|
||||
fade_outs.append(FadeOut(mob, alpha_func = not_quite_there))
|
||||
|
||||
sc.add(intersection_dot_arrow)
|
||||
sc.animate(Highlight(intersection_dot))
|
||||
sc.remove(intersection_dot_arrow)
|
||||
sc.animate(*fade_outs)
|
||||
sc.dither()
|
||||
sc.add(line_statement)
|
||||
sc.animate(*line_highlights)
|
||||
sc.remove(line_statement)
|
||||
sc.dither()
|
||||
sc.add(dots_statement, *dot_pointers)
|
||||
sc.animate(*dot_highlights)
|
||||
sc.remove(dots_statement, *dot_pointers)
|
||||
|
||||
name = "IntersectionPointCorrespondances"
|
||||
for ind in indices:
|
||||
name += str(ind)
|
||||
sc.write_to_movie(movie_prefix + name)
|
||||
|
||||
def lines_intersect_outside(radians, indices):
|
||||
assert(len(indices) == 4)
|
||||
indices.sort()
|
||||
sc = CircleScene(radians)
|
||||
intersection_point = intersection(
|
||||
(sc.points[indices[0]], sc.points[indices[1]]),
|
||||
(sc.points[indices[2]], sc.points[indices[3]])
|
||||
)
|
||||
intersection_point = tuple(list(intersection_point) + [0])
|
||||
intersection_dot = Dot(intersection_point)
|
||||
pairs = list(it.combinations(range(len(radians)), 2))
|
||||
lines_to_save = [
|
||||
sc.lines[pairs.index((indices[p0], indices[p1]))]
|
||||
for p0, p1 in [(0, 1), (2, 3)]
|
||||
]
|
||||
sc.animate(*[
|
||||
FadeOut(mob, alpha_func = not_quite_there)
|
||||
for mob in sc.mobjects if mob not in lines_to_save
|
||||
])
|
||||
sc.animate(*[
|
||||
Transform(
|
||||
Line(sc.points[indices[p0]], sc.points[indices[p1]]),
|
||||
Line(sc.points[indices[p0]], intersection_point))
|
||||
for p0, p1 in [(0, 1), (3, 2)]
|
||||
] + [ShowCreation(intersection_dot)])
|
||||
|
||||
name = "LinesIntersectOutside"
|
||||
for ind in indices:
|
||||
name += str(ind)
|
||||
sc.write_to_movie(movie_prefix + name)
|
||||
|
||||
def quadruplets_to_intersections(*radians):
|
||||
sc = CircleScene(radians)
|
||||
quadruplets = it.combinations(range(len(radians)), 4)
|
||||
frame_time = 1.0
|
||||
for quad in quadruplets:
|
||||
intersection_dot = Dot(intersection(
|
||||
(sc.points[quad[0]], sc.points[quad[2]]),
|
||||
(sc.points[quad[1]], sc.points[quad[3]])
|
||||
)).repeat(3)
|
||||
dot_quad = [deepcopy(sc.dots[i]) for i in quad]
|
||||
for dot in dot_quad:
|
||||
dot.scale_in_place(2)
|
||||
# arrows = [Arrow(d.get_center()) for d in dot_quad]
|
||||
dot_quad = CompoundMobject(*dot_quad)
|
||||
# arrows = CompoundMobject(*arrows)
|
||||
dot_quad.highlight()
|
||||
# sc.add(arrows)
|
||||
sc.add(dot_quad)
|
||||
sc.dither(frame_time / 3)
|
||||
sc.animate(Transform(
|
||||
dot_quad,
|
||||
intersection_dot,
|
||||
run_time = 3*frame_time/2
|
||||
))
|
||||
# sc.remove(arrows)
|
||||
|
||||
name = "QuadrupletsToIntersections" + str(len(radians))
|
||||
sc.write_to_movie(movie_prefix + name)
|
||||
|
||||
def defining_graph(graph):
|
||||
gs = GraphScene(graph)
|
||||
dots, lines = gs.vertices, gs.edges
|
||||
gs.remove(*dots + lines)
|
||||
all_dots = CompoundMobject(*dots)
|
||||
gs.animate(ShowCreation(all_dots))
|
||||
gs.remove(all_dots)
|
||||
gs.add(*dots)
|
||||
gs.dither()
|
||||
gs.animate(*[
|
||||
ShowCreation(line) for line in lines
|
||||
])
|
||||
|
||||
#Move to new graph
|
||||
new_graph = deepcopy(graph)
|
||||
new_graph["vertices"] = [
|
||||
(v[0] + 3*random(), v[1] + 3*random(), 0)
|
||||
for v in new_graph["vertices"]
|
||||
]
|
||||
ngs = GraphScene(new_graph)
|
||||
gs.animate(*[
|
||||
Transform(m[0], m[1])
|
||||
for m in zip(gs.mobjects, ngs.mobjects)
|
||||
], run_time = 7.0)
|
||||
|
||||
name = "DefiningGraph" + graph["name"]
|
||||
gs.write_to_movie(movie_prefix + name)
|
||||
|
||||
def doubled_edges(graph):
|
||||
gs = GraphScene(graph)
|
||||
lines_to_double = gs.edges[:9:3]
|
||||
crazy_lines = [
|
||||
(
|
||||
line,
|
||||
Line(line.end, line.start),
|
||||
CurvedLine(line.start, line.end) ,
|
||||
CurvedLine(line.end, line.start)
|
||||
)
|
||||
for line in lines_to_double
|
||||
]
|
||||
anims = []
|
||||
outward_curved_lines = []
|
||||
kwargs = {"run_time" : 3.0}
|
||||
for straight, backwards, inward, outward in crazy_lines:
|
||||
anims += [
|
||||
Transform(straight, inward, **kwargs),
|
||||
Transform(backwards, outward, **kwargs),
|
||||
]
|
||||
outward_curved_lines.append(outward)
|
||||
gs.animate(*anims)
|
||||
gs.dither()
|
||||
gs.remove(*outward_curved_lines)
|
||||
|
||||
name = "DoubledEdges" + graph["name"]
|
||||
gs.write_to_movie(movie_prefix + name)
|
||||
|
||||
|
||||
def eulers_formula(graph):
|
||||
gs = GraphScene(graph)
|
||||
terms = "V - E + F =2".split(" ")
|
||||
form = dict([
|
||||
(key, mob)
|
||||
for key, mob in zip(terms, tex_mobjects(terms))
|
||||
])
|
||||
for mob in form.values():
|
||||
mob.shift((0, SPACE_HEIGHT-1.5, 0))
|
||||
formula = CompoundMobject(*form.values())
|
||||
new_form = dict([
|
||||
(key, deepcopy(mob).shift((0, -0.7, 0)))
|
||||
for key, mob in zip(form.keys(), form.values())
|
||||
])
|
||||
gs.add(formula)
|
||||
colored_dots = [
|
||||
deepcopy(d).scale_in_place(1.5).highlight("red")
|
||||
for d in gs.dots
|
||||
]
|
||||
colored_edges = [
|
||||
deepcopy(e).highlight("red")
|
||||
for e in gs.edges
|
||||
]
|
||||
frame_time = 0.3
|
||||
|
||||
gs.generate_regions()
|
||||
parameters = [
|
||||
(colored_dots, "V", "mobject", "-", "show_creation"),
|
||||
(colored_edges, "E", "mobject", "+", "show_creation"),
|
||||
(gs.regions, "F", "region", "=2", "show_all")
|
||||
]
|
||||
for items, letter, item_type, symbol, mode in parameters:
|
||||
gs.count(
|
||||
items,
|
||||
item_type = item_type,
|
||||
mode = mode,
|
||||
num_offset = new_form[letter].get_center(),
|
||||
run_time = frame_time*len(items)
|
||||
)
|
||||
gs.dither()
|
||||
if item_type == "mobject":
|
||||
gs.remove(*items)
|
||||
gs.add(new_form[symbol])
|
||||
gs.reset_background()
|
||||
|
||||
name = "EulersFormula" + graph["name"]
|
||||
gs.write_to_movie(movie_prefix + name)
|
||||
|
||||
|
||||
##################################################
|
||||
|
||||
if __name__ == '__main__':
|
||||
radians = np.arange(0, 6, 6.0/7)
|
||||
# count_lines(*radians)
|
||||
# count_lines(*radians[:4])
|
||||
# count_intersection_points(*radians[:4])
|
||||
# count_intersection_points(*radians[:6])
|
||||
# count_intersection_points(*radians)
|
||||
# non_general_position()
|
||||
# line_corresponds_with_pair(radians, radians[3], radians[4])
|
||||
# line_corresponds_with_pair(radians, radians[2], radians[5])
|
||||
# illustrate_n_choose_k(7, 2)
|
||||
# illustrate_n_choose_k(6, 4)
|
||||
# intersection_point_correspondances(radians, range(0, 7, 2))
|
||||
# lines_intersect_outside(radians, [2, 4, 5, 6])
|
||||
quadruplets_to_intersections(*radians[:6])
|
||||
# defining_graph(SAMPLE_GRAPH)
|
||||
# doubled_edges(CUBE_GRAPH)
|
||||
# eulers_formula(CUBE_GRAPH)
|
||||
# eulers_formula(SAMPLE_GRAPH)
|
||||
# eulers_formula(OCTOHEDRON_GRAPH)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -156,46 +156,41 @@ class PascalsTriangleScene(Scene):
|
||||
|
||||
def __init__(self, nrows, *args, **kwargs):
|
||||
Scene.__init__(self, *args, **kwargs)
|
||||
diagram_height = 2*SPACE_HEIGHT - 1
|
||||
diagram_width = 1.5*SPACE_WIDTH
|
||||
cell_height = diagram_height / nrows
|
||||
cell_width = diagram_width / nrows
|
||||
portion_to_fill = 0.7
|
||||
bottom_left = np.array(
|
||||
(-cell_width * nrows / 2.0, -cell_height * nrows / 2.0, 0)
|
||||
self.nrows = nrows
|
||||
self.diagram_height = 2*SPACE_HEIGHT - 1
|
||||
self.diagram_width = 1.5*SPACE_WIDTH
|
||||
self.cell_height = self.diagram_height / nrows
|
||||
self.cell_width = self.diagram_width / nrows
|
||||
self.portion_to_fill = 0.7
|
||||
self.bottom_left = np.array(
|
||||
(-self.cell_width * nrows / 2.0, -self.cell_height * nrows / 2.0, 0)
|
||||
)
|
||||
num_to_num_mob = {}
|
||||
coords_to_mobs = {}
|
||||
coords = [(n, k) for n in range(nrows) for k in range(n+1)]
|
||||
for n, k in coords:
|
||||
self.coords_to_mobs = {}
|
||||
self.coords = [(n, k) for n in range(nrows) for k in range(n+1)]
|
||||
for n, k in self.coords:
|
||||
num = choose(n, k)
|
||||
center = bottom_left + (
|
||||
cell_width * (k+nrows/2.0 - n/2.0),
|
||||
cell_height * (nrows - n),
|
||||
0
|
||||
)
|
||||
center = self.coords_to_center(n, k)
|
||||
if num not in num_to_num_mob:
|
||||
num_to_num_mob[num] = tex_mobject(str(num))
|
||||
num_mob = deepcopy(num_to_num_mob[num])
|
||||
scale_factor = min(
|
||||
1,
|
||||
portion_to_fill * cell_height / num_mob.get_height(),
|
||||
portion_to_fill * cell_width / num_mob.get_width(),
|
||||
self.portion_to_fill * self.cell_height / num_mob.get_height(),
|
||||
self.portion_to_fill * self.cell_width / num_mob.get_width(),
|
||||
)
|
||||
num_mob.center().scale(scale_factor).shift(center)
|
||||
if n not in coords_to_mobs:
|
||||
coords_to_mobs[n] = {}
|
||||
coords_to_mobs[n][k] = num_mob
|
||||
self.add(*[coords_to_mobs[n][k] for n, k in coords])
|
||||
#Add attributes
|
||||
self.nrows = nrows
|
||||
self.coords = coords
|
||||
self.diagram_height = diagram_height
|
||||
self.diagram_width = diagram_width
|
||||
self.cell_height = cell_height
|
||||
self.cell_width = cell_width
|
||||
self.portion_to_fill= portion_to_fill
|
||||
self.coords_to_mobs = coords_to_mobs
|
||||
if n not in self.coords_to_mobs:
|
||||
self.coords_to_mobs[n] = {}
|
||||
self.coords_to_mobs[n][k] = num_mob
|
||||
self.add(*[self.coords_to_mobs[n][k] for n, k in self.coords])
|
||||
|
||||
def coords_to_center(self, n, k):
|
||||
return self.bottom_left + (
|
||||
self.cell_width * (k+self.nrows/2.0 - n/2.0),
|
||||
self.cell_height * (self.nrows - n),
|
||||
0
|
||||
)
|
||||
|
||||
def generate_n_choose_k_mobs(self):
|
||||
self.coords_to_n_choose_k = {}
|
||||
@ -212,6 +207,18 @@ class PascalsTriangleScene(Scene):
|
||||
self.coords_to_n_choose_k[n] = {}
|
||||
self.coords_to_n_choose_k[n][k] = nck_mob
|
||||
|
||||
def generate_sea_of_zeros(self):
|
||||
zero = tex_mobject("0")
|
||||
self.sea_of_zeros = []
|
||||
for n in range(self.nrows):
|
||||
for a in range((self.nrows - n)/2 + 1):
|
||||
for k in (n + a + 1, -a -1):
|
||||
self.coords.append((n, k))
|
||||
mob = deepcopy(zero)
|
||||
mob.shift(self.coords_to_center(n, k))
|
||||
self.coords_to_mobs[n][k] = mob
|
||||
self.add(mob)
|
||||
|
||||
|
||||
|
||||
##################################################
|
||||
|
@ -86,7 +86,7 @@ def command_line_create_scene(sys_argv, scene_classes, movie_prefix = ""):
|
||||
scene_classes
|
||||
)
|
||||
name = SceneClass.__name__ + SceneClass.args_to_string(*args)
|
||||
print "Writing %s..."%name
|
||||
print "Constructing %s..."%name
|
||||
scene = SceneClass(*args, display_config = display_config)
|
||||
scene.write_to_movie(movie_prefix + name)
|
||||
|
||||
|
Reference in New Issue
Block a user