This commit is contained in:
Sridhar Ramesh 2018-01-17 23:17:53 -08:00
commit 24a39c7e03
11 changed files with 124 additions and 103 deletions

View file

@ -84,15 +84,38 @@ class Camera(object):
def reset(self):
self.set_pixel_array(np.array(self.background))
####
def extract_mobject_family_members(self, mobjects, only_those_with_points = False):
if only_those_with_points:
method = Mobject.family_members_with_points
else:
method = Mobject.submobject_family
return remove_list_redundancies(list(
it.chain(*[
method(m)
for m in mobjects
if not (isinstance(m, VMobject) and m.is_subpath)
])
))
def capture_mobject(self, mobject):
return self.capture_mobjects([mobject])
def capture_mobjects(self, mobjects, include_submobjects = True):
def capture_mobjects(
self, mobjects,
include_submobjects = True,
excluded_mobjects = None,
):
if include_submobjects:
mobjects = it.chain(*[
mob.family_members_with_points()
for mob in mobjects
])
mobjects = self.extract_mobject_family_members(
mobjects, only_those_with_points = True
)
if excluded_mobjects:
all_excluded = self.extract_mobject_family_members(
excluded_mobjects
)
mobjects = list_difference_update(mobjects, all_excluded)
vmobjects = []
for mobject in mobjects:
if isinstance(mobject, VMobject):

View file

@ -43,7 +43,7 @@ DEFAULT_MOBJECT_TO_MOBJECT_BUFFER = MED_SMALL_BUFF
#All in seconds
DEFAULT_ANIMATION_RUN_TIME = 1.0
DEFAULT_POINTWISE_FUNCTION_RUN_TIME = 3.0
DEFAULT_wait_TIME = 1.0
DEFAULT_WAIT_TIME = 1.0
ORIGIN = np.array(( 0., 0., 0.))

View file

@ -454,7 +454,6 @@ class Mobject(object):
return self
def submobject_radial_gradient_highlight(self, center = None, radius = 1, inner_color = WHITE, outer_color = BLACK):
mobs = self.family_members_with_points()
if center == None:
center = self.get_center()
@ -462,14 +461,11 @@ class Mobject(object):
for mob in self.family_members_with_points():
t = np.linalg.norm(mob.get_center() - center)/radius
t = min(t,1)
print t
mob_color = interpolate_color(inner_color, outer_color, t)
print mob_color
mob.highlight(mob_color, family = False)
return self
def set_color(self, color):
self.highlight(color)
self.color = Color(color)

View file

@ -14,8 +14,9 @@ class VMobject(Mobject):
"is_subpath" : False,
"close_new_points" : False,
"mark_paths_closed" : False,
"considered_smooth" : True,
"propagate_style_to_family" : False,
"pre_function_handle_to_anchor_scale_factor" : 0.01,
"make_smooth_after_applying_functions" : False,
}
## Colors
@ -191,7 +192,6 @@ class VMobject(Mobject):
return self
def make_smooth(self):
self.considered_smooth = True
return self.change_anchor_mode("smooth")
def make_jagged(self):
@ -232,12 +232,35 @@ class VMobject(Mobject):
self.submobjects
)
def apply_function(self, function, maintain_smoothness = False):
def apply_function(self, function):
factor = self.pre_function_handle_to_anchor_scale_factor
self.scale_handle_to_anchor_distances(factor)
Mobject.apply_function(self, function)
if maintain_smoothness and self.considered_smooth:
self.scale_handle_to_anchor_distances(1./factor)
if self.make_smooth_after_applying_functions:
self.make_smooth()
return self
def scale_handle_to_anchor_distances(self, factor):
"""
If the distance between a given handle point H and its associated
anchor point A is d, then it changes H to be a distances factor*d
away from A, but so that the line from A to H doesn't change.
This is mostly useful in the context of applying a (differentiable)
function, to preserve tangency properties. One would pull all the
handles closer to their anchors, apply the function then push them out
again.
"""
if self.get_num_points() == 0:
return
anchors, handles1, handles2 = self.get_anchors_and_handles()
# print len(anchors), len(handles1), len(handles2)
a_to_h1 = handles1 - anchors[:-1]
a_to_h2 = handles2 - anchors[1:]
handles1 = anchors[:-1] + factor*a_to_h1
handles2 = anchors[1:] + factor*a_to_h2
self.set_anchors_and_handles(anchors, handles1, handles2)
## Information about line
@ -272,7 +295,6 @@ class VMobject(Mobject):
## Alignment
def align_points(self, mobject):
Mobject.align_points(self, mobject)
is_subpath = self.is_subpath or mobject.is_subpath

