2015-04-14 17:55:25 -07:00
|
|
|
#!/usr/bin/env python
|
|
|
|
|
|
|
|
import numpy as np
|
|
|
|
import itertools as it
|
|
|
|
import operator as op
|
|
|
|
from copy import deepcopy
|
|
|
|
|
|
|
|
|
|
|
|
from animation import *
|
|
|
|
from mobject import *
|
|
|
|
from image_mobject import *
|
|
|
|
from constants import *
|
|
|
|
from region import *
|
|
|
|
from scene import Scene
|
|
|
|
|
|
|
|
from moser_helpers import *
|
|
|
|
|
|
|
|
RADIUS = SPACE_HEIGHT - 0.1
|
|
|
|
CIRCLE_DENSITY = DEFAULT_POINT_DENSITY_1D*RADIUS
|
|
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
|
|
|
##################################################
|
|
|
|
|
|
|
|
def count_lines(*radians):
|
2015-04-16 21:09:12 -07:00
|
|
|
#TODO, Count things explicitly?
|
2015-04-14 17:55:25 -07:00
|
|
|
sc = CircleScene(radians)
|
|
|
|
text_center = (sc.radius + 1, sc.radius -1, 0)
|
2015-04-16 21:09:12 -07:00
|
|
|
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)
|
2015-04-14 17:55:25 -07:00
|
|
|
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)
|
|
|
|
])
|
2015-04-16 21:09:12 -07:00
|
|
|
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)
|
2015-04-14 17:55:25 -07:00
|
|
|
return sc
|
|
|
|
|
|
|
|
|
|
|
|
def count_intersection_points(*radians):
|
|
|
|
radians = [r % (2*np.pi) for r in radians]
|
|
|
|
radians.sort()
|
|
|
|
sc = CircleScene(radians)
|
|
|
|
intersection_points = [
|
2015-04-16 21:09:12 -07:00
|
|
|
intersection((p[0], p[2]), (p[1], p[3]))
|
2015-04-14 17:55:25 -07:00
|
|
|
for p in it.combinations(sc.points, 4)
|
|
|
|
]
|
2015-04-16 21:09:12 -07:00
|
|
|
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))
|
2015-04-14 17:55:25 -07:00
|
|
|
])
|
2015-04-16 21:09:12 -07:00
|
|
|
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
|
|
|
|
# ])
|
2015-04-14 17:55:25 -07:00
|
|
|
|
2015-04-16 21:09:12 -07:00
|
|
|
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)
|
2015-04-14 17:55:25 -07:00
|
|
|
return sc
|
|
|
|
|
|
|
|
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)
|
|
|
|
])
|
|
|
|
return sc1
|
|
|
|
|
2015-04-16 21:09:12 -07:00
|
|
|
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
|
|
|
|
|
2015-04-14 17:55:25 -07:00
|
|
|
|
|
|
|
##################################################
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
radians = np.arange(0, 6, 6.0/7)
|
2015-04-16 21:09:12 -07:00
|
|
|
# count_lines(*radians).write_to_movie("moser/CountLines")
|
2015-04-14 17:55:25 -07:00
|
|
|
count_intersection_points(*radians).write_to_movie("moser/CountIntersectionPoints")
|
2015-04-16 21:09:12 -07:00
|
|
|
# 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")
|