mirror of
https://github.com/3b1b/manim.git
synced 2025-08-05 16:49:03 +00:00
Refactored ShowCreation submobject management to Mobject class
This commit is contained in:
parent
a87b58a633
commit
b4eac6d6a9
6 changed files with 120 additions and 32 deletions
|
@ -4,6 +4,8 @@ import itertools as it
|
||||||
from helpers import *
|
from helpers import *
|
||||||
|
|
||||||
from mobject import Mobject
|
from mobject import Mobject
|
||||||
|
from mobject.vectorized_mobject import VMobject
|
||||||
|
from mobject.tex_mobject import DecimalNumber
|
||||||
from animation import Animation
|
from animation import Animation
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,24 +38,11 @@ class ShowPartial(Animation):
|
||||||
"submobject_mode" : None
|
"submobject_mode" : None
|
||||||
}
|
}
|
||||||
def update_mobject(self, alpha):
|
def update_mobject(self, alpha):
|
||||||
pairs = zip(
|
self.mobject.become_partial(
|
||||||
self.starting_mobject.submobject_family(),
|
self.starting_mobject,
|
||||||
self.mobject.submobject_family()
|
*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):
|
def get_bounds(self, alpha):
|
||||||
raise Exception("Not Implemented")
|
raise Exception("Not Implemented")
|
||||||
|
@ -175,6 +164,55 @@ class MoveAlongPath(Animation):
|
||||||
point = self.path.points[int(alpha*n)]
|
point = self.path.points[int(alpha*n)]
|
||||||
self.mobject.shift(point-self.mobject.get_center())
|
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 ###
|
### Animation modifiers ###
|
||||||
|
|
||||||
class ApplyToCenters(Animation):
|
class ApplyToCenters(Animation):
|
||||||
|
|
|
@ -21,7 +21,9 @@ class Mobject(object):
|
||||||
"stroke_width" : DEFAULT_POINT_THICKNESS,
|
"stroke_width" : DEFAULT_POINT_THICKNESS,
|
||||||
"name" : None,
|
"name" : None,
|
||||||
"dim" : 3,
|
"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):
|
def __init__(self, *submobjects, **kwargs):
|
||||||
digest_config(self, kwargs)
|
digest_config(self, kwargs)
|
||||||
|
@ -219,6 +221,13 @@ class Mobject(object):
|
||||||
self.shift(target_point - anchor_point + buff*direction)
|
self.shift(target_point - anchor_point + buff*direction)
|
||||||
return self
|
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):
|
def stretch_to_fit(self, length, dim, stretch = True):
|
||||||
old_length = self.length_over_dim(dim)
|
old_length = self.length_over_dim(dim)
|
||||||
if old_length == 0:
|
if old_length == 0:
|
||||||
|
@ -423,12 +432,9 @@ class Mobject(object):
|
||||||
self.submobject_family()
|
self.submobject_family()
|
||||||
)
|
)
|
||||||
|
|
||||||
def arrange_submobjects(self,
|
def arrange_submobjects(self, direction = RIGHT, center = True, **kwargs):
|
||||||
direction = RIGHT,
|
|
||||||
buff = DEFAULT_MOBJECT_TO_MOBJECT_BUFFER,
|
|
||||||
center = True):
|
|
||||||
for m1, m2 in zip(self.submobjects, self.submobjects[1:]):
|
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:
|
if center:
|
||||||
self.center()
|
self.center()
|
||||||
return self
|
return self
|
||||||
|
@ -533,13 +539,37 @@ class Mobject(object):
|
||||||
def interpolate_color(self, mobject1, mobject2, alpha):
|
def interpolate_color(self, mobject1, mobject2, alpha):
|
||||||
raise Exception("Not implemented")
|
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
|
Set points in such a way as to become only
|
||||||
part of mobject.
|
part of mobject.
|
||||||
Inputs 0 <= a < b <= 1 determine what portion
|
Inputs 0 <= a < b <= 1 determine what portion
|
||||||
of mobject to become.
|
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")
|
raise Exception("Not implemented")
|
||||||
|
|
||||||
|
|
||||||
|
@ -557,3 +587,4 @@ class Mobject(object):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -129,7 +129,7 @@ class PMobject(Mobject):
|
||||||
mobject1.rgbs, mobject2.rgbs, alpha
|
mobject1.rgbs, mobject2.rgbs, alpha
|
||||||
)
|
)
|
||||||
|
|
||||||
def become_partial(self, mobject, a, b):
|
def pointwise_become_partial(self, mobject, a, b):
|
||||||
lower_index, upper_index = [
|
lower_index, upper_index = [
|
||||||
int(x * mobject.get_num_points())
|
int(x * mobject.get_num_points())
|
||||||
for x in a, b
|
for x in a, b
|
||||||
|
|
|
@ -7,7 +7,7 @@ TEXT_MOB_SCALE_VAL = 0.05
|
||||||
|
|
||||||
|
|
||||||
class TexSymbol(VMobjectFromSVGPathstring):
|
class TexSymbol(VMobjectFromSVGPathstring):
|
||||||
def become_partial(self, mobject, a, b):
|
def pointwise_become_partial(self, mobject, a, b):
|
||||||
#TODO, this assumes a = 0
|
#TODO, this assumes a = 0
|
||||||
if b < 0.5:
|
if b < 0.5:
|
||||||
b = 2*b
|
b = 2*b
|
||||||
|
@ -17,7 +17,7 @@ class TexSymbol(VMobjectFromSVGPathstring):
|
||||||
width = 2 - 2*b
|
width = 2 - 2*b
|
||||||
opacity = 2*b - 1
|
opacity = 2*b - 1
|
||||||
b = 1
|
b = 1
|
||||||
VMobjectFromSVGPathstring.become_partial(
|
VMobjectFromSVGPathstring.pointwise_become_partial(
|
||||||
self, mobject, 0, b
|
self, mobject, 0, b
|
||||||
)
|
)
|
||||||
self.set_stroke(width = width)
|
self.set_stroke(width = width)
|
||||||
|
@ -64,10 +64,7 @@ class TexMobject(SVGMobject):
|
||||||
def handle_list_expression(self):
|
def handle_list_expression(self):
|
||||||
#TODO, next_to not sufficient?
|
#TODO, next_to not sufficient?
|
||||||
subs = [
|
subs = [
|
||||||
# TexMobject(expr)
|
TexMobject(expr)
|
||||||
self.__class__(
|
|
||||||
expr
|
|
||||||
)
|
|
||||||
for expr in self.expression
|
for expr in self.expression
|
||||||
]
|
]
|
||||||
self.initial_scale_val = 1
|
self.initial_scale_val = 1
|
||||||
|
@ -109,6 +106,27 @@ class Brace(TexMobject):
|
||||||
self.shift(left - self.get_corner(UP+LEFT) + self.buff*DOWN)
|
self.shift(left - self.get_corner(UP+LEFT) + self.buff*DOWN)
|
||||||
for mob in mobject, self:
|
for mob in mobject, self:
|
||||||
mob.rotate(angle)
|
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):
|
def tex_hash(expression, template_tex_file):
|
||||||
return str(hash(expression + template_tex_file))
|
return str(hash(expression + template_tex_file))
|
||||||
|
|
|
@ -300,7 +300,7 @@ class VMobject(Mobject):
|
||||||
# print getattr(mobject2, attr)
|
# print getattr(mobject2, attr)
|
||||||
setattr(self, attr, 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))
|
assert(isinstance(mobject, VMobject))
|
||||||
#Partial curve includes three portions:
|
#Partial curve includes three portions:
|
||||||
#-A middle section, which matches the curve exactly
|
#-A middle section, which matches the curve exactly
|
||||||
|
|
|
@ -133,6 +133,7 @@ class Arrow(Line):
|
||||||
"buff" : 0.3,
|
"buff" : 0.3,
|
||||||
"propogate_style_to_family" : False,
|
"propogate_style_to_family" : False,
|
||||||
"preserve_tip_size_when_scaling" : True,
|
"preserve_tip_size_when_scaling" : True,
|
||||||
|
"submobject_partial_creation_mode" : "one_at_a_time",
|
||||||
}
|
}
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
if len(args) == 1:
|
if len(args) == 1:
|
||||||
|
|
Loading…
Add table
Reference in a new issue