View file

@ -123,19 +123,23 @@ class Scene(object):
def capture_mobjects_in_camera(self, mobjects, **kwargs):
self.camera.capture_mobjects(mobjects, **kwargs)
def update_frame(self, mobjects = None, background = None, **kwargs):
if "include_submobjects" not in kwargs:
kwargs["include_submobjects"] = False
def update_frame(
self,
mobjects = None,
background = None,
include_submobjects = True,
**kwargs):
if mobjects is None:
mobjects = list_update(
self.foreground_mobjects,
self.mobjects,
self.foreground_mobjects,
)
if background is not None:
self.set_camera_pixel_array(background)
else:
self.reset_camera()
kwargs["include_submobjects"] = include_submobjects
self.capture_mobjects_in_camera(mobjects, **kwargs)
def freeze_background(self):
@ -167,15 +171,6 @@ class Scene(object):
###
def extract_mobject_family_members(self, *mobjects):
return remove_list_redundancies(list(
it.chain(*[
m.submobject_family()
for m in mobjects
if not (isinstance(m, VMobject) and m.is_subpath)
])
))
def get_top_level_mobjects(self):
# Return only those which are not in the family
# of another mobject from the scene
@ -209,14 +204,10 @@ class Scene(object):
"""
Mobjects will be displayed, from background to foreground,
in the order with which they are entered.
Scene class keeps track not just of the mobject directly added,
but also of every family member therein.
"""
mobjects, continual_animations = self.separate_mobjects_and_continual_animations(
mobjects_or_continual_animations
)
mobjects = self.extract_mobject_family_members(*mobjects)
self.mobjects = list_update(self.mobjects, mobjects)
self.continual_animations = list_update(
self.continual_animations, continual_animations
@ -236,31 +227,38 @@ class Scene(object):
mobjects, continual_animations = self.separate_mobjects_and_continual_animations(
mobjects_or_continual_animations
)
mobjects = self.extract_mobject_family_members(*mobjects)
self.mobjects = filter(
lambda m : m not in mobjects,
self.mobjects
)
self.remove_mobjects_not_completely_on_screen()
self.remove_foreground_mobjects(*mobjects)
to_remove = self.camera.extract_mobject_family_members(mobjects)
self.mobjects = self.get_restructured_mobject_list(self.mobjects, to_remove)
self.foreground_mobjects = self.get_restructured_mobject_list(
self.foreground_mobjects, to_remove
)
self.continual_animations = filter(
lambda ca : ca not in continual_animations and \
ca.mobject not in mobjects,
ca.mobject not in to_remove,
self.continual_animations
)
return self
def remove_mobjects_not_completely_on_screen(self):
def should_keep(mobject):
return all([
submob in self.mobjects
for submob in mobject.family_members_with_points()
])
self.mobjects = filter(should_keep, self.mobjects)
return self
def get_restructured_mobject_list(self, mobjects, to_remove):
"""
In cases where the scene contains a group, e.g. Group(m1, m2, m3), but one
of its submobjects is removed, e.g. scene.remove(m1), the list of mobjects
will be editing to contain other submobjects, but not m1, e.g. it will now
insert m2 and m3 to where the group once was.
"""
new_mobjects = []
def add_safe_mobjects_from_list(list_to_examine, set_to_remove):
for mob in list_to_examine:
if mob in set_to_remove:
continue
intersect = set_to_remove.intersection(mob.submobject_family())
if intersect:
add_safe_mobjects_from_list(mob.submobjects, intersect)
else:
new_mobjects.append(mob)
add_safe_mobjects_from_list(mobjects, set(to_remove))
return new_mobjects
def add_foreground_mobjects(self, *mobjects):
self.foreground_mobjects = list_update(
@ -274,9 +272,9 @@ class Scene(object):
return self.add_foreground_mobjects(mobject)
def remove_foreground_mobjects(self, *mobjects):
self.foreground_mobjects = filter(
lambda m : m not in mobjects,
self.foreground_mobjects
self.foreground_mobjects = get_restructured_mobject_list(
self.foreground_mobjects,
self.camera.extract_mobject_family_members(mobjects)
)
return self
@ -289,7 +287,7 @@ class Scene(object):
def bring_to_back(self, *mobjects):
self.remove(*mobjects)
self.mobjects = mobjects + self.mobjects
self.mobjects = list(mobjects) + self.mobjects
return self
def clear(self):
@ -304,17 +302,13 @@ class Scene(object):
def get_mobject_copies(self):
return [m.copy() for m in self.mobjects]
def separate_moving_and_static_mobjects(self, *animations):
moving_mobjects = self.extract_mobject_family_members(*it.chain(
def get_moving_mobjects(self, *animations):
moving_mobjects = list(it.chain(
[anim.mobject for anim in animations],
[ca.mobject for ca in self.continual_animations],
self.foreground_mobjects,
))
static_mobjects = filter(
lambda m : m not in moving_mobjects,
self.mobjects
)
return moving_mobjects, static_mobjects
return moving_mobjects
def get_time_progression(self, run_time):
times = np.arange(0, run_time, self.frame_duration)
@ -395,9 +389,8 @@ class Scene(object):
self.num_plays += 1
sync_animation_run_times_and_rate_funcs(*animations, **kwargs)
moving_mobjects, static_mobjects = \
self.separate_moving_and_static_mobjects(*animations)
self.update_frame(static_mobjects)
moving_mobjects = self.get_moving_mobjects(*animations)
self.update_frame(excluded_mobjects = moving_mobjects)
static_image = self.get_frame()
for t in self.get_animation_time_progression(animations):
for animation in animations:
@ -422,7 +415,7 @@ class Scene(object):
return self.mobjects_from_last_animation
return []
def wait(self, duration = DEFAULT_wait_TIME):
def wait(self, duration = DEFAULT_WAIT_TIME):
if self.skip_animations:
return self
@ -527,3 +520,7 @@ class Scene(object):
shutil.move(*self.args_to_rename_file)
else:
os.rename(*self.args_to_rename_file)

View file

@ -122,15 +122,13 @@ class ZoomedScene(Scene):
self.zoomed_camera.capture_mobjects(
mobjects, **kwargs
)
def separate_moving_and_static_mobjects(self, *animations):
moving_mobjects, static_mobjects = Scene.separate_moving_and_static_mobjects(
self, *animations
)
def get_moving_mobjects(self, *animations):
moving_mobjects = Scene.get_moving_mobjects(self, *animations)
if self.zoom_activated and self.little_rectangle in moving_mobjects:
# When the camera is moving, so is everything,
return self.get_mobjects(), []
return self.mobjects
else:
return moving_mobjects, static_mobjects
return moving_mobjects

View file

@ -114,7 +114,6 @@ class Sector(VMobject):
class Line(VMobject):
CONFIG = {
"buff" : 0,
"considered_smooth" : False,
"path_arc" : None,
"n_arc_anchors" : 10, #Only used if path_arc is not None
}
@ -132,7 +131,6 @@ class Line(VMobject):
path_func(self.start, self.end, alpha)
for alpha in np.linspace(0, 1, self.n_arc_anchors)
])
self.considered_smooth = True
self.account_for_buff()
def account_for_buff(self):
@ -449,7 +447,6 @@ class Polygon(VMobject):
"color" : GREEN_D,
"mark_paths_closed" : True,
"close_new_points" : True,
"considered_smooth" : False,
}
def __init__(self, *vertices, **kwargs):
assert len(vertices) > 1
@ -479,7 +476,6 @@ class Rectangle(VMobject):
"width" : 4.0,
"mark_paths_closed" : True,
"close_new_points" : True,
"considered_smooth" : False,
}
def generate_points(self):
y, x = self.height/2., self.width/2.
@ -586,7 +582,6 @@ class Grid(VMobject):
CONFIG = {
"height" : 6.0,
"width" : 6.0,
"considered_smooth" : False,
}
def __init__(self, rows, columns, **kwargs):
digest_config(self, kwargs, locals())

View file

@ -223,6 +223,7 @@ class NumberPlane(VMobject):
"secondary_line_ratio" : 1,
"written_coordinate_height" : 0.2,
"propagate_style_to_family" : False,
"make_smooth_after_applying_functions" : True,
}
def generate_points(self):
if self.x_radius is None:
@ -360,9 +361,6 @@ class NumberPlane(VMobject):
mob.make_smooth()
return self
def apply_function(self, function, maintain_smoothness = True):
VMobject.apply_function(self, function, maintain_smoothness = maintain_smoothness)

