Randolph and Mortimer

This commit is contained in:
Grant Sanderson
2015-06-13 19:00:23 -07:00
parent e47f240840
commit 344290068c
18 changed files with 414 additions and 279 deletions

View File

@ -112,27 +112,27 @@ class Animation(object):
#Fuck this is cool!
class TransformAnimations(Transform):
def __init__(self, start_anim, end_anim,
alpha_func = squish_alpha_func(high_inflection_0_to_1),
**kwargs):
self.start_anim, self.end_anim = start_anim, end_anim
Transform.__init__(
self,
start_anim.mobject,
end_anim.mobject,
run_time = max(start_anim.run_time, end_anim.run_time),
alpha_func = alpha_func,
**kwargs
)
#Rewire starting and ending mobjects
start_anim.mobject = self.starting_mobject
end_anim.mobject = self.ending_mobject
# class TransformAnimations(Transform):
# def __init__(self, start_anim, end_anim,
# alpha_func = squish_alpha_func(high_inflection_0_to_1),
# **kwargs):
# self.start_anim, self.end_anim = start_anim, end_anim
# Transform.__init__(
# self,
# start_anim.mobject,
# end_anim.mobject,
# run_time = max(start_anim.run_time, end_anim.run_time),
# alpha_func = alpha_func,
# **kwargs
# )
# #Rewire starting and ending mobjects
# start_anim.mobject = self.starting_mobject
# end_anim.mobject = self.ending_mobject
def update(self, alpha):
self.start_anim.update(alpha)
self.end_anim.update(alpha)
Transform.update(self, alpha)
# def update(self, alpha):
# self.start_anim.update(alpha)
# self.end_anim.update(alpha)
# Transform.update(self, alpha)

View File

@ -59,19 +59,21 @@ class Transform(Animation):
)
class SemiCircleTransform(Transform):
def __init__(self, mobject1, mobject2, counterclockwise = True,
*args, **kwargs):
Transform.__init__(self, mobject1, mobject2, *args, **kwargs)
self.axis = (0, 0, 1) if counterclockwise else (0, 0, -1)
def update_mobject(self, alpha):
sm, em = self.starting_mobject, self.ending_mobject
midpoints = (sm.points + em.points) / 2
angle = alpha * np.pi
rotation_matrix = np.matrix([
[np.cos(angle), np.sin(angle), 0],
[-np.sin(angle), np.cos(angle), 0],
[0, 0, 1],
])
self.mobject.points = np.dot(
sm.points - midpoints,
np.transpose(rotation_matrix)
) + midpoints
rot_matrix = rotation_matrix(angle, self.axis)[:2, :2]
self.mobject.points[:,:2] = np.dot(
(sm.points - midpoints)[:,:2],
np.transpose(rot_matrix)
) + midpoints[:,:2]
self.mobject.points[:,2] = (1-alpha)*sm.points[:,2] + alpha*em.points[:,2]
self.mobject.rgbs = (1-alpha)*sm.rgbs + alpha*em.rgbs
class FadeToColor(Transform):

View File

@ -55,3 +55,9 @@ TEMPLATE_TEXT_FILE = os.path.join(TEX_DIR, "text_template.tex")
LOGO_PATH = os.path.join(IMAGE_DIR, "logo.png")
DARK_BLUE = "#236B8E"
DARK_BROWN = "#8B4513"
LIGHT_BROWN = "#CD853F"

View File

