Add alternate smoothing options

This commit is contained in:
Grant Sanderson
2021-02-05 16:29:07 -08:00
parent f87b82a9e9
commit 66817c4e2b
3 changed files with 28 additions and 14 deletions

View File

@ -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

View File

@ -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

View File

@ -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