mirror of
https://github.com/3b1b/manim.git
synced 2025-09-01 00:48:45 +00:00
commit
3a88827cc7
4 changed files with 131 additions and 76 deletions
|
@ -31,7 +31,7 @@ class OpeningManimExample(Scene):
|
||||||
transform_title.to_corner(UP + LEFT)
|
transform_title.to_corner(UP + LEFT)
|
||||||
self.play(
|
self.play(
|
||||||
Transform(title, transform_title),
|
Transform(title, transform_title),
|
||||||
OldLaggedStart(FadeOutAndShiftDown, basel),
|
LaggedStart(*map(FadeOutAndShiftDown, basel)),
|
||||||
)
|
)
|
||||||
self.wait()
|
self.wait()
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ class OpeningManimExample(Scene):
|
||||||
self.play(
|
self.play(
|
||||||
FadeOut(title),
|
FadeOut(title),
|
||||||
FadeInFromDown(grid_title),
|
FadeInFromDown(grid_title),
|
||||||
Write(grid),
|
ShowCreation(grid, run_time=3, lag_ratio=0.1),
|
||||||
)
|
)
|
||||||
self.wait()
|
self.wait()
|
||||||
|
|
||||||
|
|
|
@ -149,6 +149,11 @@ class OldLaggedStart(Animation):
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, AnimationClass, mobject, arg_creator=None, **kwargs):
|
def __init__(self, AnimationClass, mobject, arg_creator=None, **kwargs):
|
||||||
|
print(
|
||||||
|
"Warning, this scene is using the animation "
|
||||||
|
"OldLaggedStart, which is now deprecated. Use "
|
||||||
|
"LaggedStart instead."
|
||||||
|
)
|
||||||
for key in ["rate_func", "run_time"]:
|
for key in ["rate_func", "run_time"]:
|
||||||
if key in AnimationClass.CONFIG:
|
if key in AnimationClass.CONFIG:
|
||||||
setattr(self, key, AnimationClass.CONFIG[key])
|
setattr(self, key, AnimationClass.CONFIG[key])
|
||||||
|
|
|
@ -287,7 +287,6 @@ class NumberPlane(Axes):
|
||||||
|
|
||||||
def get_lines_parallel_to_axis(self, axis1, axis2, freq, ratio):
|
def get_lines_parallel_to_axis(self, axis1, axis2, freq, ratio):
|
||||||
line = Line(axis1.get_start(), axis1.get_end())
|
line = Line(axis1.get_start(), axis1.get_end())
|
||||||
vect = line.get_vector()
|
|
||||||
dense_freq = (1 + ratio)
|
dense_freq = (1 + ratio)
|
||||||
step = 1 / dense_freq
|
step = 1 / dense_freq
|
||||||
|
|
||||||
|
@ -301,7 +300,6 @@ class NumberPlane(Axes):
|
||||||
for k, x in enumerate(inputs):
|
for k, x in enumerate(inputs):
|
||||||
new_line = line.copy()
|
new_line = line.copy()
|
||||||
new_line.move_to(axis2.number_to_point(x))
|
new_line.move_to(axis2.number_to_point(x))
|
||||||
new_line.align_to(line, vect)
|
|
||||||
if k % (1 + ratio) == 0:
|
if k % (1 + ratio) == 0:
|
||||||
lines1.add(new_line)
|
lines1.add(new_line)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -411,31 +411,6 @@ class Mobject(Container):
|
||||||
buff * direction) * coor_mask)
|
buff * direction) * coor_mask)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def align_to(self, mobject_or_point, direction=ORIGIN, alignment_vect=UP):
|
|
||||||
"""
|
|
||||||
Examples:
|
|
||||||
mob1.align_to(mob2, UP) moves mob1 vertically so that its
|
|
||||||
top edge lines ups with mob2's top edge.
|
|
||||||
|
|
||||||
mob1.align_to(mob2, alignment_vect = RIGHT) moves mob1
|
|
||||||
horizontally so that it's center is directly above/below
|
|
||||||
the center of mob2
|
|
||||||
"""
|
|
||||||
if isinstance(mobject_or_point, Mobject):
|
|
||||||
mob = mobject_or_point
|
|
||||||
target_point = mob.get_critical_point(direction)
|
|
||||||
else:
|
|
||||||
target_point = mobject_or_point
|
|
||||||
direction_norm = get_norm(direction)
|
|
||||||
if direction_norm > 0:
|
|
||||||
alignment_vect = np.array(direction) / direction_norm
|
|
||||||
reference_point = self.get_critical_point(direction)
|
|
||||||
else:
|
|
||||||
reference_point = self.get_center()
|
|
||||||
diff = target_point - reference_point
|
|
||||||
self.shift(alignment_vect * np.dot(diff, alignment_vect))
|
|
||||||
return self
|
|
||||||
|
|
||||||
def shift_onto_screen(self, **kwargs):
|
def shift_onto_screen(self, **kwargs):
|
||||||
space_lengths = [FRAME_X_RADIUS, FRAME_Y_RADIUS]
|
space_lengths = [FRAME_X_RADIUS, FRAME_Y_RADIUS]
|
||||||
for vect in UP, DOWN, LEFT, RIGHT:
|
for vect in UP, DOWN, LEFT, RIGHT:
|
||||||
|
@ -493,6 +468,22 @@ class Mobject(Container):
|
||||||
def set_depth(self, depth, stretch=False, **kwargs):
|
def set_depth(self, depth, stretch=False, **kwargs):
|
||||||
return self.rescale_to_fit(depth, 2, stretch=stretch, **kwargs)
|
return self.rescale_to_fit(depth, 2, stretch=stretch, **kwargs)
|
||||||
|
|
||||||
|
def set_coord(self, value, dim, direction=ORIGIN):
|
||||||
|
curr = self.get_coord(dim, direction)
|
||||||
|
shift_vect = np.zeros(self.dim)
|
||||||
|
shift_vect[dim] = value - curr
|
||||||
|
self.shift(shift_vect)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def set_x(self, x, direction=ORIGIN):
|
||||||
|
return self.set_coord(x, 0, direction)
|
||||||
|
|
||||||
|
def set_y(self, y, direction=ORIGIN):
|
||||||
|
return self.set_coord(y, 1, direction)
|
||||||
|
|
||||||
|
def set_z(self, z, direction=ORIGIN):
|
||||||
|
return self.set_coord(z, 2, direction)
|
||||||
|
|
||||||
def space_out_submobjects(self, factor=1.5, **kwargs):
|
def space_out_submobjects(self, factor=1.5, **kwargs):
|
||||||
self.scale(factor, **kwargs)
|
self.scale(factor, **kwargs)
|
||||||
for submob in self.submobjects:
|
for submob in self.submobjects:
|
||||||
|
@ -534,17 +525,6 @@ class Mobject(Container):
|
||||||
self.scale_in_place((length + buff) / length)
|
self.scale_in_place((length + buff) / length)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def get_start(self):
|
|
||||||
self.throw_error_if_no_points()
|
|
||||||
return np.array(self.points[0])
|
|
||||||
|
|
||||||
def get_end(self):
|
|
||||||
self.throw_error_if_no_points()
|
|
||||||
return np.array(self.points[-1])
|
|
||||||
|
|
||||||
def get_start_and_end(self):
|
|
||||||
return self.get_start(), self.get_end()
|
|
||||||
|
|
||||||
def put_start_and_end_on(self, start, end):
|
def put_start_and_end_on(self, start, end):
|
||||||
curr_start, curr_end = self.get_start_and_end()
|
curr_start, curr_end = self.get_start_and_end()
|
||||||
curr_vect = curr_end - curr_start
|
curr_vect = curr_end - curr_start
|
||||||
|
@ -586,26 +566,6 @@ class Mobject(Container):
|
||||||
mob.add_background_rectangle(**kwargs)
|
mob.add_background_rectangle(**kwargs)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
# Match other mobject properties
|
|
||||||
|
|
||||||
def match_color(self, mobject):
|
|
||||||
return self.set_color(mobject.get_color())
|
|
||||||
|
|
||||||
def match_dim(self, mobject, dim, **kwargs):
|
|
||||||
return self.rescale_to_fit(
|
|
||||||
mobject.length_over_dim(dim), dim,
|
|
||||||
**kwargs
|
|
||||||
)
|
|
||||||
|
|
||||||
def match_width(self, mobject, **kwargs):
|
|
||||||
return self.match_dim(mobject, 0, **kwargs)
|
|
||||||
|
|
||||||
def match_height(self, mobject, **kwargs):
|
|
||||||
return self.match_dim(mobject, 1, **kwargs)
|
|
||||||
|
|
||||||
def match_depth(self, mobject, **kwargs):
|
|
||||||
return self.match_dim(mobject, 2, **kwargs)
|
|
||||||
|
|
||||||
# Color functions
|
# Color functions
|
||||||
|
|
||||||
def set_color(self, color=YELLOW_C, family=True):
|
def set_color(self, color=YELLOW_C, family=True):
|
||||||
|
@ -735,23 +695,31 @@ class Mobject(Container):
|
||||||
def get_num_points(self):
|
def get_num_points(self):
|
||||||
return len(self.points)
|
return len(self.points)
|
||||||
|
|
||||||
|
def get_extremum_along_dim(self, points=None, dim=0, key=0):
|
||||||
|
if points is None:
|
||||||
|
points = self.get_points_defining_boundary()
|
||||||
|
values = points[:, dim]
|
||||||
|
if key < 0:
|
||||||
|
return np.min(values)
|
||||||
|
elif key == 0:
|
||||||
|
return (np.min(values) + np.max(values)) / 2
|
||||||
|
else:
|
||||||
|
return np.max(values)
|
||||||
|
|
||||||
def get_critical_point(self, direction):
|
def get_critical_point(self, direction):
|
||||||
|
"""
|
||||||
|
Picture a box bounding the mobject. Such a box has
|
||||||
|
9 'critical points': 4 corners, 4 edge center, the
|
||||||
|
center. This returns one of them.
|
||||||
|
"""
|
||||||
result = np.zeros(self.dim)
|
result = np.zeros(self.dim)
|
||||||
all_points = self.get_points_defining_boundary()
|
all_points = self.get_points_defining_boundary()
|
||||||
if len(all_points) == 0:
|
if len(all_points) == 0:
|
||||||
return result
|
return result
|
||||||
for dim in range(self.dim):
|
for dim in range(self.dim):
|
||||||
if direction[dim] <= 0:
|
result[dim] = self.get_extremum_along_dim(
|
||||||
min_val = min(all_points[:, dim])
|
all_points, dim=dim, key=direction[dim]
|
||||||
if direction[dim] >= 0:
|
)
|
||||||
max_val = max(all_points[:, dim])
|
|
||||||
|
|
||||||
if direction[dim] == 0:
|
|
||||||
result[dim] = (max_val + min_val) / 2
|
|
||||||
elif direction[dim] < 0:
|
|
||||||
result[dim] = min_val
|
|
||||||
else:
|
|
||||||
result[dim] = max_val
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
# Pseudonyms for more general get_critical_point method
|
# Pseudonyms for more general get_critical_point method
|
||||||
|
@ -773,11 +741,6 @@ class Mobject(Container):
|
||||||
index = np.argmax(np.dot(all_points, np.array(direction).T))
|
index = np.argmax(np.dot(all_points, np.array(direction).T))
|
||||||
return all_points[index]
|
return all_points[index]
|
||||||
|
|
||||||
def get_z_index_reference_point(self):
|
|
||||||
# TODO, better place to define default z_index_group?
|
|
||||||
z_index_group = getattr(self, "z_index_group", self)
|
|
||||||
return z_index_group.get_center()
|
|
||||||
|
|
||||||
def get_top(self):
|
def get_top(self):
|
||||||
return self.get_edge_center(UP)
|
return self.get_edge_center(UP)
|
||||||
|
|
||||||
|
@ -811,6 +774,34 @@ class Mobject(Container):
|
||||||
def get_depth(self):
|
def get_depth(self):
|
||||||
return self.length_over_dim(2)
|
return self.length_over_dim(2)
|
||||||
|
|
||||||
|
def get_coord(self, dim, direction=ORIGIN):
|
||||||
|
"""
|
||||||
|
Meant to generalize get_x, get_y, get_z
|
||||||
|
"""
|
||||||
|
return self.get_extremum_along_dim(
|
||||||
|
dim=dim, key=direction[dim]
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_x(self, direction=ORIGIN):
|
||||||
|
return self.get_coord(0, direction)
|
||||||
|
|
||||||
|
def get_y(self, direction=ORIGIN):
|
||||||
|
return self.get_coord(1, direction)
|
||||||
|
|
||||||
|
def get_z(self, direction=ORIGIN):
|
||||||
|
return self.get_coord(2, direction)
|
||||||
|
|
||||||
|
def get_start(self):
|
||||||
|
self.throw_error_if_no_points()
|
||||||
|
return np.array(self.points[0])
|
||||||
|
|
||||||
|
def get_end(self):
|
||||||
|
self.throw_error_if_no_points()
|
||||||
|
return np.array(self.points[-1])
|
||||||
|
|
||||||
|
def get_start_and_end(self):
|
||||||
|
return self.get_start(), self.get_end()
|
||||||
|
|
||||||
def point_from_proportion(self, alpha):
|
def point_from_proportion(self, alpha):
|
||||||
raise Exception("Not implemented")
|
raise Exception("Not implemented")
|
||||||
|
|
||||||
|
@ -825,12 +816,73 @@ class Mobject(Container):
|
||||||
for a1, a2 in zip(alphas[:-1], alphas[1:])
|
for a1, a2 in zip(alphas[:-1], alphas[1:])
|
||||||
])
|
])
|
||||||
|
|
||||||
|
def get_z_index_reference_point(self):
|
||||||
|
# TODO, better place to define default z_index_group?
|
||||||
|
z_index_group = getattr(self, "z_index_group", self)
|
||||||
|
return z_index_group.get_center()
|
||||||
|
|
||||||
def has_points(self):
|
def has_points(self):
|
||||||
return len(self.points) > 0
|
return len(self.points) > 0
|
||||||
|
|
||||||
def has_no_points(self):
|
def has_no_points(self):
|
||||||
return not self.has_points()
|
return not self.has_points()
|
||||||
|
|
||||||
|
# Match other mobject properties
|
||||||
|
|
||||||
|
def match_color(self, mobject):
|
||||||
|
return self.set_color(mobject.get_color())
|
||||||
|
|
||||||
|
def match_dim_size(self, mobject, dim, **kwargs):
|
||||||
|
return self.rescale_to_fit(
|
||||||
|
mobject.length_over_dim(dim), dim,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
def match_width(self, mobject, **kwargs):
|
||||||
|
return self.match_dim_size(mobject, 0, **kwargs)
|
||||||
|
|
||||||
|
def match_height(self, mobject, **kwargs):
|
||||||
|
return self.match_dim_size(mobject, 1, **kwargs)
|
||||||
|
|
||||||
|
def match_depth(self, mobject, **kwargs):
|
||||||
|
return self.match_dim_size(mobject, 2, **kwargs)
|
||||||
|
|
||||||
|
def match_coord(self, mobject, dim, direction=ORIGIN):
|
||||||
|
return self.set_coord(
|
||||||
|
mobject.get_coord(dim, direction),
|
||||||
|
dim=dim,
|
||||||
|
direction=direction,
|
||||||
|
)
|
||||||
|
|
||||||
|
def match_x(self, mobject, direction=ORIGIN):
|
||||||
|
return self.match_coord(mobject, 0, direction)
|
||||||
|
|
||||||
|
def match_y(self, mobject, direction=ORIGIN):
|
||||||
|
return self.match_coord(mobject, 1, direction)
|
||||||
|
|
||||||
|
def match_z(self, mobject, direction=ORIGIN):
|
||||||
|
return self.match_coord(mobject, 2, direction)
|
||||||
|
|
||||||
|
def align_to(self, mobject_or_point, direction=ORIGIN, alignment_vect=UP):
|
||||||
|
"""
|
||||||
|
Examples:
|
||||||
|
mob1.align_to(mob2, UP) moves mob1 vertically so that its
|
||||||
|
top edge lines ups with mob2's top edge.
|
||||||
|
|
||||||
|
mob1.align_to(mob2, alignment_vect = RIGHT) moves mob1
|
||||||
|
horizontally so that it's center is directly above/below
|
||||||
|
the center of mob2
|
||||||
|
"""
|
||||||
|
if isinstance(mobject_or_point, Mobject):
|
||||||
|
point = mobject_or_point.get_critical_point(direction)
|
||||||
|
else:
|
||||||
|
point = mobject_or_point
|
||||||
|
|
||||||
|
for dim in range(self.dim):
|
||||||
|
if direction[dim] != 0:
|
||||||
|
self.set_coord(point[dim], dim, direction)
|
||||||
|
return self
|
||||||
|
|
||||||
# Family matters
|
# Family matters
|
||||||
|
|
||||||
def __getitem__(self, value):
|
def __getitem__(self, value):
|
||||||
|
|
Loading…
Add table
Reference in a new issue