View file

@ -67,8 +67,9 @@ class ChangingDecimal(Animation):
for x in range(self.spare_parts)]
)
if self.tracked_mobject:
self.diff_from_tracked_mobject = \
decimal_number_mobject.get_center() - self.tracked_mobject.get_center()
dmc = decimal_number_mobject.get_center()
tmc = self.tracked_mobject.get_center()
self.diff_from_tracked_mobject = dmc - tmc
Animation.__init__(self, decimal_number_mobject, **kwargs)
def update_mobject(self, alpha):
@ -85,14 +86,9 @@ class ChangingDecimal(Animation):
)
new_decimal.replace(decimal, dim_to_match = 1)
new_decimal.highlight(decimal.get_color())
decimal.align_data(new_decimal)
families = [
mob.family_members_with_points()
for mob in decimal, new_decimal
]
for sm1, sm2 in zip(*families):
sm1.interpolate(sm1, sm2, 1)
self.mobject.number = new_number
decimal.submobjects = new_decimal.submobjects
decimal.number = new_number
def update_position(self):
if self.position_update_func is not None:

View file

@ -267,7 +267,6 @@ class VideoIcon(SVGMobject):
CONFIG = {
"file_name" : "video_icon",
"width" : 2*SPACE_WIDTH/12.,
"considered_smooth" : False,
}
def __init__(self, **kwargs):
SVGMobject.__init__(self, **kwargs)
@ -275,8 +274,6 @@ class VideoIcon(SVGMobject):
self.scale_to_fit_width(self.width)
self.set_stroke(color = WHITE, width = 0)
self.set_fill(color = WHITE, opacity = 1)
for mob in self:
mob.considered_smooth = False
class VideoSeries(VGroup):
CONFIG = {

View file

@ -175,11 +175,10 @@ class ThreeDScene(Scene):
if is_camera_rotating:
self.add(self.ambient_camera_rotation)
def separate_moving_and_static_mobjects(self, *animations):
moving, static = Scene.separate_moving_and_static_mobjects(self, *animations)
def get_moving_mobjects(self, *animations):
if self.camera.rotation_mobject in moving:
return moving + static, []
return moving, static
return self.mobjects
return Scene.get_moving_mobjects(self, *animations)
##############