@ -34,6 +34,8 @@ def paint_region(region, image_array = None, color = None):
def paint_mobject(mobject, image_array = None):
pixels = get_pixels(image_array)
if mobject.get_num_points() == 0:
return pixels
height = pixels.shape[0]
width = pixels.shape[1]
space_height = SPACE_HEIGHT
@ -48,9 +50,12 @@ def paint_mobject(mobject, image_array = None):
points[:,1] *= -1
#Map points to pixel space, then create pixel array first in terms
#of its flattened version
try:
points += np.array(
[space_width, space_height]*points.shape[0]
).reshape(points.shape)
except:
print points.shape, mobject.points.shape
points *= np.array(
[width / (2.0 * space_width), height / (2.0 * space_height)]*\
points.shape[0]

View File

@ -3,3 +3,4 @@ from image_mobject import *
from simple_mobjects import *
from three_dimensional_mobjects import *
from function_graphs import *
from creatures import *

87
mobject/creatures.py Normal file
View File

@ -0,0 +1,87 @@
import numpy as np
import itertools as it
import os
from image_mobject import *
from mobject import *
from simple_mobjects import *
class PiCreature(CompoundMobject):
DEFAULT_COLOR = "blue"
def __init__(self, color = DEFAULT_COLOR, **kwargs):
scale_val = 0.5
mouth_to_eyes_distance = 0.25
part_names = [
'arm',
'body',
'left_eye',
'right_eye',
'left_leg',
'right_leg',
'mouth',
]
white_part_names = ['left_eye', 'right_eye', 'mouth']
directory = os.path.join(IMAGE_DIR, "PiCreature")
self.parts = []
self.white_parts = []
for part_name in part_names:
path = os.path.join(directory, "pi_creature_"+part_name)
path += ".png"
mob = ImageMobject(path)
mob.scale(scale_val)
if part_name in white_part_names:
self.white_parts.append(mob)
else:
mob.highlight(color)
setattr(self, part_name, mob)
self.parts.append(mob)
self.mouth.center().shift(
self.left_eye.get_center()/2 +
self.right_eye.get_center()/2 -
(0, mouth_to_eyes_distance, 0)
)
self.reload_parts()
def reload_parts(self):
CompoundMobject.__init__(self, *self.parts)
return self
def highlight(self, color):
for part in set(self.parts).difference(self.white_parts):
part.highlight(color)
return self.reload_parts()
def give_frown(self):
center = self.mouth.get_center()
self.mouth.center()
self.mouth.apply_function(lambda (x, y, z) : (x, -y, z))
self.mouth.shift(center)
return self.reload_parts()
def give_straight_face(self):
center = self.mouth.get_center()
self.mouth.center()
new_mouth = tex_mobject("-").scale(0.5)
new_mouth.center().shift(self.mouth.get_center())
new_mouth.shift(center)
self.parts[self.parts.index(self.mouth)] = new_mouth
self.white_parts[self.white_parts.index(self.mouth)] = new_mouth
self.mouth = new_mouth
return self.reload_parts()
class Randolph(PiCreature):
pass #Nothing more than an alternative name
class Mortimer(PiCreature):
def __init__(self, *args, **kwargs):
PiCreature.__init__(self, *args, **kwargs)
self.highlight(DARK_BROWN)
self.give_straight_face()

View File

@ -88,10 +88,23 @@ class Mobject(object):
def shift(self, vector):
cycle = it.cycle(vector)
v = np.array([cycle.next() for x in range(self.points.size)]).reshape(self.points.shape)
v = np.array([
cycle.next()
for x in range(self.points.size)
]).reshape(self.points.shape)
self.points += v
return self
def wag(self, wag_direction = [0, 1, 0], wag_axis = [-1, 0, 0]):
alphas = np.dot(self.points, np.transpose(wag_axis))
alphas -= min(alphas)
alphas /= max(alphas)
self.points += np.dot(
alphas.reshape((len(alphas), 1)),
np.array(wag_direction).reshape((1, 3))
)
return self
def center(self):
self.shift(-self.get_center())
return self
@ -116,9 +129,6 @@ class Mobject(object):
self.add_points(points, rgbs)
return self
def get_num_points(self):
return self.points.shape[0]
def pose_at_angle(self):
self.rotate(np.pi / 7)
self.rotate(np.pi / 7, [1, 0, 0])
@ -155,6 +165,10 @@ class Mobject(object):
return self
### Getters ###
def get_num_points(self):
return self.points.shape[0]
def get_center(self):
return np.apply_along_axis(np.mean, 0, self.points)

View File

@ -83,7 +83,7 @@ class Line(Mobject1D):
def __init__(self, start, end, density = DEFAULT_POINT_DENSITY_1D, *args, **kwargs):
self.start = np.array(start)
self.end = np.array(end)
density *= np.linalg.norm(self.start - self.end)
density *= self.get_length()
Mobject1D.__init__(self, density = density, *args, **kwargs)
def generate_points(self):
@ -92,6 +92,16 @@ class Line(Mobject1D):
for t in np.arange(0, 1, self.epsilon)
])
def get_length(self):
return np.linalg.norm(self.start - self.end)
def get_slope(self):
rise, run = [
float(self.end[i] - self.start[i])
for i in [1, 0]
]
return rise/run
class CurvedLine(Line):
def generate_points(self):
equidistant_point = rotate_vector(

View File

View File

@ -1,82 +0,0 @@
#!/usr/bin/env python
import numpy as np
import itertools as it
import operator as op
from copy import deepcopy
from random import random, randint
import sys
import inspect
from animation import *
from mobject import *
from image_mobject import *
from constants import *
from region import *
from scene import Scene
from script_wrapper import command_line_create_scene
from moser_helpers import *
from graphs import *
if __name__ == "__main__":
prefix = "moser_images/"
# cs_outer = CircleScene(RADIANS[:6])
# cs_outer.highlight_region(
# Region(lambda x, y : x**2 + y**2 > RADIUS**2)
# )
# cs_graph = CircleScene(RADIANS)
# cs_graph.generate_intersection_dots()
# cs_graph.add(*cs_graph.intersection_dots)
# cs_graph.chop_lines_at_intersection_points()
# cs_graph.chop_circle_at_points()
# for line in cs_graph.lines:
# line.scale_in_place(0.5)
# for piece in cs_graph.smaller_circle_pieces:
# piece.highlight("yellow")
# cs_graph.remove(*cs_graph.circle_pieces)
# cs_graph.add(*cs_graph.smaller_circle_pieces)
savable_things = [
# (Mobject(), "Blackness")
# (tex_mobject(r"V-E+F=2"), "EulersFormula"),
# (PascalsTriangleScene(N_PASCAL_ROWS), "PascalsTriangle"),
# (tex_mobject(r"1, 2, 4, 8, 16, 31, \dots"), "FalsePattern"),
# (
# tex_mobject(r"""
# \underbrace{1, 2, 4, 16, 31, 57, 99, 163, 256, 386, \dots}_{
# \text{What is this pattern?}
# }
# """),
# "WhatIsThisPattern"
# ),
# (tex_mobject(r"n \choose k"), "NChooseK"),
# (GraphScene(SAMPLE_GRAPH), "SampleGraph"),
# (text_mobject("You don't even want me to draw this..."), "DontWantToDraw"),
# (tex_mobject(r"{100 \choose 2} = \frac{100 \cdot 99}{2} = 4950"), "100Choose2"),
# (text_mobject("What? You actually want me to draw it? Okay..."), "ReallyDontWant"),
# (text_mobject(r"There! You happy? \\ It's just one big blue blob."), "YouHappy"),
# (
# tex_mobject(
# r"{100 \choose 4} = \frac{(100)(99)(98)(97)}{(1)(2)(3)(4)} = 3,921,225"
# ),
# "100Choose4"
# ),
# (text_mobject("Euler's Characteristic Formula"), "EF_Words"),
# (cs_outer, "OuterRegion"),
# (text_mobject("Pause and see if you can remember on your own!"), "Recap")
# (CircleScene([2*np.pi*random() for x in range(100)]), "CircleScene100")
# (text_mobject(r"""
# \textbf{Eul$\cdot$er's} (\text{oil}\textschwa\text{rz}), \emph{adj}:
# \begin{enumerate}
# \item Beautiful
# \item Demonstrating an unexpected logical aesthetic, especially in the context of mathematics.
# \end{enumerate}
# """), "EulersDefinition"),
# (cs_graph, "SuitableGraph"),
]
for thing, name in savable_things:
thing.save_image(prefix + name)

View File

@ -1,128 +0,0 @@
import numpy as np
import itertools as it
from constants import *
from helpers import *
from image_mobject import *
from region import *
from scene import Scene
from graphs import *
RADIUS = SPACE_HEIGHT - 0.1
CIRCLE_DENSITY = DEFAULT_POINT_DENSITY_1D*RADIUS
MOVIE_PREFIX = "moser/"
RADIANS = np.arange(0, 6, 6.0/7)
MORE_RADIANS = np.append(RADIANS, RADIANS + 0.5)
N_PASCAL_ROWS = 7
BIG_N_PASCAL_ROWS = 11
############################################
class CircleScene(Scene):
args_list = [
(RADIANS[:x],)
for x in range(1, len(RADIANS)+1)
]
@staticmethod
def args_to_string(*args):
return str(len(args[0])) #Length of radians
def __init__(self, radians, radius = RADIUS, *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.n_equals = tex_mobject(
"n=%d"%len(radians),
).shift((-SPACE_WIDTH+1, SPACE_HEIGHT-1.5, 0))
self.add(self.circle, self.n_equals, *self.dots + self.lines)
def generate_intersection_dots(self):
"""
Generates and adds attributes intersection_points and
intersection_dots, but does not yet add them to the scene
"""
self.intersection_points = [
intersection((p[0], p[2]), (p[1], p[3]))
for p in it.combinations(self.points, 4)
]
self.intersection_dots = [
Dot(point) for point in self.intersection_points
]
def chop_lines_at_intersection_points(self):
if not hasattr(self, "intersection_dots"):
self.generate_intersection_dots()
self.remove(*self.lines)
self.lines = []
for point_pair in it.combinations(self.points, 2):
int_points = filter(
lambda p : is_on_line(p, *point_pair),
self.intersection_points
)
points = list(point_pair) + int_points
points = map(lambda p : (p[0], p[1], 0), points)
points.sort(cmp = lambda x,y: cmp(x[0], y[0]))
self.lines += [
Line(points[i], points[i+1])
for i in range(len(points)-1)
]
self.add(*self.lines)
def chop_circle_at_points(self):
self.remove(self.circle)
self.circle_pieces = []
self.smaller_circle_pieces = []
for i in range(len(self.points)):
pp = self.points[i], self.points[(i+1)%len(self.points)]
transform = np.array([
[pp[0][0], pp[1][0], 0],
[pp[0][1], pp[1][1], 0],
[0, 0, 1]
])
circle = deepcopy(self.circle)
smaller_circle = deepcopy(self.circle)
for c in circle, smaller_circle:
c.points = np.dot(
c.points,
np.transpose(np.linalg.inv(transform))
)
c.filter_out(
lambda p : p[0] < 0 or p[1] < 0
)
if c == smaller_circle:
c.filter_out(
lambda p : p[0] > 4*p[1] or p[1] > 4*p[0]
)
c.points = np.dot(
c.points,
np.transpose(transform)
)
self.circle_pieces.append(circle)
self.smaller_circle_pieces.append(smaller_circle)
self.add(*self.circle_pieces)
def generate_regions(self):
self.regions = plane_partition_from_points(*self.points)
interior = Region(lambda x, y : x**2 + y**2 < self.radius**2)
map(lambda r : r.intersect(interior), self.regions)
self.exterior = interior.complement()
##################################################
def int_list_to_string(int_list):
return "-".join(map(str, int_list))
def moser_function(n):
return choose(n, 4) + choose(n, 2) + 1

View File

@ -38,17 +38,20 @@ CUBE_GRAPH = {
SAMPLE_GRAPH = {
"name" : "SampleGraph",
# 4 2 3
# 4 2 3 8
# 0 1
#
# 5
# 7
# 5 6
"vertices" :[
( 0, 0, 0),
( 2, 0, 0),
( 1, 1, 0),
( 3, 1, 0),
(-1, 1, 0),
( 1, 2, 0),
( 3, 2, 0),
(-1, 2, 0),
(-2,-2, 0),
( 2,-2, 0),
( 4,-1, 0),
( 6, 2, 0),
],
"edges" : [
(0, 1),
@ -61,6 +64,11 @@ SAMPLE_GRAPH = {
(4, 5),
(0, 5),
(1, 5),
(5, 6),
(6, 7),
(7, 1),
(7, 8),
(8, 3),
],
"region_cycles" : [
(0, 1, 2),
@ -68,7 +76,9 @@ SAMPLE_GRAPH = {
(2, 4, 0),
(4, 5, 0),
(0, 5, 1),
(4, 5, 1, 3),
(1, 5, 6, 7),
(1, 7, 8, 3),
(4, 5, 6, 7, 8),
]
}

View File

@ -6,6 +6,7 @@ from graphs import *
from mobject import *
from animation import *
from region import *
from constants import *
from helpers import *
@ -20,14 +21,16 @@ class GraphScene(Scene):
return args[0]["name"]
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"])
Scene.__init__(self, *args, **kwargs)
def construct(self):
self.points = map(np.array, self.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"]
for i, j in self.graph["edges"]
]
self.add(*self.dots + self.edges)
@ -45,6 +48,50 @@ class GraphScene(Scene):
regions[-1].complement()#Outer region painted outwardly...
self.regions = regions
def generate_spanning_tree(self):
pass
def draw_vertices(self):
self.clear()
self.animate(ShowCreation(CompoundMobject(*self.vertices)))
def draw_edges(self):
self.animate(*[
ShowCreation(edge, run_time = 1.0)
for edge in self.edges
])
def replace_vertices_with(self, mobject):
mobject.center()
diameter = max(mobject.get_height(), mobject.get_width())
self.animate(*[
SemiCircleTransform(
vertex,
deepcopy(mobject).shift(vertex.get_center())
)
for vertex in self.vertices
] + [
ApplyMethod(
edge.scale_in_place,
(edge.get_length() - diameter) / edge.get_length()
)
for edge in self.edges
])
def annotate_edges(self, mobject):
angles = map(np.arctan, map(Line.get_slope, self.edges))
self.edge_annotations = [
deepcopy(mobject).rotate(angle).shift(edge.get_center())
for angle, edge in zip(angles, self.edges)
]
self.animate(*[
FadeIn(ann)
for ann in self.edge_annotations
])
BIG_N_PASCAL_ROWS = 11
N_PASCAL_ROWS = 7
class PascalsTriangleScene(Scene):

View File

@ -63,7 +63,7 @@ def find_scene_class_and_args(scene_string, args_extension,
sys.exit(0)
return possible_results[index]
def command_line_create_scene(sys_argv, movie_prefix = ""):
def command_line_create_scene(movie_prefix = ""):
scene_classes = [
pair[1]
for pair in inspect.getmembers(
@ -74,7 +74,7 @@ def command_line_create_scene(sys_argv, movie_prefix = ""):
)
]
try:
opts, args = getopt.getopt(sys_argv, "h:l:p")
opts, args = getopt.getopt(sys.argv[1:], 'hlps')
except getopt.GetoptError as err:
print str(err)
sys.exit(2)
@ -82,7 +82,7 @@ def command_line_create_scene(sys_argv, movie_prefix = ""):
scene_string = ""
args_extension = ""
display_config = PRODUCTION_QUALITY_DISPLAY_CONFIG
preview = False
action = "write"
for opt, arg in opts:
if opt == '-h':
@ -92,7 +92,9 @@ def command_line_create_scene(sys_argv, movie_prefix = ""):
display_config = LOW_QUALITY_DISPLAY_CONFIG
elif opt == '-p':
display_config = LOW_QUALITY_DISPLAY_CONFIG
preview = True
action = "preview"
elif opt == '-s':
action = "show_frame"
if len(args) > 0:
scene_string = args[0]
if len(args) > 1:
@ -105,10 +107,14 @@ def command_line_create_scene(sys_argv, movie_prefix = ""):
name = SceneClass.__name__ + SceneClass.args_to_string(*args)
print "Constructing %s..."%name
scene = SceneClass(*args, display_config = display_config)
if preview:
scene.preview()
else:
if action == "write":
scene.write_to_movie(movie_prefix + name)
elif action == "preview":
scene.preview()
elif action == "show_frame":
scene.show_frame()

View File

@ -0,0 +1,48 @@
#!/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, GraphScene
from moser_main import EulersFormula
from script_wrapper import command_line_create_scene
MOVIE_PREFIX = "ecf_graph_scenes/"
class IntroduceGraphs(GraphScene):
def construct(self):
GraphScene.construct(self)
self.draw_vertices()
self.draw_edges()
self.dither()
self.clear()
self.add(*self.edges)
self.replace_vertices_with(SimpleFace().scale(0.4))
friends = text_mobject("Friends").scale(0.5)
self.annotate_edges(friends.shift((0, friends.get_height()/2, 0)))
self.animate(*[
SemiCircleTransform(vertex, Dot(point))
for vertex, point in zip(self.vertices, self.points)
]+[
Transform(ann, line)
for ann, line in zip(
self.edge_annotations,
self.edges
)
])
self.dither()
class PlanarGraphDefinition(Scene):
def construct(self):
if __name__ == "__main__":
command_line_create_scene(MOVIE_PREFIX)

View File

@ -1,24 +1,19 @@
#!/usr/bin/env python
from PIL import Image
import numpy as np
from animation import *
from mobject import *
from constants import *
from helpers import *
from scene import *
from image_mobject import *
import itertools as it
import os
import numpy as np
DARK_BLUE = "#236B8E"
DARK_BROWN = "#8B4513"
LIGHT_BROWN = "#CD853F"
LOGO_RADIUS = 1.5
if __name__ == '__main__':
circle = Circle(density = 100, color = 'skyblue').repeat(5).scale(LOGO_RADIUS)
sphere = Sphere(density = 50, color = DARK_BLUE).scale(LOGO_RADIUS)

View File

@ -8,7 +8,6 @@ from copy import deepcopy
from animation import *
from mobject import *
from image_mobject import *
from constants import *
from region import *
from scene import Scene

View File

@ -11,14 +11,123 @@ import inspect
from animation import *
from mobject import *
from image_mobject import *
from constants import *
from region import *
from scene import Scene
from scene import Scene, GraphScene, PascalsTriangleScene
from script_wrapper import command_line_create_scene
from moser_helpers import *
from graphs import *
RADIUS = SPACE_HEIGHT - 0.1
CIRCLE_DENSITY = DEFAULT_POINT_DENSITY_1D*RADIUS
MOVIE_PREFIX = "moser/"
RADIANS = np.arange(0, 6, 6.0/7)
MORE_RADIANS = np.append(RADIANS, RADIANS + 0.5)
N_PASCAL_ROWS = 7
BIG_N_PASCAL_ROWS = 11
def int_list_to_string(int_list):
return "-".join(map(str, int_list))
def moser_function(n):
return choose(n, 4) + choose(n, 2) + 1
###########################################
class CircleScene(Scene):
args_list = [
(RADIANS[:x],)
for x in range(1, len(RADIANS)+1)
]
@staticmethod
def args_to_string(*args):
return str(len(args[0])) #Length of radians
def __init__(self, radians, radius = RADIUS, *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.n_equals = tex_mobject(
"n=%d"%len(radians),
).shift((-SPACE_WIDTH+1, SPACE_HEIGHT-1.5, 0))
self.add(self.circle, self.n_equals, *self.dots + self.lines)
def generate_intersection_dots(self):
"""
Generates and adds attributes intersection_points and
intersection_dots, but does not yet add them to the scene
"""
self.intersection_points = [
intersection((p[0], p[2]), (p[1], p[3]))
for p in it.combinations(self.points, 4)
]
self.intersection_dots = [
Dot(point) for point in self.intersection_points
]
def chop_lines_at_intersection_points(self):
if not hasattr(self, "intersection_dots"):
self.generate_intersection_dots()
self.remove(*self.lines)
self.lines = []
for point_pair in it.combinations(self.points, 2):
int_points = filter(
lambda p : is_on_line(p, *point_pair),
self.intersection_points
)
points = list(point_pair) + int_points
points = map(lambda p : (p[0], p[1], 0), points)
points.sort(cmp = lambda x,y: cmp(x[0], y[0]))
self.lines += [
Line(points[i], points[i+1])
for i in range(len(points)-1)
]
self.add(*self.lines)
def chop_circle_at_points(self):
self.remove(self.circle)
self.circle_pieces = []
self.smaller_circle_pieces = []
for i in range(len(self.points)):
pp = self.points[i], self.points[(i+1)%len(self.points)]
transform = np.array([
[pp[0][0], pp[1][0], 0],
[pp[0][1], pp[1][1], 0],
[0, 0, 1]
])
circle = deepcopy(self.circle)
smaller_circle = deepcopy(self.circle)
for c in circle, smaller_circle:
c.points = np.dot(
c.points,
np.transpose(np.linalg.inv(transform))
)
c.filter_out(
lambda p : p[0] < 0 or p[1] < 0
)
if c == smaller_circle:
c.filter_out(
lambda p : p[0] > 4*p[1] or p[1] > 4*p[0]
)
c.points = np.dot(
c.points,
np.transpose(transform)
)
self.circle_pieces.append(circle)
self.smaller_circle_pieces.append(smaller_circle)
self.add(*self.circle_pieces)
def generate_regions(self):
self.regions = plane_partition_from_points(*self.points)
interior = Region(lambda x, y : x**2 + y**2 < self.radius**2)
map(lambda r : r.intersect(interior), self.regions)
self.exterior = interior.complement()
class CountSections(CircleScene):
def __init__(self, *args, **kwargs):
@ -688,8 +797,14 @@ class EulersFormula(GraphScene):
for d in self.dots
]
colored_edges = [
deepcopy(e).highlight("red")
CompoundMobject(
Line(midpoint, start),
Line(midpoint, end),
).highlight("red")
for e in self.edges
for start, end, midpoint in [
(e.start, e.end, (e.start + e.end)/2)
]
]
frame_time = 0.3
@ -1585,7 +1700,7 @@ class IntersectionChoppingExamples(Scene):
##################################################
if __name__ == "__main__":
command_line_create_scene(sys.argv[1:], MOVIE_PREFIX)
command_line_create_scene(MOVIE_PREFIX)