mirror of
https://github.com/3b1b/manim.git
synced 2025-08-02 02:35:22 +08:00
Refactored ShowCreation submobject management to Mobject class
This commit is contained in:
@ -4,6 +4,8 @@ import itertools as it
|
||||
from helpers import *
|
||||
|
||||
from mobject import Mobject
|
||||
from mobject.vectorized_mobject import VMobject
|
||||
from mobject.tex_mobject import DecimalNumber
|
||||
from animation import Animation
|
||||
|
||||
|
||||
@ -36,24 +38,11 @@ class ShowPartial(Animation):
|
||||
"submobject_mode" : None
|
||||
}
|
||||
def update_mobject(self, alpha):
|
||||
pairs = zip(
|
||||
self.starting_mobject.submobject_family(),
|
||||
self.mobject.submobject_family()
|
||||
self.mobject.become_partial(
|
||||
self.starting_mobject,
|
||||
*self.get_bounds(alpha),
|
||||
submobject_partial_creation_mode = self.submobject_mode
|
||||
)
|
||||
for i, (start, mob) in enumerate(pairs):
|
||||
if self.submobject_mode == "lagged_start":
|
||||
sub_alpha = 2*alpha - float(i)/len(pairs)
|
||||
sub_alpha = max(0, sub_alpha)
|
||||
sub_alpha = min(1, sub_alpha)
|
||||
elif self.submobject_mode == "one_at_a_time":
|
||||
lower = float(i)/len(pairs)
|
||||
upper = float(i+1)/len(pairs)
|
||||
sub_alpha = (alpha-lower)/(upper-lower)
|
||||
sub_alpha = max(0, sub_alpha)
|
||||
sub_alpha = min(1, sub_alpha)
|
||||
else:
|
||||
sub_alpha = alpha
|
||||
mob.become_partial(start, *self.get_bounds(sub_alpha))
|
||||
|
||||
def get_bounds(self, alpha):
|
||||
raise Exception("Not Implemented")
|
||||
@ -175,6 +164,55 @@ class MoveAlongPath(Animation):
|
||||
point = self.path.points[int(alpha*n)]
|
||||
self.mobject.shift(point-self.mobject.get_center())
|
||||
|
||||
class RangingValues(Animation):
|
||||
CONFIG = {
|
||||
"num_decimal_points" : 2,
|
||||
"rate_func" : None,
|
||||
"tracking_function" : None,
|
||||
"tracked_mobject" : None,
|
||||
"tracked_mobject_next_to_kwargs" : {},
|
||||
}
|
||||
def __init__(self, start_val, end_val, **kwargs):
|
||||
digest_config(self, kwargs, locals())
|
||||
Animation.__init__(self, self.get_mobject_at_alpha(0), **kwargs)
|
||||
|
||||
def update_mobject(self, alpha):
|
||||
pairs = zip(
|
||||
self.mobject.family_members_with_points(),
|
||||
self.get_mobject_at_alpha(alpha).family_members_with_points()
|
||||
)
|
||||
for old, new in pairs:
|
||||
##TODO, figure out a better way
|
||||
old.__dict__.update(new.__dict__)
|
||||
|
||||
def get_number(self, alpha):
|
||||
return interpolate(self.start_val, self.end_val, alpha)
|
||||
|
||||
def get_mobject_at_alpha(self, alpha):
|
||||
mob = DecimalNumber(
|
||||
self.get_number(alpha),
|
||||
num_decimal_points=self.num_decimal_points
|
||||
)
|
||||
if self.tracking_function:
|
||||
self.tracking_function(alpha, mob)
|
||||
elif self.tracked_mobject:
|
||||
mob.next_to(
|
||||
self.tracked_mobject,
|
||||
**self.tracked_mobject_next_to_kwargs
|
||||
)
|
||||
return mob
|
||||
|
||||
def set_tracking_function(self, func):
|
||||
"""
|
||||
func shoudl be of the form func(alpha, mobject), and
|
||||
should dictate where to place running number during an
|
||||
animation
|
||||
"""
|
||||
self.tracking_function = func
|
||||
|
||||
|
||||
|
||||
|
||||
### Animation modifiers ###
|
||||
|
||||
class ApplyToCenters(Animation):
|
||||
|
@ -21,7 +21,9 @@ class Mobject(object):
|
||||
"stroke_width" : DEFAULT_POINT_THICKNESS,
|
||||
"name" : None,
|
||||
"dim" : 3,
|
||||
"target" : None
|
||||
"target" : None,
|
||||
#Options are lagged_start, one_at_a_time, all_at_once
|
||||
"submobject_partial_creation_mode" : "lagged_start",
|
||||
}
|
||||
def __init__(self, *submobjects, **kwargs):
|
||||
digest_config(self, kwargs)
|
||||
@ -219,6 +221,13 @@ class Mobject(object):
|
||||
self.shift(target_point - anchor_point + buff*direction)
|
||||
return self
|
||||
|
||||
def shift_onto_screen(self):
|
||||
space_lengths = [SPACE_WIDTH, SPACE_HEIGHT]
|
||||
for vect in UP, DOWN, LEFT, RIGHT:
|
||||
dim = np.argmax(np.abs(vect))
|
||||
if abs(self.get_edge_center(vect)[dim]) > space_lengths[dim]:
|
||||
self.to_edge(vect)
|
||||
|
||||
def stretch_to_fit(self, length, dim, stretch = True):
|
||||
old_length = self.length_over_dim(dim)
|
||||
if old_length == 0:
|
||||
@ -423,12 +432,9 @@ class Mobject(object):
|
||||
self.submobject_family()
|
||||
)
|
||||
|
||||
def arrange_submobjects(self,
|
||||
direction = RIGHT,
|
||||
buff = DEFAULT_MOBJECT_TO_MOBJECT_BUFFER,
|
||||
center = True):
|
||||
def arrange_submobjects(self, direction = RIGHT, center = True, **kwargs):
|
||||
for m1, m2 in zip(self.submobjects, self.submobjects[1:]):
|
||||
m2.next_to(m1, direction, buff = buff)
|
||||
m2.next_to(m1, direction, **kwargs)
|
||||
if center:
|
||||
self.center()
|
||||
return self
|
||||
@ -533,13 +539,37 @@ class Mobject(object):
|
||||
def interpolate_color(self, mobject1, mobject2, alpha):
|
||||
raise Exception("Not implemented")
|
||||
|
||||
def become_partial(self, mobject, a, b):
|
||||
def become_partial(self, mobject, a, b, submobject_partial_creation_mode = None):
|
||||
"""
|
||||
Set points in such a way as to become only
|
||||
part of mobject.
|
||||
Inputs 0 <= a < b <= 1 determine what portion
|
||||
of mobject to become.
|
||||
"""
|
||||
self.pointwise_become_partial(mobject, a, b)
|
||||
#TODO, color
|
||||
# self.interpolate_color(self, mobject, b)
|
||||
|
||||
spcm = submobject_partial_creation_mode or self.submobject_partial_creation_mode
|
||||
pairs = zip(self.submobjects, mobject.submobjects)
|
||||
for i, (self_sub, mob_sub) in enumerate(pairs):
|
||||
if spcm == "lagged_start":
|
||||
prop = float(i)/len(pairs)
|
||||
sub_a = np.clip(2*a - prop, 0, 1)
|
||||
sub_b = np.clip(2*b - prop, 0, 1)
|
||||
elif spcm == "one_at_a_time":
|
||||
lower = float(i)/len(pairs)
|
||||
upper = float(i+1)/len(pairs)
|
||||
sub_a = np.clip((a-lower)/(upper-lower), 0, 1)
|
||||
sub_b = np.clip((b-lower)/(upper-lower), 0, 1)
|
||||
elif spcm == "all_at_once":
|
||||
sub_a, sub_b = a, b
|
||||
else:
|
||||
raise Exception("Invalid submobject partial creation mode")
|
||||
self_sub.become_partial(mob_sub, sub_a, sub_b)
|
||||
return self
|
||||
|
||||
def pointwise_become_partial(self, mobject, a, b):
|
||||
raise Exception("Not implemented")
|
||||
|
||||
|
||||
@ -557,3 +587,4 @@ class Mobject(object):
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -129,7 +129,7 @@ class PMobject(Mobject):
|
||||
mobject1.rgbs, mobject2.rgbs, alpha
|
||||
)
|
||||
|
||||
def become_partial(self, mobject, a, b):
|
||||
def pointwise_become_partial(self, mobject, a, b):
|
||||
lower_index, upper_index = [
|
||||
int(x * mobject.get_num_points())
|
||||
for x in a, b
|
||||
|
@ -7,7 +7,7 @@ TEXT_MOB_SCALE_VAL = 0.05
|
||||
|
||||
|
||||
class TexSymbol(VMobjectFromSVGPathstring):
|
||||
def become_partial(self, mobject, a, b):
|
||||
def pointwise_become_partial(self, mobject, a, b):
|
||||
#TODO, this assumes a = 0
|
||||
if b < 0.5:
|
||||
b = 2*b
|
||||
@ -17,7 +17,7 @@ class TexSymbol(VMobjectFromSVGPathstring):
|
||||
width = 2 - 2*b
|
||||
opacity = 2*b - 1
|
||||
b = 1
|
||||
VMobjectFromSVGPathstring.become_partial(
|
||||
VMobjectFromSVGPathstring.pointwise_become_partial(
|
||||
self, mobject, 0, b
|
||||
)
|
||||
self.set_stroke(width = width)
|
||||
@ -64,10 +64,7 @@ class TexMobject(SVGMobject):
|
||||
def handle_list_expression(self):
|
||||
#TODO, next_to not sufficient?
|
||||
subs = [
|
||||
# TexMobject(expr)
|
||||
self.__class__(
|
||||
expr
|
||||
)
|
||||
TexMobject(expr)
|
||||
for expr in self.expression
|
||||
]
|
||||
self.initial_scale_val = 1
|
||||
@ -110,6 +107,27 @@ class Brace(TexMobject):
|
||||
for mob in mobject, self:
|
||||
mob.rotate(angle)
|
||||
|
||||
class DecimalNumber(TexMobject):
|
||||
CONFIG = {
|
||||
"num_decimal_points" : 2,
|
||||
"digit_to_digit_buff" : 0.05
|
||||
}
|
||||
def __init__(self, float_num, **kwargs):
|
||||
digest_config(self, kwargs)
|
||||
num_string = '%.*f' % (self.num_decimal_points, float_num)
|
||||
TexMobject.__init__(self, list(num_string))
|
||||
self.arrange_submobjects(
|
||||
buff = self.digit_to_digit_buff,
|
||||
aligned_edge = DOWN
|
||||
)
|
||||
if float_num < 0:
|
||||
minus = self.submobjects[0]
|
||||
minus.next_to(
|
||||
self.submobjects[1], LEFT,
|
||||
buff = self.digit_to_digit_buff
|
||||
)
|
||||
|
||||
|
||||
def tex_hash(expression, template_tex_file):
|
||||
return str(hash(expression + template_tex_file))
|
||||
|
||||
|
@ -300,7 +300,7 @@ class VMobject(Mobject):
|
||||
# print getattr(mobject2, attr)
|
||||
setattr(self, attr, getattr(mobject2, attr))
|
||||
|
||||
def become_partial(self, mobject, a, b):
|
||||
def pointwise_become_partial(self, mobject, a, b):
|
||||
assert(isinstance(mobject, VMobject))
|
||||
#Partial curve includes three portions:
|
||||
#-A middle section, which matches the curve exactly
|
||||
|
@ -133,6 +133,7 @@ class Arrow(Line):
|
||||
"buff" : 0.3,
|
||||
"propogate_style_to_family" : False,
|
||||
"preserve_tip_size_when_scaling" : True,
|
||||
"submobject_partial_creation_mode" : "one_at_a_time",
|
||||
}
|
||||
def __init__(self, *args, **kwargs):
|
||||
if len(args) == 1:
|
||||
|
Reference in New Issue
Block a user