Additive/multiplicative rules

This commit is contained in:
Grant Sanderson
2016-04-30 15:08:53 -07:00
parent dbb31980da
commit e5dc0db8ef
7 changed files with 320 additions and 33 deletions

View File

@ -130,19 +130,18 @@ class Homotopy(Animation):
class PhaseFlow(Animation):
CONFIG = {
"virtual_time" : 1
"virtual_time" : 1,
"rate_func" : None,
}
def __init__(self, function, mobject, **kwargs):
digest_config(self, kwargs, locals())
self.get_nudge_func = lambda alpha_diff : \
lambda point : point + alpha_diff*function(point)
Animation.__init__(self, mobject, **kwargs)
def update_mobject(self, alpha):
if hasattr(self, "last_alpha"):
nudge = self.virtual_time*(alpha-self.last_alpha)
dt = self.virtual_time*(alpha-self.last_alpha)
self.mobject.apply_function(
self.get_nudge_func(nudge)
lambda p : p + dt*self.function(p)
)
self.last_alpha = alpha
@ -160,19 +159,25 @@ class MoveAlongPath(Animation):
class ApplyToCenters(Animation):
def __init__(self, AnimationClass, mobjects, **kwargs):
centers = [mob.get_center() for mob in mobjects]
kwargs["mobject"] = Mobject().add_points(centers)
self.centers_container = AnimationClass(**kwargs)
kwargs.pop("mobject")
Animation.__init__(self, Mobject(*mobjects), **kwargs)
full_kwargs = AnimationClass.CONFIG
full_kwargs.update(kwargs)
full_kwargs["mobject"] = Mobject(*[
mob.get_point_mobject()
for mob in mobjects
])
self.centers_container = AnimationClass(**full_kwargs)
full_kwargs.pop("mobject")
Animation.__init__(self, Mobject(*mobjects), **full_kwargs)
self.name = str(self) + AnimationClass.__name__
def update_mobject(self, alpha):
self.centers_container.update_mobject(alpha)
points = self.centers_container.mobject.points
center_mobs = self.centers_container.mobject.split()
mobjects = self.mobject.split()
for point, mobject in zip(points, mobjects):
mobject.center().shift(point)
for center_mob, mobject in zip(center_mobs, mobjects):
mobject.shift(
center_mob.get_center()-mobject.get_center()
)

View File

@ -129,6 +129,8 @@ class Camera(object):
if len(points) == 0:
continue
coords = self.points_to_pixel_coords(points)
if np.all(~self.on_screen_pixels(coords)):
return result
start = "M%d %d"%tuple(coords[0])
#(handle1, handle2, anchor) tripletes
triplets = zip(*[

View File

@ -1,7 +1,6 @@
import numpy as np
import itertools as it
from PIL import Image
import cv2
from copy import deepcopy
from mobject import Mobject

View File

@ -87,9 +87,11 @@ class VMobject(Mobject):
def get_stroke_color(self):
try:
self.stroke_rgb[self.stroke_rgb<0] = 0
self.stroke_rgb[self.stroke_rgb>1] = 1
return Color(rgb = self.stroke_rgb)
except:
return Color(rgb = 0.99*self.stroke_rgb)
return Color(WHITE)
#TODO, get color? Specify if stroke or fill
#is the predominant color attribute?
@ -192,6 +194,16 @@ class VMobject(Mobject):
self.submobjects
)
def arrange_submobjects(self,
direction = RIGHT,
buff = DEFAULT_MOBJECT_TO_MOBJECT_BUFFER,
center = True):
for m1, m2 in zip(self.submobjects, self.submobjects[1:]):
m2.next_to(m1, direction, buff = buff)
if center:
self.center()
return self
## Information about line
def component_curves(self):

View File

@ -56,10 +56,10 @@ class PiCreature(SVGMobject):
self.set_stroke(color = BLACK, width = self.stroke_width)
if not self.parts_named:
self.name_parts()
self.mouth.set_fill(BLACK)
self.body.set_fill(self.color)
self.pupils.set_fill(BLACK)
self.eyes.set_fill(WHITE)
self.mouth.set_fill(BLACK, opacity = 1)
self.body.set_fill(self.color, opacity = 1)
self.pupils.set_fill(BLACK, opacity = 1)
self.eyes.set_fill(WHITE, opacity = 1)
return self

View File

@ -98,6 +98,9 @@ class UnitInterval(NumberLine):
class Axes(VMobject):
CONFIG = {
"propogate_style_to_family" : True
}
def generate_points(self, **kwargs):
self.x_axis = NumberLine(**kwargs)
self.y_axis = NumberLine(**kwargs).rotate(np.pi/2)
@ -116,9 +119,10 @@ class NumberPlane(VMobject):
"x_line_frequency" : 1,
"y_line_frequency" : 1,
"secondary_line_ratio" : 1,
"written_coordinate_height" : 0.5,
"written_coordinate_height" : 0.2,
"written_coordinate_nudge" : 0.1*(DOWN+RIGHT),
"num_pair_at_center" : (0, 0),
"propogate_style_to_family" : False,
}
def generate_points(self):
@ -160,7 +164,7 @@ class NumberPlane(VMobject):
def init_colors(self):
VMobject.init_colors(self)
self.axes.set_stroke(self.axes_color)
# self.main_lines.set_stroke(self.color)
self.main_lines.set_stroke(self.color)
self.secondary_lines.set_stroke(self.secondary_color, 1)
return self

