mirror of
https://github.com/3b1b/manim.git
synced 2025-08-05 16:49:03 +00:00
Fixed align_to
This commit is contained in:
parent
f6d6958c2d
commit
4aa63198d7
1 changed files with 124 additions and 72 deletions
|
@ -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