mirror of
https://github.com/3b1b/manim.git
synced 2025-07-27 20:12:24 +08:00
Add alternate smoothing options
This commit is contained in:
@ -1,7 +1,6 @@
|
|||||||
from manimlib.constants import *
|
from manimlib.constants import *
|
||||||
from manimlib.mobject.types.vectorized_mobject import VMobject
|
from manimlib.mobject.types.vectorized_mobject import VMobject
|
||||||
from manimlib.utils.config_ops import digest_config
|
from manimlib.utils.config_ops import digest_config
|
||||||
from manimlib.utils.space_ops import get_norm
|
|
||||||
|
|
||||||
|
|
||||||
class ParametricCurve(VMobject):
|
class ParametricCurve(VMobject):
|
||||||
@ -11,7 +10,6 @@ class ParametricCurve(VMobject):
|
|||||||
"epsilon": 1e-8,
|
"epsilon": 1e-8,
|
||||||
# TODO, automatically figure out discontinuities
|
# TODO, automatically figure out discontinuities
|
||||||
"discontinuities": [],
|
"discontinuities": [],
|
||||||
"smoothing": True,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, t_func, t_range=None, **kwargs):
|
def __init__(self, t_func, t_range=None, **kwargs):
|
||||||
@ -42,8 +40,7 @@ class ParametricCurve(VMobject):
|
|||||||
points = np.array([self.t_func(t) for t in t_range])
|
points = np.array([self.t_func(t) for t in t_range])
|
||||||
self.start_new_path(points[0])
|
self.start_new_path(points[0])
|
||||||
self.add_points_as_corners(points[1:])
|
self.add_points_as_corners(points[1:])
|
||||||
if self.smoothing:
|
self.make_smooth(true_smooth=False)
|
||||||
self.make_smooth()
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ from manimlib.mobject.mobject import Mobject
|
|||||||
from manimlib.mobject.mobject import Point
|
from manimlib.mobject.mobject import Point
|
||||||
from manimlib.utils.bezier import bezier
|
from manimlib.utils.bezier import bezier
|
||||||
from manimlib.utils.bezier import get_smooth_quadratic_bezier_handle_points
|
from manimlib.utils.bezier import get_smooth_quadratic_bezier_handle_points
|
||||||
|
from manimlib.utils.bezier import get_smooth_cubic_bezier_handle_points
|
||||||
from manimlib.utils.bezier import get_quadratic_approximation_of_cubic
|
from manimlib.utils.bezier import get_quadratic_approximation_of_cubic
|
||||||
from manimlib.utils.bezier import interpolate
|
from manimlib.utils.bezier import interpolate
|
||||||
from manimlib.utils.bezier import integer_interpolate
|
from manimlib.utils.bezier import integer_interpolate
|
||||||
@ -402,13 +403,13 @@ class VMobject(Mobject):
|
|||||||
])
|
])
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def set_points_smoothly(self, points):
|
def set_points_smoothly(self, points, true_smooth=False):
|
||||||
self.set_points_as_corners(points)
|
self.set_points_as_corners(points)
|
||||||
self.make_smooth()
|
self.make_smooth(true_smooth)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def change_anchor_mode(self, mode):
|
def change_anchor_mode(self, mode):
|
||||||
assert(mode in ["jagged", "smooth"])
|
assert(mode in ["jagged", "approx_smooth", "true_smooth"])
|
||||||
nppc = self.n_points_per_curve
|
nppc = self.n_points_per_curve
|
||||||
for submob in self.family_members_with_points():
|
for submob in self.family_members_with_points():
|
||||||
subpaths = submob.get_subpaths()
|
subpaths = submob.get_subpaths()
|
||||||
@ -416,17 +417,27 @@ class VMobject(Mobject):
|
|||||||
for subpath in subpaths:
|
for subpath in subpaths:
|
||||||
anchors = np.vstack([subpath[::nppc], subpath[-1:]])
|
anchors = np.vstack([subpath[::nppc], subpath[-1:]])
|
||||||
new_subpath = np.array(subpath)
|
new_subpath = np.array(subpath)
|
||||||
if mode == "smooth":
|
if mode == "approx_smooth":
|
||||||
new_subpath[1::nppc] = get_smooth_quadratic_bezier_handle_points(anchors)
|
new_subpath[1::nppc] = get_smooth_quadratic_bezier_handle_points(anchors)
|
||||||
|
elif mode == "true_smooth":
|
||||||
|
h1, h2 = get_smooth_cubic_bezier_handle_points(anchors)
|
||||||
|
new_subpath = get_quadratic_approximation_of_cubic(anchors[:-1], h1, h2, anchors[1:])
|
||||||
elif mode == "jagged":
|
elif mode == "jagged":
|
||||||
new_subpath[1::nppc] = 0.5 * (anchors[:-1] + anchors[1:])
|
new_subpath[1::nppc] = 0.5 * (anchors[:-1] + anchors[1:])
|
||||||
submob.append_points(new_subpath)
|
submob.append_points(new_subpath)
|
||||||
submob.refresh_triangulation()
|
submob.refresh_triangulation()
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def make_smooth(self):
|
def make_smooth(self, true_smooth=True):
|
||||||
# TODO, Change this to not rely on a cubic-to-quadratic conversion
|
"""
|
||||||
return self.change_anchor_mode("smooth")
|
If true_smooth is set to True, the number of points
|
||||||
|
in the mobject will double, but the effect will be
|
||||||
|
a genuinely smooth (C2) curve. Otherwise, it may not
|
||||||
|
becomes perfectly smooth, but the number of points
|
||||||
|
will stay the same.
|
||||||
|
"""
|
||||||
|
mode = "true_smooth" if true_smooth else "approx_smooth"
|
||||||
|
return self.change_anchor_mode(mode)
|
||||||
|
|
||||||
def make_jagged(self):
|
def make_jagged(self):
|
||||||
return self.change_anchor_mode("jagged")
|
return self.change_anchor_mode("jagged")
|
||||||
@ -824,7 +835,7 @@ class VMobject(Mobject):
|
|||||||
def apply_function(self, function):
|
def apply_function(self, function):
|
||||||
super().apply_function(function)
|
super().apply_function(function)
|
||||||
if self.make_smooth_after_applying_functions:
|
if self.make_smooth_after_applying_functions:
|
||||||
self.make_smooth()
|
self.make_smooth(true_smooth=False)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@triggers_refreshed_triangulation
|
@triggers_refreshed_triangulation
|
||||||
|
@ -134,8 +134,14 @@ def get_smooth_quadratic_bezier_handle_points(points):
|
|||||||
0.25 * ps[0:-2] + ps[1:-1] - 0.25 * ps[2:]
|
0.25 * ps[0:-2] + ps[1:-1] - 0.25 * ps[2:]
|
||||||
for ps in (points, points[::-1])
|
for ps in (points, points[::-1])
|
||||||
]
|
]
|
||||||
handles = 0.5 * np.vstack([smooth_to_right, [smooth_to_left[0]]])
|
if np.isclose(points[0], points[-1]).all():
|
||||||
handles += 0.5 * np.vstack([smooth_to_right[0], smooth_to_left[::-1]])
|
last_str = 0.25 * points[-2] + points[-1] - 0.25 * points[1]
|
||||||
|
last_stl = 0.25 * points[1] + points[0] - 0.25 * points[-2]
|
||||||
|
else:
|
||||||
|
last_str = smooth_to_left[0]
|
||||||
|
last_stl = smooth_to_right[0]
|
||||||
|
handles = 0.5 * np.vstack([smooth_to_right, [last_str]])
|
||||||
|
handles += 0.5 * np.vstack([last_stl, smooth_to_left[::-1]])
|
||||||
return handles
|
return handles
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user