mirror of
https://github.com/3b1b/manim.git
synced 2025-09-01 00:48:45 +00:00
Additive/multiplicative rules
This commit is contained in:
parent
dbb31980da
commit
e5dc0db8ef
7 changed files with 320 additions and 33 deletions
|
@ -130,19 +130,18 @@ class Homotopy(Animation):
|
||||||
|
|
||||||
class PhaseFlow(Animation):
|
class PhaseFlow(Animation):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"virtual_time" : 1
|
"virtual_time" : 1,
|
||||||
|
"rate_func" : None,
|
||||||
}
|
}
|
||||||
def __init__(self, function, mobject, **kwargs):
|
def __init__(self, function, mobject, **kwargs):
|
||||||
digest_config(self, kwargs, locals())
|
digest_config(self, kwargs, locals())
|
||||||
self.get_nudge_func = lambda alpha_diff : \
|
|
||||||
lambda point : point + alpha_diff*function(point)
|
|
||||||
Animation.__init__(self, mobject, **kwargs)
|
Animation.__init__(self, mobject, **kwargs)
|
||||||
|
|
||||||
def update_mobject(self, alpha):
|
def update_mobject(self, alpha):
|
||||||
if hasattr(self, "last_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.mobject.apply_function(
|
||||||
self.get_nudge_func(nudge)
|
lambda p : p + dt*self.function(p)
|
||||||
)
|
)
|
||||||
self.last_alpha = alpha
|
self.last_alpha = alpha
|
||||||
|
|
||||||
|
@ -160,19 +159,25 @@ class MoveAlongPath(Animation):
|
||||||
|
|
||||||
class ApplyToCenters(Animation):
|
class ApplyToCenters(Animation):
|
||||||
def __init__(self, AnimationClass, mobjects, **kwargs):
|
def __init__(self, AnimationClass, mobjects, **kwargs):
|
||||||
centers = [mob.get_center() for mob in mobjects]
|
full_kwargs = AnimationClass.CONFIG
|
||||||
kwargs["mobject"] = Mobject().add_points(centers)
|
full_kwargs.update(kwargs)
|
||||||
self.centers_container = AnimationClass(**kwargs)
|
full_kwargs["mobject"] = Mobject(*[
|
||||||
kwargs.pop("mobject")
|
mob.get_point_mobject()
|
||||||
Animation.__init__(self, Mobject(*mobjects), **kwargs)
|
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__
|
self.name = str(self) + AnimationClass.__name__
|
||||||
|
|
||||||
def update_mobject(self, alpha):
|
def update_mobject(self, alpha):
|
||||||
self.centers_container.update_mobject(alpha)
|
self.centers_container.update_mobject(alpha)
|
||||||
points = self.centers_container.mobject.points
|
center_mobs = self.centers_container.mobject.split()
|
||||||
mobjects = self.mobject.split()
|
mobjects = self.mobject.split()
|
||||||
for point, mobject in zip(points, mobjects):
|
for center_mob, mobject in zip(center_mobs, mobjects):
|
||||||
mobject.center().shift(point)
|
mobject.shift(
|
||||||
|
center_mob.get_center()-mobject.get_center()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -129,6 +129,8 @@ class Camera(object):
|
||||||
if len(points) == 0:
|
if len(points) == 0:
|
||||||
continue
|
continue
|
||||||
coords = self.points_to_pixel_coords(points)
|
coords = self.points_to_pixel_coords(points)
|
||||||
|
if np.all(~self.on_screen_pixels(coords)):
|
||||||
|
return result
|
||||||
start = "M%d %d"%tuple(coords[0])
|
start = "M%d %d"%tuple(coords[0])
|
||||||
#(handle1, handle2, anchor) tripletes
|
#(handle1, handle2, anchor) tripletes
|
||||||
triplets = zip(*[
|
triplets = zip(*[
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import itertools as it
|
import itertools as it
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
import cv2
|
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
from mobject import Mobject
|
from mobject import Mobject
|
||||||
|
|
|
@ -87,9 +87,11 @@ class VMobject(Mobject):
|
||||||
|
|
||||||
def get_stroke_color(self):
|
def get_stroke_color(self):
|
||||||
try:
|
try:
|
||||||
|
self.stroke_rgb[self.stroke_rgb<0] = 0
|
||||||
|
self.stroke_rgb[self.stroke_rgb>1] = 1
|
||||||
return Color(rgb = self.stroke_rgb)
|
return Color(rgb = self.stroke_rgb)
|
||||||
except:
|
except:
|
||||||
return Color(rgb = 0.99*self.stroke_rgb)
|
return Color(WHITE)
|
||||||
|
|
||||||
#TODO, get color? Specify if stroke or fill
|
#TODO, get color? Specify if stroke or fill
|
||||||
#is the predominant color attribute?
|
#is the predominant color attribute?
|
||||||
|
@ -192,6 +194,16 @@ class VMobject(Mobject):
|
||||||
self.submobjects
|
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
|
## Information about line
|
||||||
|
|
||||||
def component_curves(self):
|
def component_curves(self):
|
||||||
|
|
|
@ -56,10 +56,10 @@ class PiCreature(SVGMobject):
|
||||||
self.set_stroke(color = BLACK, width = self.stroke_width)
|
self.set_stroke(color = BLACK, width = self.stroke_width)
|
||||||
if not self.parts_named:
|
if not self.parts_named:
|
||||||
self.name_parts()
|
self.name_parts()
|
||||||
self.mouth.set_fill(BLACK)
|
self.mouth.set_fill(BLACK, opacity = 1)
|
||||||
self.body.set_fill(self.color)
|
self.body.set_fill(self.color, opacity = 1)
|
||||||
self.pupils.set_fill(BLACK)
|
self.pupils.set_fill(BLACK, opacity = 1)
|
||||||
self.eyes.set_fill(WHITE)
|
self.eyes.set_fill(WHITE, opacity = 1)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -98,6 +98,9 @@ class UnitInterval(NumberLine):
|
||||||
|
|
||||||
|
|
||||||
class Axes(VMobject):
|
class Axes(VMobject):
|
||||||
|
CONFIG = {
|
||||||
|
"propogate_style_to_family" : True
|
||||||
|
}
|
||||||
def generate_points(self, **kwargs):
|
def generate_points(self, **kwargs):
|
||||||
self.x_axis = NumberLine(**kwargs)
|
self.x_axis = NumberLine(**kwargs)
|
||||||
self.y_axis = NumberLine(**kwargs).rotate(np.pi/2)
|
self.y_axis = NumberLine(**kwargs).rotate(np.pi/2)
|
||||||
|
@ -116,9 +119,10 @@ class NumberPlane(VMobject):
|
||||||
"x_line_frequency" : 1,
|
"x_line_frequency" : 1,
|
||||||
"y_line_frequency" : 1,
|
"y_line_frequency" : 1,
|
||||||
"secondary_line_ratio" : 1,
|
"secondary_line_ratio" : 1,
|
||||||
"written_coordinate_height" : 0.5,
|
"written_coordinate_height" : 0.2,
|
||||||
"written_coordinate_nudge" : 0.1*(DOWN+RIGHT),
|
"written_coordinate_nudge" : 0.1*(DOWN+RIGHT),
|
||||||
"num_pair_at_center" : (0, 0),
|
"num_pair_at_center" : (0, 0),
|
||||||
|
"propogate_style_to_family" : False,
|
||||||
}
|
}
|
||||||
|
|
||||||
def generate_points(self):
|
def generate_points(self):
|
||||||
|
@ -160,7 +164,7 @@ class NumberPlane(VMobject):
|
||||||
def init_colors(self):
|
def init_colors(self):
|
||||||
VMobject.init_colors(self)
|
VMobject.init_colors(self)
|
||||||
self.axes.set_stroke(self.axes_color)
|
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)
|
self.secondary_lines.set_stroke(self.secondary_color, 1)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,7 @@ def get_top_inverse(i, j):
|
||||||
class TOP(VMobject):
|
class TOP(VMobject):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"triangle_height_to_number_height" : 3,
|
"triangle_height_to_number_height" : 3,
|
||||||
"offset_multiple" : 1.2,
|
"offset_multiple" : 1.5,
|
||||||
"radius" : 1.5,
|
"radius" : 1.5,
|
||||||
"propogate_style_to_family" : False,
|
"propogate_style_to_family" : False,
|
||||||
}
|
}
|
||||||
|
@ -121,7 +121,7 @@ class TOP(VMobject):
|
||||||
value = TexMobject(value)
|
value = TexMobject(value)
|
||||||
if isinstance(value, TOP):
|
if isinstance(value, TOP):
|
||||||
return self.put_top_on_vertix(index, value)
|
return self.put_top_on_vertix(index, value)
|
||||||
value.scale_to_fit_height(self.get_value_height())
|
self.rescale_corner_mobject(value)
|
||||||
value.center()
|
value.center()
|
||||||
if index == 0:
|
if index == 0:
|
||||||
offset = -value.get_corner(UP+RIGHT)
|
offset = -value.get_corner(UP+RIGHT)
|
||||||
|
@ -134,6 +134,26 @@ class TOP(VMobject):
|
||||||
value.shift(anchors[index])
|
value.shift(anchors[index])
|
||||||
return value
|
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):
|
def get_surrounding_circle(self, color = YELLOW):
|
||||||
return Circle(
|
return Circle(
|
||||||
radius = 1.7*self.radius,
|
radius = 1.7*self.radius,
|
||||||
|
@ -143,20 +163,20 @@ class TOP(VMobject):
|
||||||
(self.triangle.get_height()/6)*DOWN
|
(self.triangle.get_height()/6)*DOWN
|
||||||
)
|
)
|
||||||
|
|
||||||
def put_top_on_vertix(self, index, top):
|
def rescale_corner_mobject(self, mobject):
|
||||||
top.scale_to_fit_height(2*self.get_value_height())
|
if mobject.get_height() > self.get_value_height():
|
||||||
top_anchors = list(
|
mobject.scale_to_fit_height(self.get_value_height())
|
||||||
top.triangle.get_anchors_and_handles()[0][:3]
|
return self
|
||||||
)
|
|
||||||
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 get_value_height(self):
|
def get_value_height(self):
|
||||||
return self.triangle.get_height()/self.triangle_height_to_number_height
|
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):
|
def reset_submobjects(self):
|
||||||
self.submobjects = [self.triangle] + self.values
|
self.submobjects = [self.triangle] + self.values
|
||||||
return self
|
return self
|
||||||
|
@ -501,6 +521,251 @@ class AdditiveProperty(Scene):
|
||||||
self.remove(copies)
|
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):
|
class Test(Scene):
|
||||||
|
|
Loading…
Add table
Reference in a new issue