View File

@ -82,7 +82,7 @@ def get_top_inverse(i, j):
class TOP(VMobject):
CONFIG = {
"triangle_height_to_number_height" : 3,
"offset_multiple" : 1.2,
"offset_multiple" : 1.5,
"radius" : 1.5,
"propogate_style_to_family" : False,
}
@ -121,7 +121,7 @@ class TOP(VMobject):
value = TexMobject(value)
if isinstance(value, TOP):
return self.put_top_on_vertix(index, value)
value.scale_to_fit_height(self.get_value_height())
self.rescale_corner_mobject(value)
value.center()
if index == 0:
offset = -value.get_corner(UP+RIGHT)
@ -134,6 +134,26 @@ class TOP(VMobject):
value.shift(anchors[index])
return value
def put_top_on_vertix(self, index, top):
top.scale_to_fit_height(2*self.get_value_height())
vertices = top.get_vertices()
vertices[index] = 0
start = reduce(op.add, vertices)/2
end = self.triangle.get_anchors_and_handles()[0][index]
top.shift(end-start)
return top
def put_in_vertex(self, index, mobject):
self.rescale_corner_mobject(mobject)
mobject.center()
mobject.shift(interpolate(
self.get_center(),
self.get_vertices()[index],
0.7
))
return mobject
def get_surrounding_circle(self, color = YELLOW):
return Circle(
radius = 1.7*self.radius,
@ -143,20 +163,20 @@ class TOP(VMobject):
(self.triangle.get_height()/6)*DOWN
)
def put_top_on_vertix(self, index, top):
top.scale_to_fit_height(2*self.get_value_height())
top_anchors = list(
top.triangle.get_anchors_and_handles()[0][:3]
)
top_anchors[index] = 0
start = reduce(op.add, top_anchors)/2
end = self.triangle.get_anchors_and_handles()[0][index]
top.shift(end-start)
return top
def rescale_corner_mobject(self, mobject):
if mobject.get_height() > self.get_value_height():
mobject.scale_to_fit_height(self.get_value_height())
return self
def get_value_height(self):
return self.triangle.get_height()/self.triangle_height_to_number_height
def get_center(self):
return center_of_mass(self.get_vertices())
def get_vertices(self):
return self.triangle.get_anchors_and_handles()[0][:3]
def reset_submobjects(self):
self.submobjects = [self.triangle] + self.values
return self
@ -501,6 +521,251 @@ class AdditiveProperty(Scene):
self.remove(copies)
class DrawInsideTriangle(Scene):
def construct(self):
top = TOP()
top.scale(2)
dot = top.put_in_vertex(0, Dot())
plus = top.put_in_vertex(1, TexMobject("+"))
times = top.put_in_vertex(2, TexMobject("\\times"))
plus.highlight(GREEN)
times.highlight(YELLOW)
self.add(top)
self.dither()
for mob in dot, plus, times:
self.play(Write(mob, run_time = 1))
self.dither()
class ConstantOnTop(Scene):
def construct(self):
top = TOP()
dot = top.put_in_vertex(1, Dot())
times1 = top.put_in_vertex(0, TexMobject("\\times"))
times2 = top.put_in_vertex(2, TexMobject("\\times"))
times1.highlight(YELLOW)
times2.highlight(YELLOW)
three = top.put_on_vertex(1, "3")
lower_left_x = top.put_on_vertex(0, "x")
lower_right_x = top.put_on_vertex(2, "x")
x_cubed = TexMobject("x^3").to_edge(UP)
x_cubed.submobjects.reverse() #To align better
cube_root_x = TexMobject("\\sqrt[3]{x}").to_edge(UP)
self.add(top)
self.play(ShowCreation(three))
self.play(
FadeIn(lower_left_x),
Write(x_cubed),
run_time = 1
)
self.dither()
self.play(*[
Transform(*pair, path_arc = np.pi)
for pair in [
(lower_left_x, lower_right_x),
(x_cubed, cube_root_x),
]
])
self.dither(2)
for mob in dot, times1, times2:
self.play(ShowCreation(mob))
self.dither()
def get_const_top_TOP(*args):
top = TOP(*args)
dot = top.put_in_vertex(1, Dot())
times1 = top.put_in_vertex(0, TexMobject("\\times"))
times2 = top.put_in_vertex(2, TexMobject("\\times"))
times1.highlight(YELLOW)
times2.highlight(YELLOW)
top.add(dot, times1, times2)
return top
class MultiplyWithConstantTop(Scene):
def construct(self):
top1 = get_const_top_TOP("x", "3")
top2 = get_const_top_TOP("y", "3")
top3 = get_const_top_TOP("xy", "3")
times = TexMobject("\\times")
equals = TexMobject("=")
top_exp_equation = VMobject(
top1, times, top2, equals, top3
)
top_exp_equation.arrange_submobjects()
old_style_exp = TexMobject("(x^3)(y^3) = (xy)^3")
old_style_exp.to_edge(UP)
old_style_exp.highlight(GREEN)
old_style_rad = TexMobject("\\sqrt[3]{x} \\sqrt[3]{y} = \\sqrt[3]{xy}")
old_style_rad.to_edge(UP)
old_style_rad.highlight(RED)
self.add(top_exp_equation, old_style_exp)
self.dither(3)
old_tops = [top1, top2, top3]
new_tops = []
for top in old_tops:
new_top = top.copy()
new_top.put_on_vertex(2, new_top.values[0])
new_top.shift(0.5*LEFT)
new_tops.append(new_top)
self.play(
Transform(old_style_exp, old_style_rad),
Transform(
VMobject(*old_tops),
VMobject(*new_tops),
path_arc = np.pi/2
)
)
self.dither(3)
class RightStaysConstantQ(Scene):
def construct(self):
top1, top2, top3 = old_tops = [
TOP(None, s, "8")
for s in "x", "y", TexMobject("x?y")
]
q_mark = TexMobject("?").scale(2)
equation = VMobject(
top1, q_mark, top2, TexMobject("="), top3
)
equation.arrange_submobjects(buff = 0.7)
symbols_at_top = VMobject(*[
top.values[1]
for top in top1, top2, top3
])
symbols_at_lower_right = VMobject(*[
top.put_on_vertex(0, top.values[1].copy())
for top in top1, top2, top3
])
old_style_eq1 = TexMobject("\\sqrt[x]{8} ? \\sqrt[y]{8} = \\sqrt[x?y]{8}")
old_style_eq1.highlight(BLUE)
old_style_eq2 = TexMobject("\\log_x(8) ? \\log_y(8) = \\log_{x?y}(8)")
old_style_eq2.highlight(YELLOW)
for eq in old_style_eq1, old_style_eq2:
eq.to_edge(UP)
randy = Randolph()
randy.to_corner()
bubble = ThoughtBubble().pin_to(randy)
bubble.add_content(TOP(None, None, "8"))
self.add(randy, bubble)
self.play(ApplyMethod(randy.change_mode, "pondering"))
self.dither(3)
triangle = bubble.content.triangle
eight = bubble.content.values[2]
bubble.clear()
self.play(
Transform(triangle, equation),
FadeOut(eight),
ApplyPointwiseFunction(
lambda p : (p+2*DOWN)*15/np.linalg.norm(p+2*DOWN),
bubble
),
FadeIn(old_style_eq1),
ApplyMethod(randy.shift, 3*DOWN + 3*LEFT),
run_time = 2
)
self.remove(triangle)
self.add(equation)
self.dither(4)
self.play(
Transform(
symbols_at_top, symbols_at_lower_right,
path_arc = np.pi/2
),
Transform(old_style_eq1, old_style_eq2)
)
self.dither(2)
class AOplusB(Scene):
def construct(self):
self.add(TexMobject(
"a \\oplus b = \\dfrac{1}{\\frac{1}{a} + \\frac{1}{b}}"
).scale(2))
self.dither()
class ConstantLowerRight(Scene):
def construct(self):
top = TOP()
times = top.put_in_vertex(0, TexMobject("\\times"))
times.highlight(YELLOW)
oplus = top.put_in_vertex(1, TexMobject("\\oplus"))
oplus.highlight(BLUE)
dot = top.put_in_vertex(2, Dot())
eight = top.put_on_vertex(2, TexMobject("8"))
self.add(top)
self.play(ShowCreation(eight))
for mob in dot, oplus, times:
self.play(ShowCreation(mob))
self.dither()
top.add(eight)
top.add(times, oplus, dot)
top1, top2, top3 = tops = [
top.copy() for i in range(3)
]
big_oplus = TexMobject("\\oplus").scale(2).highlight(BLUE)
equals = TexMobject("=")
equation = VMobject(
top1, big_oplus, top2, equals, top3
)
equation.arrange_submobjects()
top3.shift(0.5*RIGHT)
x, y, xy = [
t.put_on_vertex(0, s)
for t, s in zip(tops, ["x", "y", "xy"])
]
old_style_eq = TexMobject(
"\\dfrac{1}{\\frac{1}{\\log_x(8)} + \\frac{1}{\\log_y(8)}} = \\log_{xy}(8)"
)
old_style_eq.to_edge(UP).highlight(RED)
triple_top_copy = VMobject(*[
top.copy() for i in range(3)
])
self.clear()
self.play(
Transform(triple_top_copy, VMobject(*tops)),
FadeIn(VMobject(x, y, xy, big_oplus, equals))
)
self.remove(triple_top_copy)
self.add(*tops)
self.play(Write(old_style_eq))
self.dither(3)
syms = VMobject(x, y, xy)
new_syms = VMobject(*[
t.put_on_vertex(1, s)
for t, s in zip(tops, ["x", "y", "x \\oplus y"])
])
new_old_style_eq = TexMobject(
"\\sqrt[x]{8} \\sqrt[y]{8} = \\sqrt[X]{8}"
)
X = new_old_style_eq.split()[-4]
frac = TexMobject("\\frac{1}{\\frac{1}{x} + \\frac{1}{y}}")
frac.replace(X)
frac_lower_right = frac.get_corner(DOWN+RIGHT)
frac.scale(2)
frac.shift(frac_lower_right - frac.get_corner(DOWN+RIGHT))
new_old_style_eq.submobjects[-4] = frac
new_old_style_eq.to_edge(UP)
new_old_style_eq.highlight(RED)
big_times = TexMobject("\\times").highlight(YELLOW)
big_times.shift(big_oplus.get_center())
self.play(
Transform(old_style_eq, new_old_style_eq),
Transform(syms, new_syms, path_arc = np.pi/2),
Transform(big_oplus, big_times)
)
self.dither(4)
class Test(Scene):