mirror of
https://github.com/3b1b/manim.git
synced 2025-08-05 16:49:03 +00:00
Changed how functions are applied to vectorized mobjects to handle smoothness issues more cleanly
This commit is contained in:
parent
1b67abd8a9
commit
f64c076e7e
4 changed files with 35 additions and 23 deletions
|
@ -14,8 +14,9 @@ class VMobject(Mobject):
|
||||||
"is_subpath" : False,
|
"is_subpath" : False,
|
||||||
"close_new_points" : False,
|
"close_new_points" : False,
|
||||||
"mark_paths_closed" : False,
|
"mark_paths_closed" : False,
|
||||||
"considered_smooth" : True,
|
|
||||||
"propagate_style_to_family" : False,
|
"propagate_style_to_family" : False,
|
||||||
|
"pre_function_handle_to_anchor_scale_factor" : 0.01,
|
||||||
|
"make_smooth_after_applying_functions" : False,
|
||||||
}
|
}
|
||||||
|
|
||||||
## Colors
|
## Colors
|
||||||
|
@ -191,7 +192,6 @@ class VMobject(Mobject):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def make_smooth(self):
|
def make_smooth(self):
|
||||||
self.considered_smooth = True
|
|
||||||
return self.change_anchor_mode("smooth")
|
return self.change_anchor_mode("smooth")
|
||||||
|
|
||||||
def make_jagged(self):
|
def make_jagged(self):
|
||||||
|
@ -232,12 +232,35 @@ class VMobject(Mobject):
|
||||||
self.submobjects
|
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)
|
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()
|
self.make_smooth()
|
||||||
return self
|
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
|
## Information about line
|
||||||
|
|
||||||
|
@ -272,7 +295,6 @@ class VMobject(Mobject):
|
||||||
|
|
||||||
|
|
||||||
## Alignment
|
## Alignment
|
||||||
|
|
||||||
def align_points(self, mobject):
|
def align_points(self, mobject):
|
||||||
Mobject.align_points(self, mobject)
|
Mobject.align_points(self, mobject)
|
||||||
is_subpath = self.is_subpath or mobject.is_subpath
|
is_subpath = self.is_subpath or mobject.is_subpath
|
||||||
|
|
|
@ -114,7 +114,6 @@ class Sector(VMobject):
|
||||||
class Line(VMobject):
|
class Line(VMobject):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"buff" : 0,
|
"buff" : 0,
|
||||||
"considered_smooth" : False,
|
|
||||||
"path_arc" : None,
|
"path_arc" : None,
|
||||||
"n_arc_anchors" : 10, #Only used if path_arc is not 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)
|
path_func(self.start, self.end, alpha)
|
||||||
for alpha in np.linspace(0, 1, self.n_arc_anchors)
|
for alpha in np.linspace(0, 1, self.n_arc_anchors)
|
||||||
])
|
])
|
||||||
self.considered_smooth = True
|
|
||||||
self.account_for_buff()
|
self.account_for_buff()
|
||||||
|
|
||||||
def account_for_buff(self):
|
def account_for_buff(self):
|
||||||
|
@ -449,7 +447,6 @@ class Polygon(VMobject):
|
||||||
"color" : GREEN_D,
|
"color" : GREEN_D,
|
||||||
"mark_paths_closed" : True,
|
"mark_paths_closed" : True,
|
||||||
"close_new_points" : True,
|
"close_new_points" : True,
|
||||||
"considered_smooth" : False,
|
|
||||||
}
|
}
|
||||||
def __init__(self, *vertices, **kwargs):
|
def __init__(self, *vertices, **kwargs):
|
||||||
assert len(vertices) > 1
|
assert len(vertices) > 1
|
||||||
|
@ -479,7 +476,6 @@ class Rectangle(VMobject):
|
||||||
"width" : 4.0,
|
"width" : 4.0,
|
||||||
"mark_paths_closed" : True,
|
"mark_paths_closed" : True,
|
||||||
"close_new_points" : True,
|
"close_new_points" : True,
|
||||||
"considered_smooth" : False,
|
|
||||||
}
|
}
|
||||||
def generate_points(self):
|
def generate_points(self):
|
||||||
y, x = self.height/2., self.width/2.
|
y, x = self.height/2., self.width/2.
|
||||||
|
@ -586,7 +582,6 @@ class Grid(VMobject):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"height" : 6.0,
|
"height" : 6.0,
|
||||||
"width" : 6.0,
|
"width" : 6.0,
|
||||||
"considered_smooth" : False,
|
|
||||||
}
|
}
|
||||||
def __init__(self, rows, columns, **kwargs):
|
def __init__(self, rows, columns, **kwargs):
|
||||||
digest_config(self, kwargs, locals())
|
digest_config(self, kwargs, locals())
|
||||||
|
|
|
@ -223,6 +223,7 @@ class NumberPlane(VMobject):
|
||||||
"secondary_line_ratio" : 1,
|
"secondary_line_ratio" : 1,
|
||||||
"written_coordinate_height" : 0.2,
|
"written_coordinate_height" : 0.2,
|
||||||
"propagate_style_to_family" : False,
|
"propagate_style_to_family" : False,
|
||||||
|
"make_smooth_after_applying_functions" : True,
|
||||||
}
|
}
|
||||||
def generate_points(self):
|
def generate_points(self):
|
||||||
if self.x_radius is None:
|
if self.x_radius is None:
|
||||||
|
@ -360,9 +361,6 @@ class NumberPlane(VMobject):
|
||||||
mob.make_smooth()
|
mob.make_smooth()
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def apply_function(self, function, maintain_smoothness = True):
|
|
||||||
VMobject.apply_function(self, function, maintain_smoothness = maintain_smoothness)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -267,7 +267,6 @@ class VideoIcon(SVGMobject):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"file_name" : "video_icon",
|
"file_name" : "video_icon",
|
||||||
"width" : 2*SPACE_WIDTH/12.,
|
"width" : 2*SPACE_WIDTH/12.,
|
||||||
"considered_smooth" : False,
|
|
||||||
}
|
}
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
SVGMobject.__init__(self, **kwargs)
|
SVGMobject.__init__(self, **kwargs)
|
||||||
|
@ -275,8 +274,6 @@ class VideoIcon(SVGMobject):
|
||||||
self.scale_to_fit_width(self.width)
|
self.scale_to_fit_width(self.width)
|
||||||
self.set_stroke(color = WHITE, width = 0)
|
self.set_stroke(color = WHITE, width = 0)
|
||||||
self.set_fill(color = WHITE, opacity = 1)
|
self.set_fill(color = WHITE, opacity = 1)
|
||||||
for mob in self:
|
|
||||||
mob.considered_smooth = False
|
|
||||||
|
|
||||||
class VideoSeries(VGroup):
|
class VideoSeries(VGroup):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
|
|
Loading…
Add table
Reference in a new issue