mirror of
https://github.com/3b1b/manim.git
synced 2025-09-19 04:41:56 +00:00
Merge branch 'master' into eop
This commit is contained in:
commit
9e2ce6ea62
6 changed files with 403 additions and 13 deletions
75
active_projects/name_animation.py
Normal file
75
active_projects/name_animation.py
Normal file
|
@ -0,0 +1,75 @@
|
|||
from big_ol_pile_of_manim_imports import *
|
||||
|
||||
NAME_WITH_SPACES = "Prime Meridian"
|
||||
DIAMETER = 3.0
|
||||
RADIUS = DIAMETER / 2
|
||||
LETTER_SCALE = 1
|
||||
|
||||
class NameAnimationScene(Scene):
|
||||
|
||||
def construct(self):
|
||||
|
||||
name = ''.join(NAME_WITH_SPACES.split(' '))
|
||||
letters = list(name)
|
||||
nb_letters = len(letters)
|
||||
randy = PiCreature()
|
||||
randy.move_to(ORIGIN).scale_to_fit_height(0.5 * DIAMETER)
|
||||
randy.set_color(BLUE_E)
|
||||
randy.look_at(UP + RIGHT)
|
||||
self.add(randy)
|
||||
dtheta = TAU/nb_letters
|
||||
angles = np.arange(TAU/4,-3 * TAU / 4,-dtheta)
|
||||
name_mob = VGroup()
|
||||
for (letter, angle) in zip(letters, angles):
|
||||
letter_mob = TextMobject(letter).scale(LETTER_SCALE)
|
||||
pos = RADIUS * np.cos(angle) * RIGHT + RADIUS * np.sin(angle) * UP
|
||||
letter_mob.move_to(pos)
|
||||
name_mob.add(letter_mob)
|
||||
|
||||
pos2 = RADIUS * np.cos(angles[2]) * RIGHT + RADIUS * np.sin(angles[2]) * UP
|
||||
|
||||
self.play(
|
||||
LaggedStart(Write, name_mob, run_time = 3),
|
||||
ApplyMethod(randy.look_at, pos2, run_time = 3)
|
||||
)
|
||||
|
||||
for i in range(2,nb_letters + 2):
|
||||
|
||||
group = []
|
||||
|
||||
for (j,letter_mob) in enumerate(name_mob.submobjects):
|
||||
|
||||
new_angle = TAU / 4 - i * j * dtheta
|
||||
new_pos = RADIUS * np.cos(new_angle) * RIGHT + RADIUS * np.sin(new_angle) * UP
|
||||
letter_mob.target = letter_mob.copy().move_to(new_pos)
|
||||
anim = MoveToTarget(letter_mob, path_arc = - j * dtheta)
|
||||
group.append(anim)
|
||||
|
||||
self.play(
|
||||
AnimationGroup(*group, run_time = 3),
|
||||
ApplyMethod(randy.look_at,name_mob.submobjects[2], run_time = 3)
|
||||
)
|
||||
self.wait(0.5)
|
||||
|
||||
|
||||
thank_you = TextMobject("Thank You!").next_to(randy, DOWN)
|
||||
new_randy = randy.copy()
|
||||
new_randy.change("hooray")
|
||||
new_randy.set_color(BLUE_E)
|
||||
new_randy.look_at(ORIGIN)
|
||||
self.play(
|
||||
Transform(name_mob, thank_you),
|
||||
Transform(randy, new_randy)
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
303
active_projects/wallis_g.py
Normal file
303
active_projects/wallis_g.py
Normal file
|
@ -0,0 +1,303 @@
|
|||
from big_ol_pile_of_manim_imports import *
|
||||
from once_useful_constructs.light import AmbientLight
|
||||
from once_useful_constructs.light import Lighthouse
|
||||
from once_useful_constructs.light import SwitchOn
|
||||
# from once_useful_constructs.light import LightSource
|
||||
|
||||
|
||||
class IntroduceDistanceProduct(MovingCameraScene):
|
||||
CONFIG = {
|
||||
"ambient_light_config": {
|
||||
"opacity_function": inverse_quadratic(1, 1.1, 1),
|
||||
"num_levels": 100,
|
||||
# "num_levels": 10,
|
||||
"light_radius": 10,
|
||||
# "radius": 1,
|
||||
"max_opacity": 0.4,
|
||||
"color": YELLOW,
|
||||
},
|
||||
"num_lighthouses": 6,
|
||||
"circle_radius": 3,
|
||||
"observer_color": MAROON_B,
|
||||
"lighthouse_height": 0.5,
|
||||
"camera_class": MovingCamera,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.draw_circle_with_points()
|
||||
self.turn_into_lighthouses_and_observer()
|
||||
self.show_sum_of_inverse_squares()
|
||||
|
||||
def draw_circle_with_points(self):
|
||||
circle = Circle(color=BLUE)
|
||||
circle.scale(self.circle_radius)
|
||||
|
||||
lh_dots = self.lh_dots = VGroup(*[
|
||||
Dot().move_to(circle.point_from_proportion(alpha))
|
||||
for alpha in np.arange(0, 1, 1.0 / self.num_lighthouses)
|
||||
])
|
||||
lh_dot_arrows = VGroup(*[
|
||||
Arrow(*[
|
||||
interpolate(circle.get_center(), dot.get_center(), a)
|
||||
for a in 0.6, 0.9
|
||||
], buff=0)
|
||||
for dot in lh_dots
|
||||
])
|
||||
evenly_space_dots_label = TextMobject("Evenly-spaced \\\\ dots")
|
||||
evenly_space_dots_label.scale_to_fit_width(0.5 * circle.get_width())
|
||||
evenly_space_dots_label.move_to(circle)
|
||||
|
||||
special_dot = self.special_dot = Dot(color=self.observer_color)
|
||||
special_dot.move_to(circle.point_from_proportion(0.04))
|
||||
special_dot_arrow = Vector(DL)
|
||||
special_dot_arrow.next_to(special_dot, UR, SMALL_BUFF)
|
||||
special_dot_arrow.match_color(special_dot)
|
||||
special_dot_label = TextMobject("Special dot")
|
||||
special_dot_label.next_to(
|
||||
special_dot_arrow.get_start(), UP, SMALL_BUFF)
|
||||
special_dot_label.match_color(special_dot)
|
||||
special_dot.save_state()
|
||||
special_dot.next_to(special_dot_arrow, UR)
|
||||
special_dot.set_fill(opacity=0)
|
||||
|
||||
self.play(ShowCreation(circle))
|
||||
self.play(
|
||||
LaggedStart(ShowCreation, lh_dots),
|
||||
LaggedStart(GrowArrow, lh_dot_arrows),
|
||||
Write(evenly_space_dots_label)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
special_dot.restore,
|
||||
GrowArrow(special_dot_arrow),
|
||||
Write(special_dot_label, run_time=1),
|
||||
FadeOut(VGroup(lh_dot_arrows, evenly_space_dots_label))
|
||||
)
|
||||
self.wait()
|
||||
self.play(FadeOut(VGroup(special_dot_arrow, special_dot_label)))
|
||||
|
||||
def turn_into_lighthouses_and_observer(self):
|
||||
lighthouses = self.lighthouses = VGroup()
|
||||
lights = self.lights = VGroup()
|
||||
for dot in self.lh_dots:
|
||||
point = dot.get_center()
|
||||
lighthouse = Lighthouse()
|
||||
lighthouse.scale_to_fit_height(self.lighthouse_height)
|
||||
lighthouse.move_to(point)
|
||||
lighthouses.add(lighthouse)
|
||||
|
||||
light = AmbientLight(
|
||||
source_point=VectorizedPoint(point),
|
||||
**self.ambient_light_config
|
||||
)
|
||||
lights.add(light)
|
||||
|
||||
observer = self.observer = PiCreature(color=self.observer_color)
|
||||
observer.flip()
|
||||
observer.move_to(self.special_dot)
|
||||
observer.to_edge(RIGHT)
|
||||
|
||||
self.play(
|
||||
LaggedStart(FadeOut, self.lh_dots),
|
||||
LaggedStart(FadeIn, lighthouses),
|
||||
LaggedStart(SwitchOn, lights),
|
||||
)
|
||||
self.wait()
|
||||
self.play(FadeIn(observer))
|
||||
self.play(
|
||||
observer.scale_to_fit_height, 0.25,
|
||||
observer.next_to, self.special_dot, RIGHT, 0.5 * SMALL_BUFF,
|
||||
)
|
||||
self.wait()
|
||||
|
||||
def show_sum_of_inverse_squares(self):
|
||||
lines = VGroup(*[
|
||||
Line(self.special_dot.get_center(), dot.get_center())
|
||||
for dot in self.lh_dots
|
||||
])
|
||||
labels = VGroup(*[TexMobject("d_%d" % i) for i in range(len(lines))])
|
||||
for label, line in zip(labels, lines):
|
||||
label.scale(0.75)
|
||||
vect = rotate_vector(line.get_vector(), TAU / 4)
|
||||
vect *= 2 * SMALL_BUFF / np.linalg.norm(vect)
|
||||
label.move_to(line.get_center() + vect)
|
||||
|
||||
sum_of_inverse_squares = TexMobject(*it.chain(*[
|
||||
["{1", "\\over", "(", "d_%d" % i, ")", "^2}", "+"]
|
||||
for i in range(len(lines))
|
||||
]))
|
||||
sum_of_inverse_squares.submobjects.pop(-1)
|
||||
sum_of_inverse_squares.to_edge(UP)
|
||||
d_terms = sum_of_inverse_squares.get_parts_by_tex("d_")
|
||||
d_terms.set_color(YELLOW)
|
||||
plusses = sum_of_inverse_squares.get_parts_by_tex("+")
|
||||
last_term = sum_of_inverse_squares[-6:]
|
||||
non_d_terms = VGroup(*filter(
|
||||
lambda m: m not in d_terms and m not in last_term,
|
||||
sum_of_inverse_squares
|
||||
))
|
||||
|
||||
brace = Brace(sum_of_inverse_squares, DOWN)
|
||||
brace_text = brace.get_text("Total intensity of light")
|
||||
|
||||
arrow = Vector(DOWN, color=WHITE).next_to(brace, DOWN)
|
||||
basel_sum = TexMobject(
|
||||
"{1 \\over 1^2} + ",
|
||||
"{1 \\over 2^2} + ",
|
||||
"{1 \\over 3^2} + ",
|
||||
"{1 \\over 4^2} + ",
|
||||
"\\cdots",
|
||||
)
|
||||
basel_sum.next_to(arrow, DOWN)
|
||||
basel_cross = Cross(basel_sum)
|
||||
useful_for = TextMobject("Useful for")
|
||||
useful_for.next_to(arrow, RIGHT)
|
||||
|
||||
wallis_product = TexMobject(
|
||||
"{2 \\over 1} \\cdot", "{2 \\over 3} \\cdot",
|
||||
"{4 \\over 3} \\cdot", "{4 \\over 5} \\cdot",
|
||||
"{6 \\over 5} \\cdot", "{6 \\over 7} \\cdot",
|
||||
"\\cdots"
|
||||
)
|
||||
wallis_product.move_to(basel_sum)
|
||||
|
||||
light_rings = VGroup(*it.chain(*self.lights))
|
||||
|
||||
self.play(
|
||||
LaggedStart(ShowCreation, lines),
|
||||
LaggedStart(Write, labels),
|
||||
)
|
||||
circle_group = VGroup(*self.get_top_level_mobjects())
|
||||
self.wait()
|
||||
self.play(
|
||||
ReplacementTransform(labels[-1].copy(), last_term[3]),
|
||||
Write(VGroup(*it.chain(last_term[:3], last_term[4:])))
|
||||
)
|
||||
self.remove(last_term)
|
||||
self.add(last_term)
|
||||
self.wait()
|
||||
self.play(
|
||||
Write(non_d_terms),
|
||||
ReplacementTransform(
|
||||
labels[:-1].copy(),
|
||||
d_terms[:-1],
|
||||
),
|
||||
circle_group.scale, 0.8, {"about_edge": DOWN}
|
||||
)
|
||||
self.wait()
|
||||
self.play(LaggedStart(
|
||||
ApplyMethod, light_rings,
|
||||
lambda m: (m.set_fill, {"opacity": 2 * m.get_fill_opacity()}),
|
||||
rate_func=there_and_back,
|
||||
run_time=3,
|
||||
))
|
||||
self.wait()
|
||||
|
||||
# Mention useful just to basel problem
|
||||
circle_group.save_state()
|
||||
self.play(
|
||||
circle_group.scale, 0.5,
|
||||
circle_group.to_corner, DL,
|
||||
)
|
||||
self.play(
|
||||
GrowFromCenter(brace),
|
||||
Write(brace_text)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeOut(brace_text),
|
||||
GrowArrow(arrow),
|
||||
FadeIn(useful_for),
|
||||
FadeIn(basel_sum),
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
ShowCreation(basel_cross),
|
||||
FadeOut(VGroup(arrow, useful_for, brace))
|
||||
)
|
||||
basel_group = VGroup(basel_sum, basel_cross)
|
||||
self.play(
|
||||
basel_group.scale, 0.5,
|
||||
basel_group.to_corner, DR,
|
||||
)
|
||||
self.play(Write(wallis_product))
|
||||
self.wait()
|
||||
|
||||
# Transition to distance product
|
||||
self.play(
|
||||
circle_group.restore,
|
||||
wallis_product.match_width, basel_sum,
|
||||
wallis_product.next_to, basel_sum, UP, {"aligned_edge": RIGHT},
|
||||
)
|
||||
self.play(
|
||||
d_terms.shift, d_terms.get_height() * UP / 2,
|
||||
*[
|
||||
FadeOut(mob)
|
||||
for mob in sum_of_inverse_squares
|
||||
if mob not in d_terms and mob not in plusses
|
||||
]
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeOut(plusses),
|
||||
d_terms.arrange_submobjects, RIGHT, 0.5 * SMALL_BUFF,
|
||||
d_terms.move_to, sum_of_inverse_squares, DOWN,
|
||||
)
|
||||
self.wait()
|
||||
|
||||
# Label distance product
|
||||
brace = Brace(d_terms, UP, buff=SMALL_BUFF)
|
||||
distance_product_label = brace.get_text("``Distance product''")
|
||||
|
||||
self.play(
|
||||
GrowFromCenter(brace),
|
||||
Write(distance_product_label)
|
||||
)
|
||||
line_copies = lines.copy().set_color(RED)
|
||||
self.play(LaggedStart(ShowCreationThenDestruction, line_copies))
|
||||
self.wait()
|
||||
self.play(LaggedStart(
|
||||
ApplyFunction, light_rings,
|
||||
lambda mob: (
|
||||
lambda m: m.shift(MED_SMALL_BUFF * UP).set_fill(opacity=2 * m.get_fill_opacity()),
|
||||
mob
|
||||
),
|
||||
rate_func=wiggle,
|
||||
run_time=6,
|
||||
))
|
||||
self.wait()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,6 +1,9 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from constants import FRAME_HEIGHT
|
||||
|
||||
from camera.camera import Camera
|
||||
from mobject.frame import ScreenRectangle
|
||||
|
||||
|
||||
class MovingCamera(Camera):
|
||||
|
@ -12,11 +15,14 @@ class MovingCamera(Camera):
|
|||
"aligned_dimension": "width" # or height
|
||||
}
|
||||
|
||||
def __init__(self, frame, **kwargs):
|
||||
def __init__(self, frame=None, **kwargs):
|
||||
"""
|
||||
frame is a Mobject, (should be a rectangle) determining
|
||||
which region of space the camera displys
|
||||
"""
|
||||
if frame is None:
|
||||
frame = ScreenRectangle(height=FRAME_HEIGHT)
|
||||
frame.fade(1)
|
||||
self.frame = frame
|
||||
Camera.__init__(self, **kwargs)
|
||||
|
||||
|
|
|
@ -67,6 +67,12 @@ X_AXIS = np.array((1., 0., 0.))
|
|||
Y_AXIS = np.array((0., 1., 0.))
|
||||
Z_AXIS = np.array((0., 0., 1.))
|
||||
|
||||
# Useful abbreviations for diagonals
|
||||
UL = UP + LEFT
|
||||
UR = UP + RIGHT
|
||||
DL = DOWN + LEFT
|
||||
DR = DOWN + RIGHT
|
||||
|
||||
TOP = FRAME_Y_RADIUS * UP
|
||||
BOTTOM = FRAME_Y_RADIUS * DOWN
|
||||
LEFT_SIDE = FRAME_X_RADIUS * LEFT
|
||||
|
|
|
@ -99,14 +99,15 @@ class PiCreature(SVGMobject):
|
|||
|
||||
def set_color(self, color):
|
||||
self.body.set_fill(color)
|
||||
self.color = color
|
||||
return self
|
||||
|
||||
def change_mode(self, mode):
|
||||
new_self = self.__class__(
|
||||
mode=mode,
|
||||
color=self.color
|
||||
mode = mode,
|
||||
)
|
||||
new_self.scale_to_fit_height(self.get_height())
|
||||
new_self.match_style(self)
|
||||
new_self.match_height(self)
|
||||
if self.is_flipped() ^ new_self.is_flipped():
|
||||
new_self.flip()
|
||||
new_self.shift(self.eyes.get_center() - new_self.eyes.get_center())
|
||||
|
|
|
@ -139,7 +139,7 @@ class Mobject(Container):
|
|||
self.target = self.copy()
|
||||
return self.target
|
||||
|
||||
#### Transforming operations ######
|
||||
# Transforming operations
|
||||
|
||||
def apply_to_family(self, func):
|
||||
for mob in self.family_members_with_points():
|
||||
|
@ -156,7 +156,7 @@ class Mobject(Container):
|
|||
"""
|
||||
Default behavior is to scale about the center of the mobject.
|
||||
The argument about_edge can be a vector, indicating which side of
|
||||
the mobject to scale about, e.g., mob.scale(about_edge = RIGHT)
|
||||
the mobject to scale about, e.g., mob.scale(about_edge = RIGHT)
|
||||
scales about mob.get_right().
|
||||
|
||||
Otherwise, if about_point is given a value, scaling is done with
|
||||
|
@ -249,7 +249,7 @@ class Mobject(Container):
|
|||
mob.apply_over_attr_arrays(repeat_array)
|
||||
return self
|
||||
|
||||
#### In place operations ######
|
||||
# In place operations.
|
||||
# Note, much of these are now redundant with default behavior of
|
||||
# above methods
|
||||
|
||||
|
@ -278,7 +278,7 @@ class Mobject(Container):
|
|||
self.rotate(TAU / 14, RIGHT + UP, **kwargs)
|
||||
return self
|
||||
|
||||
#### Positioning methods ####
|
||||
# Positioning methods
|
||||
|
||||
def center(self):
|
||||
self.shift(-self.get_center())
|
||||
|
@ -334,7 +334,7 @@ class Mobject(Container):
|
|||
|
||||
def align_to(self, mobject_or_point, direction=ORIGIN, alignment_vect=UP):
|
||||
"""
|
||||
Examples:
|
||||
Examples:
|
||||
mob1.align_to(mob2, UP) moves mob1 vertically so that its
|
||||
top edge lines ups with mob2's top edge.
|
||||
|
||||
|
@ -488,7 +488,7 @@ class Mobject(Container):
|
|||
def set_color(self, color=YELLOW_C, family=True):
|
||||
"""
|
||||
Condition is function which takes in one arguments, (x, y, z).
|
||||
Here it just recurses to submobjects, but in subclasses this
|
||||
Here it just recurses to submobjects, but in subclasses this
|
||||
should be further implemented based on the the inner workings
|
||||
of color
|
||||
"""
|
||||
|
@ -521,8 +521,7 @@ class Mobject(Container):
|
|||
return self
|
||||
|
||||
def set_submobject_colors_by_radial_gradient(self, center=None, radius=1, inner_color=WHITE, outer_color=BLACK):
|
||||
mobs = self.family_members_with_points()
|
||||
if center == None:
|
||||
if center is None:
|
||||
center = self.get_center()
|
||||
|
||||
for mob in self.family_members_with_points():
|
||||
|
@ -618,7 +617,7 @@ class Mobject(Container):
|
|||
def get_all_points(self):
|
||||
return self.get_merged_array("points")
|
||||
|
||||
### Getters ###
|
||||
# Getters
|
||||
|
||||
def get_points_defining_boundary(self):
|
||||
return self.points
|
||||
|
|
Loading…
Add table
Reference in a new issue